数据结构与算法作为计算机学科中至关重要的一门课程,在日常业务代码中常常很难用到或者说很难进行相关的实践,我们常常在leetcode中练习的习题感到没有用武之地。实际上,我们可以通过优化页面中的一些代码及在需求实现过程中对之前阅读过的源码或者之前练习过的习题进行相关的举一反三和触类旁通。本文列举了一些作者在日常业务代码书写过程中进行的一些相关数据结构算法的实践以及对于算法与数据结构练习的思考。
自定义优先级规则展示
切换时间粒度字段映射
在前端页面中,我们经常会遇到需要一排展示数量或者不同维度属性的需求,通常来说我们会将后端所有返回的字段都进行相关的展示,但是在一些轻交互重展示的场景中,比如可视化大屏,就需要我们对展示的内容进行取舍,而这个取舍就需要我们能够根据需求或者说产品数据的反馈进行优先级的选择排布,这里就会涉及到优先级的动态调整过程,也就是能够根据数据或者需求来自定义展示优先级。
第一个比较简单的想法就是根据产品需求进行数组的分流,然后合并数组进行截取展示
fn(arr) {
let r = [], _r = [];
for(let i=0; i < arr.length; i++) {
// 数量展示优化
if( 达到某个数量 ) return r;
if(// 根据产品需求对数组进行分流) {
r.push(arr[i])
} else {
_r.push(arr[i])
}
}
return r.length > 5 ? r.slice(0,5) : r.concat(_r).slice(0,5);
};
gn() {
this.resourceConfig.map(// 业务逻辑).sort((a,b) => a.structure - b.structure));
}
最后 fn(gn())
方案二来源于链表的删除更新方便的特点,通过一个链表将所有的优先级进行串联起来,通过使用update操作进行相关的业务更新操作
// 构造一个节点
class Node {
constructor(v, next){
this.value = v;
this.next = next;
}
}
class LinkList {
constructor(){
// 链表的属性,长度和头部
this.size = 0
this.head = new Node(null, null)
}
// 是否为空
isEmpty() {
return this.size === 0
}
// 更新链表,进行相关业务的操作
update() {
}
}
本方案来源于react的fiber的优先级调度,通过优先队列进行相关的操作
class PriorityQueue{
// 取父节点索引 ~~((index - 1) / 2)
constructor(arr){
if (arr.length){
this.tree = []
this._build_tree(arr);
return;
}
this.tree = [];
}
// 入队
enqueue(val){
this.tree.push(val);
// 上浮
this._up(this.tree.length - 1);
}
// 出队
dequeue(){
// 取树根元素
this.tree.shift();
// 最后一个元素放树根,进行下沉
let last = this.tree.pop();
this.tree.unshift(last);
// log(n)下沉
this._down(0);
}
// 取队首的值
getFirst(){
return this.tree[0];
}
_build_tree(arr){
let tree = this.tree;
tree.push(arr[0]);
for (let i = 1; i < arr.length; i++){
tree.unshift(arr[i]);
this._down(0);
}
}
// 对index号元素执行下沉操作. 也叫heapify
_down(index){
let tree = this.tree;
// 本身就是叶子节点,无需下沉
let last_no_leaf = ~~((tree.length - 2) / 2);
if (index > last_no_leaf) return;
while(index <= last_no_leaf){
let l = tree[index * 2 + 1];
let r = tree[index * 2 + 2] || tree[index * 2 + 1]; // 有可能没有右儿子
let max = l >= r ? l : r;
let maxIndex = l >= r ? index * 2 + 1: index * 2 + 2
if (tree[index] < max){
[tree[index], tree[maxIndex]] = [tree[maxIndex], tree[index]]
index = index * 2 + 1
}else{
return;
}
}
}
// 对index号元素执行上浮操作
_up(index){
let tree = this.tree;
while(index !== 0){
let p = ~~((index - 1) / 2);
if (tree[index] > tree[p]){
[tree[index], tree[p]] = [tree[p], tree[index]];
// let tmp = index;
// this._down(tmp);
index = p;
} else {
return;
}
}
}
}
在前端页面中,对于动态下拉选择框选项,我们通常通过接口进行获取,但是对于多级联动的下拉选择选项,对于不同的时间粒度选择通常返回的数据名称相同但是id确实不同的,这时通常需要对数据进行映射处理
在时间粒度进行切换时,需要记录前后最终前后两个时间粒度的值,通过接口进行时间粒度的数据映射,这里可以通过栈进行时间粒度的记录,获取最初和最后的时间粒度,最后进行数据映射
const timeSizeList = [];
// 进行入栈操作
timeSizeList.push(...)
日常进行数据结构习题练习或者阅读源码过程中,除了为了应付面试之外,最重要的还是要学习源码或者习题中解决问题的思路以及想法,在日常的业务代码中,虽然很难写出框架代码那种优雅简洁的实现方案,但是也应该在日常工作中多思考如何利用数据结构与算法来优化代码的时空复杂度,更好的优化代码的执行,从而提升用户体验,这才是一个高级工程师应该关注的细节点,不能只是为了完成业务代码而完成业务代码,这样虽然写了很多代码,但其实其对个人代码能力及计算机素养的提升都是很有限的,事倍却工半,希望在重复的业务代码书写过程中,也能做到优雅与高效并存,共勉!!!
原文:https://segmentfault.com/a/1190000040275616
据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。包括三个组成成分:数据的逻辑结构、物理结构(存储结构)、数据运算结构。
一个具有层级结构的数据,实现这个功能非常容易,因为这个结构和组件的结构是一致的,递归遍历就可以了。但是,由于后端通常采用的是关系型数据库,所以返回的数据通常会是这个样子:前端这边想要将数据转换一下其实也不难,因为要合并重复项
数组不总是组织数据的最佳数据结构,在很多编程语言中,数组的长度是固定的,所以当数组已被数据填满时,再要加入新的元素就会非常困难。在数组中,添加和删除元素也很麻烦,因为需要将数组中的其他元素向前或向后平移。
图由边的集合及顶点的集合组成。边是有方向的是有序图(有向图),否则就是无序图(无向图)。图中的一系列顶点构成路径,路径中所有的顶点都由边连接。路径的长度用路径中第一个顶点到最后一个顶点之间边的数量表示。
Set 是ES6提供的一种新的数据结构,它允许你存储任何类型的唯一值,而且Set中的元素是唯一的。我们用new操作符来生成一个Set对象,set结构的实例有以下属性
链表更加像是数组。链表和数组都是用于存储有序元素的集合,但有几点大不相同,链表的实现不像之前介绍的栈和队列一般依赖于数组(至少我们目前是这样实现的),它必须自己构建类并组织逻辑实现。我们先创建一个Node类
集合set是一种包含不同元素的数据结构。集合中的元素成为成员。集合的两个最重要特性是:集合中的成员是无序的;集合中不允许相同成员存在,计算机中的集合与数学中集合的概念相同,有一些概念我们必须知晓:
一个树结构包含一系列存在父子关系的节点。每个节点都有一个父节点(除了顶部的第一个节点)以及零个或多个子节点:关于数的深度和高度的问题,不同的教材有不同的说法
给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。主要就是用到了数组的 split 、 reverse 、 join 、 map 方法,原理:就是把字符串变成数组
链表和数组的对比:在大多数语言中,数组的大小是固定的,从数组的起点或中间添加或删除元素的成本很高,因为需要移动元素,链表中的每一个元素在内存中不是连续放置的,和它左右两侧元素是没有关系的
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!