龙空技术网

链表?很难吗?看js 如何简单地实现

我是小椰子呀 236

前言:

今天同学们对“js怎么实现链表”大致比较关心,看官们都需要学习一些“js怎么实现链表”的相关文章。那么小编同时在网摘上网罗了一些对于“js怎么实现链表””的相关文章,希望我们能喜欢,兄弟们一起来学习一下吧!

1.定义

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

本文章以单链表为例

1.1 节点

节点包含两部分,一部分是存储数据元素的数据域,一部分是存储指向下一个节点的指针域,上图,绿色是数据域,蓝色是指针域,他们一起共同构成一个节点。

let Node = function(data){    this.data = data;    this.next = null;}let node1 = new Node(1);let node2 = new Node(2);let node3 = new Node(3);node1.next = node2;node2.next = node3;console.log(node1.data, 'mmmmm')console.log(node1.next.data)console.log(node1.next.next.data)这就是一个简单的链表。复制代码

1.2 首尾节点

顾名思义,链表的第一个节点和最后一个节点

1.3 有头链表和无头链表

无头链表指第一个节点既有指针域也有数据域

有头链表是指第一个节点只有指针域 没有数据域

上图是无头链边,下图是有头链表

下边介绍,均用无头链表

2. 链表的实现

链表有以下方法

append 添加一个新元素insert 在指定位置插入一个元素remove 删除指定位置的节点remove_head 删除首节点remove_tail 删除尾节点indexOf 返回指定元素的索引、get 返回指定索引位置的元素tail 返回尾节点head 返回头节点length 返回链表的长度isEmpty 判断链表是否为空clear 清空链表prignf 打印整个链表

在代码中,每一步为大家解析

