前端必须掌握的数据结构

前端必须要掌握常见的数据结构,学会这招,让你对开发中的数据结构更加清晰!


一.队列

像排队一样,队列就是先进先出,排队入场!


image
class Queue {
    constructor() {
        this.arr = []
    }
    enqueue(element){ // 入队列
        this.arr.push(element)
    }
    dequeue(){ // 出队列
        return this.items.shift()
    }
}

二.栈

像拿起堆放的柴火一样,栈就是先进后出,就是离场时后进的人先出!


image
class Stack {
    constructor(){
        this.arr = [];
    }
    push(element){ // 入栈
        this.arr.push(element);
    }
    pop() { // 出栈
        return this.items.pop();
    }
}

三.链表

image

链表让我们删除数据和新增数据更加方便!

head指针指向第一个存入的元素节点,每个节点都有next属性指向一下一个元素节点,最后一个元素的指针指向null

创建一个节点,每个节点的结构非常简单

class Node {
    constructor(element){
        this.element = element; // 每个节点保存的内容
        this.next = null; // 保存的指针,指向下一个节点
    }
}

构建链表

class LinkList {
    constructor(){
        this.head = null; // 表头 默认指向第一个节点,没有为null
        this.length = 0;
    }
    append(element){
        // 追加节点
        const node = new Node(element);
        if(this.head == null){
            this.head = node; // 第一个节点就是表头
        }else{
            let current = this.head;
            // 从第一个节点查找到最后一个节点
            while(current.next){
                current = current.next;
            }
            current.next = node; // 找到最后一个节点添加next指向新增节点
        }
        this.length++; // 每增加一个长度
    }
}

使用链表,不难看出链表的特点就是通过next来指向下一个节点(像链条一样)

const ll = new LinkList();
ll.append(1);
ll.append(2);
console.log(ll); // head: Node { element: 1, next: Node { element: 2, next: null } }

实现链表的插入

insert(position,element){
    // 插入的时候判断插入的位置
    if(position>=0 && position <=this.length){
        const node = new Node(element); // 创建一个节点
        if(position === 0){ // 如果位置是0
            node.next = this.head; // 那么就让当前节点变成头
            this.head = node;
        }else{
            let current = this.head; // 获取头节点查找位置
            let previous = null;
            let index = 0;
            while(index++ < position){ // 查找到节点位置
                previous = current;
                current = current.next;
            }
            node.next = current; // 让当前节点next是刚才找到的节点
            previous.next = node; // 他的上一个节点的next是当前节点
        }
        this.length++;
    }
}

实现链表的删除

removeAt(position){
      if(position > -1 && position < this.length){
          if(position ==0){ // 如果是第一个直接改变指针
              this.head = this.head.next
          }else{
              let index = 0;
              let previous = null;
              let current = this.head;
              while(index++ < position){ // 找到要删除的这一项,直接让上一个指针指向下一个人
                  previous = current;
                  current = current.next
              }
              previous.next = current.next; // 上一个next直接指向下一个next
          }
          this.length--;
      }
  }

更新链表中的内容

update(position,element) {
    if (position >= 0 && position < this.length) {
        if (position === 0) {
          // 根位置 直接更改跟的内容即可
          this.head.element = element
        }else{
            let index = 0;
            // 查找到要修改的项来更新
            let current = this.head;
            while(index++ < position){
              current = current.next;
            }
            current.element = element;
        }
      }
  }

四.集合

ES6已经为我们提供了Set的api,但是在某些时候(浏览器不支持的情况下),我们还是需要自己来实现Set的

class Set{
    constructor(){
        this.items = {};
    }
    has(value){ // 判断
        return this.items.hasOwnProperty(value);
    }
    add(value){ // 像集合中添加
        if(!this.has(value)){
            this.items[value] = value;
        }
    }
    remove(value){ // 删除集合中的某一项
        if(this.has(value)){
            delete this.items[value];
        }
    }
}

集合,常见的方法有:交集、并集、差集

五.hash表

image

特点是查找速度快,但是存储量需要手动扩展

class HashTable{
    constructor(){
        this.table = [];
    }
    calcuteHash(key){ // 通过put的key 计算hash戳,存到数组中
        let hash = 0;
        for(let s of key){
            hash += s.charCodeAt();
        }
        return hash % 100; // 只能存放100个
    }
    get(key){ // 从hash表中取出值
        let hash = this.calcuteHash(key);
        return this.table[hash]
    }
    put(key,value){ // 像hash表中存入
        let hash = this.calcuteHash(key);
        this.table[hash] = value;
    }
}
let hash = new HashTable();
hash.put('abc',1);
console.log(hash.get('abc'));

六.树

叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

image

前端最常考察的就是二叉树!

二叉树: 树中的节点最多只能有两个子节点

二叉查找树:
若左子树不空,则左子树上所有节点的值均小于它的根节点的值
若右子树不空,则右子树上所有节点的值均大于它的根节点的值

class Node {
    constructor(key){
        this.key = key;
        this.left = null; // 左树
        this.right = null;// 右树
    }
}
class BinarySearchTree{
    constructor(){
        this.root = null;
    }
    insert(key){
        const newNode = new Node(key);
        const insertNode = (node,newNode)=>{
            // 看下是放在左边还是右边
            if(newNode.key < node.key){ // left
                if(node.left == null){
                    node.left = newNode;
                }else{ // 如果节点已经有了那么继续像当前节点插入
                    insertNode(node.left,newNode);
                }
            }else{ // right
                if(node.right == null){
                    node.right = newNode;
                }else{
                    insertNode(node.right,newNode);
                }
            }
        }
        if(!this.root){ // 如果根没有值 那么他就是根
            this.root = newNode;
        }else{ // 插到某一侧
            insertNode(this.root,newNode)
        }
    }
}
let binaryTree = new BinarySearchTree();
binaryTree.insert(8);
binaryTree.insert(3);
binaryTree.insert(10);

七.图

图可以看成有关联的树,我们可以使用邻接表来描述各个节点的关系


image
class Graph{
    constructor(){
        this.List = {};
    }
    addNode(v){
        this.List[v] = [];
    }
    addRelation(v,w){
        // 相互存储关系
        this.List[v].push(w);
        this.List[w].push(v);
    }
}
const graph = new Graph();
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'].forEach(node => graph.addNode(node));
graph.addRelation('A', 'B')
graph.addRelation('A', 'C')
graph.addRelation('A', 'D')
console.log(graph.List['A']);

看到这里是不是对数据结构有了一定的认识啦!接下来就靠大家的合理应用啦~

觉得本文对你有帮助吗?请分享给更多人
关注「前端优选」加星标,提升前端技能


前端优选公众号.jpg

加我微信:webyouxuan

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容