乐趣区

关于前端:数据结构算法在专网项目中的实践

前言

数据结构与算法作为计算机学科中至关重要的一门课程,在日常业务代码中经常很难用到或者说很难进行相干的实际,咱们经常在 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(...)

总结

日常进行数据结构习题练习或者浏览源码过程中,除了为了应酬面试之外,最重要的还是要学习源码或者习题中解决问题的思路以及想法,在日常的业务代码中,尽管很难写出框架代码那种优雅简洁的实现计划,然而也应该在日常工作中多思考如何利用数据结构与算法来优化代码的时空复杂度,更好的优化代码的执行,从而晋升用户体验,这才是一个高级工程师应该关注的细节点,不能只是为了实现业务代码而实现业务代码,这样尽管写了很多代码,但其实其对集体代码能力及计算机素养的晋升都是很无限的,事倍却工半,心愿在反复的业务代码书写过程中,也能做到优雅与高效并存,共勉!!!

参考

  • React 中的高优先级工作插队机制
  • JS 手动实现一个链表
  • 联合 React 源码,五分钟带你把握优先队列
  • JS 实现优先队列的三种形式
退出移动版