function LinkList(){    var Node = function(data){        this.data = data;        this.next = null;    }    let length = 0;    let head = null; // 头节点    let tail = null // 尾节点    // 添加节点    this.append = function(data) {        // 创建新节点        let new_node = new Node(data);        // 如果没有节点,那么头节点就是新节点,尾节点也是新节点        if(head === null) {            head = new_node;            tail = head;        }else {          //  后边只需要在尾节点后边新增加节点          //  然后把新节点点 变成尾节点            tail.next = new_node;             tail = new_node;        }                length +=1;        return true;    }           // 节点打印    this.printf = function(){        let curr_node = head;      // 节点打印 只需要一直 循环,直到节点的指针域不再链接新的节点        while(curr_node) {            console.log(curr_node.data);            curr_node = curr_node.next;        }    }    // 在 指定的位置插入一个元素   this.insert = function(index,data){        if(index < 0 || index > length) {            return null;        }else if (index ===length){           //  此时 只需要在尾节点直接添加新元素            this.append(data)        }else {            let new_node = new Node(data);            if(index === 0) {               //  如果为0 证明是要插到最前边,那么原来的头节点head 就是新元素的下一个节点,               //  新元素 自然就成为新的头节点                new_node.next = head;                head = new_node;            }else {                let curr_node = head;                let insert_index = 1;                //  循环是为了找到插入的位置 我们只需要找到要插入的位置的前一个节点                // 循环结束后 curr_node  就是new_node 的上一个节点                //  我们可以让index 为1 带入想象                 while(insert_index < index){                    insert_index +=1;                    curr_node = curr_node.next;                }                // 此时 curr_node 是 要插入位置的前一个节点                let next_node = curr_node.next;  //  将原本当前节点的下一个节点先变量存储                 curr_node.next = new_node;                   new_node.next = next_node;            }        }        length +=1;        return true    }    // 删除指定位置的节点    this.remove = function(index){        if(index < 0 || index >=length) {            return null        }else {            let del_node = null;            if(index === 0) {                // head 指向下一个节点,那么当前的head 自然就没啦                del_node = head;                head = head.next;            }else {                let curr_node = head;                let pre_node = null;                let del_index = 0;                // 找到需要删除的位置, del_index 表示被删除节点的所在索引,pre_node 表示被删除                // 节点的上一个节点, curr_node 表示需要被删除的节点                while(del_index < index){                    del_index +=1;                    pre_node = curr_node;                    curr_node = curr_node.next;                }                //  把curr_node 从链表里拿出来                del_node = curr_node;                pre_node.next = curr_node.next;                // 如果删除的是尾节点                if(curr_node.next === null){                    tail = pre_node;                }            }                            length -= 1;               del_node.next = null;               return del_node.data;           }    }    //  获取指定索引位置的节点,需要传入参数 index    this.get = function(index) {        if(index < 0 || index >= length) {            return null        }        let node_index = 0;        let curr_node = head;      // 遍历节点,找到索引位置的节点         while(node_index < index){            node_index +=1;           curr_node = curr_node.next;        }        return curr_node.data;     }    // 返回指定元素所在的位置 如果链表中没这个元素,返回-1 ,如果存在多个,返回第一个    this.indeOf = function(data){        let curr_node = head;        let index = -1;        while(curr_node) {            index +=1;            if(curr_node.data === data) {                return index            }else {                curr_node = curr_node.next;            }        }        return -1;    }    // 删除 尾节点     this.remove_tail = function() {         return this.remove(length -1)     }     // 删除头节点     this.remove_head = function(){         return this.remove(0)     }     // 返回链表的头节点的值     this.head = function(){         return this.get(0)     }     //返回链表尾节点的值     this.tail = function(){         return this.get(length -1)     }     // isEmpty     this.isEmpty = function(){         return length === 0;     }     // 清空链表     this.clear = function(){         head = null;         tail = null;         length = 0     }}let link = new LinkList();link.append(1)link.append(3)link.append(4)console.log(link.get(2),'2')console.log(link.head(),'3')console.log(link.tail(),'4')// link.remove(2)// link.insert(1,8)console.log(link.indeOf(4),'link.indeOf(2)')link.printf();复制代码
3. 用链表实现栈和队列

实现栈

实现队列

function Queue(){    let linklist = new LinkList();    // 如队列    this.enqueue = function(data){        linklist.append(data);    }    // 出队列    this.dequeue = function(){        linklist.remove_head()    }        //返回队首    this.head = function(){        return linklist.head()    }    // 返回队尾    this.tail = function(){        return linklist.tail()    }    // size     this.size = function(){       return linklist.length()    }    // clear    this.clear = function(){        linklist.clear()    }    //isEmpty    this.isEmpty = function(){        linklist.isEmpty()    }}复制代码
4. 实现翻转链表

1. 使用迭代实现

function reverse_iter(head){    if(!head) {        return null    }         let pre_node = null;   // 前一个节点    let curr_node = head;  // 当前要翻转的节点   while(curr_node) {     let  next_node = curr_node.next;  //  记录当前节点的下一个节点     curr_node.next = pre_node;  // 当前节点指向前一个节点     pre_node = curr_node;   // 节点指针后移   向后滑动     curr_node = next_node;  //  节点指针后移   向后滑动   }       // 返回pre_node, 当循环结束时,pre_node指向翻转前链表的最后一个节点   //(翻转前的第一个节点head)的链域为NULL      return pre_node}复制代码

2. 递归实现

function reverise_digui(head){    if(!head){        return null;    }    //  终止条件  : 找到链表的最后一个节点    if(head.next === null ) {        return head    }    // 从下一个节点开始进行翻转  先翻转后边的链表,//从后边的两个节点开始反转,依次向前  let new_head = reverise_digui(head.next)  head.next.next = head  //  将后一个链表节点指向前一个节点  head.next = null;  // 将原链表中的前一个节点指向后一个节点的指向关系断开 return new_head;}

总结: 链表其实并不难,所有的都是从简单到复杂,只要理解了其概念,从简单到复杂,然后再去leetcode 刷一些简单的题,你入大厂的敲门砖就开始了

标签: #js怎么实现链表