JS数据结构和算法 --- 链表

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Mr_JavaScript/article/details/84674049

概念:性质类似于数组,是计算机的一种存储结构。链表由一系列结点组成,每个结点里包含了本结点的数据域和指向下一个结点的指针(里面存储着下一个结点)。

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

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

应用场景:对线性表的长度或者规模难以估计;频繁做插入和删除操作;构建动态性比较强的线性表。

操作方法:

1、append(element) 尾部插入元素

     1)链表为空时,即插入的元素作为链表头(直接赋值)

     2)链表不为空时,从链表头开始查找,若当前查找项的指针不为null,继续查找下一项;直到当前查找项的指针等于null(最后一项),把新元素赋值当前项的指针(尾部插入)

2、insert(position,element) 向链表插入元素

     1)头部插入(下标等于0),即插入的元素作为链表头

     2)非头部插入,从头部开始查找,当前查找项的下标不等于position时,继续向后查找,直到查找项下标等于position,使当前查找的前一项的指针指向插入项,插入项的指针指向当前项,完成插入。

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

     1)移除第1项(下标等于0),即使原链表头的指针作为新链表头

     2)移除非第一项(下标大于0),即跳过当前结点,使前一个结点的指针 指向 当前节点的指针

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

     1)从头部开始查找,如果当前查找项等于目标项就返回对应的下标,否则继续往后查找;

     2)若链表循环结束了还没找到,则返回-1(不存在)

5、remove(element) 直接移除某项元素(代码复用)

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

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

6、isEmpty() 判断链表是否为空

7、size() 查询链表的大小

实例:js实现各操作方法的详解

/* 一个链表类 */
function LinkedList(element){
    // 列表头
    let head = null;
    // 链表长度
    let length = 0;
    // 辅助类:结点
    function NodeItem(element){
        this.element = element;    // 数据域
        this.next = null;          // 指针
    }
    /* 
        append(element) 链表尾添加元素 
        1)链表为空时,即插入的元素作为链表头(直接赋值)
        2)链表不为空时,从链表头开始查找,若当前查找项的指针不为null,继续查找下一项;直到当前查找项的指针等于null(最后一项),把新增项赋值给当前项的指针(尾部插入)
    */
    this.append = (element)=>{
        let node = new NodeItem(element);   // 调用辅助类创建一个新结点
        // 链表为空
        if(head == null){   
            head = node;    // 把第一个添加的结点作为链表头
        }
        // 已存在结点
        else{
            let current = head;             // 定义一个current变量,存储head链表头的值,代表当前正在查找的值(从头部开始查找)
            while(current.next!==null){     // 当前查找项的指针不为null(即不是最后一项),继续往后找,直到next=null循环结束
                current = current.next;     // 把下一项赋值给当前查找项,即查找下一项(循环的经典方法)
            }
            // while循环结束后,current已经到了最后一项(current.next=null)
            current.next = node;            // 插入新元素
        }
        length++;
    };
    /* 
        insert(position,element) 向链表插入元素
        1)头部插入(下标等于0),即插入的元素作为链表头
        2)非头部插入,从头部开始查找,当前查找项的下标不等于position时,继续向后查找,直到查找项下标等于position,使当前查找的前一项的指针指向插入项,插入项的指针指向当前项,完成插入。
    */
    this.insert = (position, element)=>{
        let node = new NodeItem(element);       // 调用辅助类创建一个新元素结点(即插入的元素)
        // 越界
        if(position>-1 && position<length){
            // 链表头插入
            if(position==0){                    
                let current = head;             // 先把原表头存储在current变量里
                head = node;                    // 把插入项赋值给表头(即插入链表头)
                head.next = current;            // 使插入项的指针指向原表头(链接起来)
            }
            // 非链表头插入
            else{
                let index = 0;                  // 当前查找项的下标
                let previous = null;            // 查找项的前一项
                let current = head;             // 从链表头开始查找,先把它存储在current变量里
                while(index < position){        // 查找的当前项下标小于目标项下标时,继续往后找
                    previous = current;         // 当前项赋值给前一项
                    current = current.next;     // 当前项的指针赋值给当前项,即查找项往后移动一项
                    index++;                    // 下标加一
                }
                // 直到index=position时,即找到了目标项
                previous.next = node;           // 前一项的指针指向插入项
                node.next = current;            // 插入项的指针指向当前找到的目标项
                // 完成上面两步,即完成插入
            }
            length++;
        }
    };
    /* 
        removeAt(position) 根据下标移除元素
        1)移除第1项(下标等于0),即使原链表头(第一项)的指针作为新链表的表头
        2)移除非第一项(下标大于0),即跳过当前结点,使前一个结点的指针 指向 当前节点的指针
    */
    this.removeAt = (position)=>{
        if(position>-1 && position<length){
            let current = head;  
            // 移除第一项
            if(position==0){                    
                head = current.next;            // 使原表头的指针变成新表头,到达移除原表头的目的
            }
            // 移除非第一项
            else{
                let index = 0;                  // 当前项的下标
                let previous = null;            // 当前查找项的前一个结点
                // let current = head;             // 从头部开始查找
                while(index<position){          // 当前结点的下标小于指定结点下标时,往后移动一项,继续查找
                    previous = current;         // 往后移动一项的方法就是,把后一项赋值给前一项
                    current = current.next;     
                    index++;
                }
                // 当index = position 时跳出循环,即找到了要移除的那一项
                previous.next = current.next;   // 跳过当前项,使前一项的指针指向当前项的指针
            }
            length--;   //长度减1
            return current;
        }
    };
    /* 
        indexOf(element) 查找某元素的下标 
        1)从头部开始查找,如果当前查找项等于目标项就返回对应的下标,否则继续往后查找;
        2)若链表循环结束了还没找到,则返回-1(不存在)
    */
    this.indexOf = (element)=>{
        let index = 0;                          // 下标
        let current = head;                     // 从头部开始查找
        while(current !== null){                // 当前项不等于null,表示还不是最后一项,继续循环
            if(element === current.element){    // 当前项的值等于目标项
                return index;                   // 返回对应下标
            }
            current = current.next;             // 否则继续往后查找
            index++;                            // 下标加一
        }
        return -1;       // 若循环结束还没找到,返回-1,链表里不存在该元素
    };
    /* 
        remove(element) 直接移除某项元素(代码复用)
        1)调用indexOf(element)方法找到目标项的下标;
        2)调用removeAt(position)方法根据目标项的下标移除目标项 
    */
    this.remove = (element)=>{
        return this.removeAt(this.indexOf(element));
    };
    /* isEmpty() 判断链表是否为空 */
    this.isEmpty = ()=>{
        return length == 0;
    };
    /* size() 查询链表的大小 */
    this.size = ()=>{
        return length;
    };
    /* 查看链表  */ 
    this.getHead = ()=>{     
      return head;       
    };

}

(完)

猜你喜欢

转载自blog.csdn.net/Mr_JavaScript/article/details/84674049