JS数据结构与算法 —— 链表

概念:链表是计算机的一种存储结构。链表由一系列结点组成,每个结点里包含了本结点的数据域和指向下一个结点的指针。如下图item存储数据,next存储下一个节点的引用,其中最后一个节点的指针指向了null,表示链表结束的位置。

JS数据结构与算法 —— 链表_第1张图片

作用:按一定顺序储存数据,允许在任意位置插入和删除结点。

分类:单向链表、双向链表、单向循环链表和双向循环链表

应用场景适用于需要频繁进行插入和删除操作的数据存储。

js实现一个单向链表

我们需要定义两个类,一个是Node类表示节点,一个是LinkedList类表示链表;LinkedList类里有head(头节点)和length(链长)两个属性,有几个操作方法,如append(添加),insert(插入),remove(移除),removeAt(根据下标移除),isEmpty(链表是否为空),size(链表大小),display(查看链表)。

定义Node类,表示节点

class Node{
    constructor(element){
        this.element = element;    // 数据         
        this.next = null;          // 指针
    }
}

定义LinkedList类,表示链表(为了便于阅读,已把LinkedList类的方法提取出来展示)

class LinkedList{
    constructor(){
        this.head = null;       // 列表头
        this.length = 0;        // 链表长度
    }
}

当链表为空时,即链表头head为null,下面实现链表的各操作方法

append(element)  新增元素

新增元素分为两种情况,链表为空和链表不为空。链表为空时,新增的元素作为链表头(直接赋值);链表不为空时,从链表尾添加,即原链表尾的指针next指向新增元素。

append(element){
    let node = new Node(element);   // 调用辅助类创建一个新结点
    // 链表为空
    if(this.head == null){   
        this.head = node;    // 把第一个添加的结点作为链表头
    }
    // 已存在结点
    else{
        let current = this.head;        // 当前正在查找的节点(从头部开始查找)
        while(current.next!==null){     // 当前查找项的指针不为null(即不是最后一项),继续往后找,直到next=null循环结束
            current = current.next;     // 把下一项赋值给当前查找项,即查找下一项(循环的经典方法)
        }
        // while循环结束后,current已经到了最后一项(current.next=null)
        current.next = node;            // 插入新元素
    }
    length++;   // 长度加1
}

insert(position,element)  插入元素

根据下标找到目标节点,从目标节点之插入新元素,插入元素分为两种情况,头部插入和非头部插入。头部插入(下标等于0),即插入的元素作为链表头;非头部插入,找到目标节点和目标节点的前一个节点(我们称之为前节点),使前节点的指针指向插入节点,而插入节点的指针指向目标节点,完成插入。如下图是非头部插入示意图,node2为目标节点,node1为前节点,node3为插入节点,使node1的指针指向node3,而node3的指针指向node2,即完成了插入操作。

JS数据结构与算法 —— 链表_第2张图片

insert(element,position){
    let node = new Node(element);           // 定义一个新结点
    // 越界
    if(position>-1 && position

removeAt(position)  根据下标移除元素

 根据下标移除元素也分为两种情况,移除链表头和移除非链表头节点。移除链表头节点(下标等于0),即使原链表头的指针指向的节点作为新链表头;移除非链表头节点,根据下标找到需要移除的目标节点和它的前一个节点,使前结点的指针 指向 目标节点的指针所指向的节点,即完成了移除目标节点。如下图是移除非链表头节点示意图,node1为目标节点,head为前节点,node2为node1指针指向的节点,使head的指针指向node2,即完成了移除node1节点的操作。

JS数据结构与算法 —— 链表_第3张图片

removeAt(position){
    if(position>-1 && position

indexOf(element)  查找某元素的下标

从头部开始查找,如果当前查找节点等于目标节点就返回对应的下标,否则继续往后查找;若链表循环结束了还没找到,则返回-1(不存在)。

indexOf(element){
    let index = 0;                          // 当前下标
    let current = this.head;                // 从头部开始查找
    while(current !== null){                // 当前项不等于null,表示还不是最后一项,继续循环
        if(element === current.element){    // 如果当前节点的值等于目标项
            return index;                   // 返回对应下标
        }
        current = current.next;             // 否则继续往后查找
        index++;                            // 下标加1
    }
    return -1;       // 若循环结束还没找到,返回-1,链表里不存在该元素
}

remove(element)  移除元素(代码复用)

     1)调用indexOf(element)方法找到目标项的下标;

     2)调用removeAt(position)方法根据目标项的下标移除目标项

remove(element){
    return this.removeAt(this.indexOf(element));
}

isEmpty()  判断链表是否为空

isEmpty(){
    return length === 0;
}

size()  查询链表的大小

size(){
    return length;
}

查看完整源码

更多数据结构相关,请查看专栏:《JavaScript数据结构与算法》

(完)

你可能感兴趣的:(☛,JavaScript(ES6),☛,JS数据结构与算法)