JavaScript单链表详解(增,删,改,查、逆序)

1、addNode(val):在链表尾部添加元素(val为节点的值)。

2、Length():链表的长度。

3、display():打印链表。

4、ModifyValue(val1,val2):替换指定值。

5、findValue(val):查找指定的值,返回它的位置。

6、DeleteValue(val):删除指定节点。

7、ModifyLc(location,val):修改指定位置的值。

8、insert(location,val):向指定位置添加元素。

9、ReverseOrder():逆序。

单链表及节点。

链表是一系列的存储数据元素的单元通过指针串接起来形成的,因此每个单元至少有两个域,
一个域用于数据元素的存储,另一个域是指向其他单元的指针
这里具有一个数据域和多个指针域的存储单元通常称为 结点(node)

一种最简单的结点结构如图所示,它是构成单链表的基本结点结构。在结点中数据域用来存储数据元素,
指针域用于指向下一个具有相同结构的结点。

在这里插入图片描述

特性

单链表的一个重要特性就是只能通过前驱结点找到后续结点,而无法从后续结点找到前驱结点。

优缺点

优点:

1、链表是一个动态数据结构,因此它可以在运行时通过分配和取消分配内存来增长和收缩。 因此,无需给出链表的初始大小

2、节点的插入和删除确实非常容易。 与数组不同,在插入或删除元素后,我们不必移动元素。 在链表中,我们只需要更新节点的下一个指针中存在的地址即可。

3、由于链表的大小可以在运行时增加或减小,因此不会浪费内存。 在数组的情况下,会浪费大量内存,例如,如果我们声明一个大小为10的数组并在其中仅存储6个元素,那么就会浪费4个元素的空间。 链表中没有这种问题,因为仅在需要时才分配内存

缺点:

1、与数组相比,在链表中存储元素需要更多的内存。 因为在链表中,每个节点都包含一个指针,并且它本身需要额外的内存。

2、在链表中很难遍历元素或节点。 我们不能像按索引在数组中那样随机访问任何元素。 例如,如果我们要访问位置n处的节点,则必须遍历它之前的所有节点。 因此,访问节点所需的时间很大。

3、在链表中,反向遍历确实很困难。 在双链表的情况下,它比较容易,但是向后指针需要额外的内存,因此浪费了内存。

1、addNode(val)

1、在尾部插入元素时,如果head为空(长度length=0),也就是链表为空,我们只需要将头结点指向新创建的节点。
在这里插入图片描述
2、如果链表不为空,我们只需找到最后一个节点,并将它的next指向新创建的节点。
在这里插入图片描述

//在链表尾部添加元素(val为节点的值)
 ListNode.prototype.addNode = function(val){
     //创建需要添加的节点
     let newNode = new Node(val);
    //判断链表是否为空,若不为空则在链表后面添加元素,否则它就是头节点
    if(this.length==0){
        this.head=newNode;
    }else{
        let head1 = this.head;
        while(head1.next!==null){//找到链表的尾部
        head1 = head1.next;
    }
    head1.next = newNode;//向链表的尾部添加节点
    }
    this.length++;//添加节点后对应的长度增加
 }

2、Length()

链表的长度,由于我们增加节点和删除节点时都会更新链表中的length属性,所以length的值就是链表的长度。

ListNode.prototype.Length = function(){
     return this.length;//返回它的长度,就是链表的长度
 }

3、display()

我们建立一个数组来保存链表的遍历结果,如果当前指针不为空,就把它的值存入数组,然后把指针移动到下一个位置。直到它为空,这样就可以遍历链表中所有的值了。

 //打印链表
 ListNode.prototype.display = function(){
    let head1 = this.head;
    let res  = [];//用数组保存遍历的链表里的值
    let i = 0;
    while(head1!==null){//依次遍历链表,并将值存入数组
        res[i] = head1.val;
        head1 = head1.next;
        i++;
    }
    return res;
 }

4、ModifyValue(val1,val2)

替换值时,我们先找到这个值的位置,然后在修改它的值。

//替换指定值
 ListNode.prototype.ModifyValue = function(val1,val2){//将val1替换为val2
     let location = this.findValue(val1);//查找到val1的位置
     if(location==false){//如果没有查找到,返回false
         return false;
     }
     let head1 = this.head;//如果查找到了,就找到那一个节点,并将值替换
     while(head1!==null&&location>1){
         head1 = head1.next;
         location--;
     }
     head1.val = val2;
 }

5、findValue(val)

查找指定值时,我们通过依次遍历链表中所有的值来查找指定值的位置,通过计算遍历了几个值来返回它的相对位置。

//查找指定的值,返回它的位置
 ListNode.prototype.findValue = function(val){
    let head1 = this.head;
    let count = 0;
    while(head1!==null){//依次遍历链表
        if(head1.val==val){//如果找到了,就返回它的位置
            count++;
            return count;
        }else{//没找到就一直往下找;
            head1 = head1.next;
            count++;
        }
    }
    return false;//遍历完后,如果没找到就返回false
 }

6、DeleteValue(val)

我们还是先查找指定值出现的位置,如果没查到,就说明链表里没有这个值。

如果找到的是头节点,只需要将它的头指针指向它下一个节点:
在这里插入图片描述
否则就找到要删除节点的上一个节点和下一个节点:
在这里插入图片描述
然后让上一个节点指向要删除的下一个节点:
在这里插入图片描述

//删除指定节点
 ListNode.prototype.DeleteValue = function(val){
    let location = this.findValue(val);//查找到val的位置
    if(location==false){//如果没找到,就返回false
        return false;
    }
    let head1 = this.head;
    let head2 = null;
    if(location==1){//如果需要删除头结点,则直接让头结点指向下一个节点
        this.head=this.head.next;
        this.length--;
    }else{
        while(location>2&&head1.next!==null){//否则就找到它的上一个节点
            head1 = head1.next;
            location--;
        }
        head2 = head1.next.next;//找到他的下一个节点
        head1.next = head2;//将它的上一个节点和下一个节点连接在一起
        this.length--;
    }
    
}

7、ModifyLc(location,val)

直接找到需要修改的位置,然后将它的值修改为val。

//修改指定位置的值
 ListNode.prototype.ModifyLc = function(location,val){
     location = location-1;//起始位置是从0开始的,而正常是从1开始
    if(this.length<location||location<0){ //判断是否越界
        return false;
    }
    if(location==0){//改变头节点的值
        this.head.val = val
    }else{//改变后面的值
        let count = 0;
        let head1 = this.head;
        while(count<location&&head1!==null){//找到需要修改的位置
        head1 = head1.next;
        count++;
    }
    head1.val=val;//找到指定的位置后修改值
    }
 }

8、insert(location,val)

如果在头部插入:
在这里插入图片描述
在中间或尾部插入:

插入前:
在这里插入图片描述
插入后:
在这里插入图片描述

//向指定位置添加元素
 ListNode.prototype.insert = function(location,val){
     location = location-1//起始位置是从0开始的,而正常是从1开始
     //判断链表的长度和位置,如果需要插入的位置大于链表长度或者位置小于0,返回false
     if(this.length<location||location<0){
        return false;
     }
     let newNode = new Node(val);//创建需要插入的节点
     if(location==0){//如果在头部插入
        newNode.next = this.head;//将节点的next指向head
        this.head = newNode;//head指向第一个节点
     }else{//否则找到需要插入的位置
         let count = 0;
         let head1 = this.head;
         let head2 = null
         while(count<location&&head1!==null){
             head2 = head1;//找到需要插入的前一个节点
             head1 = head1.next;//找到需要插入的后一个节点
             count++;
         }
         head2.next = newNode;//将前一个节点的next指向插入的节点
         newNode.next = head1;//将插入节点的next指向后一个节点
     }
     this.length++;
 }

9、ReverseOrder()

如果链表只有一个节点或者为空,则不需要逆序。

否则

逆序过程的第一步图示如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

以上步骤整理后:在这里插入图片描述

//逆序
 ListNode.prototype.ReverseOrder = function(){
     let l1 = this.head;
    if(l1===null||(l1!==null&&l1.next==null)){//判断链表为空或者只存在一个节点,直接返回
    return l1;
    }else{//链表存在两个及以上的节点
    let head2 = l1.next;//让head指向l1的下一个节点
    let head1 = l1;//head1指向第一个节点
    while(head2.next!==null){
        l1.next = head2.next;//断开第二个指针,让第一个节点和第三个节点连接
        head2.next = head1;//将第一个节点☞向头节点
        head1 = head2;//head1更新到头节点上
        head2=l1.next;//head重新指向l1的第二个节点
    }
    if(head2!==null&&head2.next==null){//将最后一个节点指向头节点
        l1.next = null;
        head2.next = head1;
    }   
    this.head = head2
    }
}

完整链表的创建以及常用的方法。

//单链表的建立和基础操作
class Node{//创建一个节点类
    constructor(val, next){
        this.val = (val===undefined ? 0 : val)
        this.next = (next===undefined ? null : next)
    }
 }

 function ListNode(){//链表类  
        this.length = 0;
        this.head = null;
 }

//在链表尾部添加元素(val为节点的值)
 ListNode.prototype.addNode = function(val){
     //创建需要添加的节点
     let newNode = new Node(val);
    //判断链表是否为空,若不为空则在链表后面添加元素,否则它就是头节点
    if(this.length==0){
        this.head=newNode;
    }else{
        let head1 = this.head;
        while(head1.next!==null){//找到链表的尾部
        head1 = head1.next;
    }
    head1.next = newNode;//向链表的尾部添加节点
    }
    this.length++;//添加节点后对应的长度增加
 }

 ListNode.prototype.Length = function(){
     return this.length;//返回它的长度,就是链表的长度
 }

 //打印链表
 ListNode.prototype.display = function(){
    let head1 = this.head;
    let res  = [];//用数组保存遍历的链表里的值
    let i = 0;
    while(head1!==null){//依次遍历链表,并将值存入数组
        res[i] = head1.val;
        head1 = head1.next;
        i++;
    }
    return res;
 }

 //替换指定值
 ListNode.prototype.ModifyValue = function(val1,val2){//将val1替换为val2
     let location = this.findValue(val1);//查找到val1的位置
     if(location==false){//如果没有查找到,返回false
         return false;
     }
     let head1 = this.head;//如果查找到了,就找到那一个节点,并将值替换
     while(head1!==null&&location>1){
         head1 = head1.next;
         location--;
     }
     head1.val = val2;
 }


 
 //查找指定的值,返回它的位置
 ListNode.prototype.findValue = function(val){
    let head1 = this.head;
    let count = 0;
    while(head1!==null){//依次遍历链表
        if(head1.val==val){//如果找到了,就返回它的位置
            count++;
            return count;
        }else{//没找到就一直往下找;
            head1 = head1.next;
            count++;
        }
    }
    return false;//遍历完后,如果没找到就返回false
 }

 //删除指定节点
 ListNode.prototype.DeleteValue = function(val){
    let location = this.findValue(val);//查找到val的位置
    if(location==false){//如果没找到,就返回false
        return false;
    }
    let head1 = this.head;
    let head2 = null;
    if(location==1){//如果需要删除头结点,则直接让头结点指向下一个节点
        this.head=this.head.next;
        this.length--;
    }else{
        while(location>2&&head1.next!==null){//否则就找到它的上一个节点
            head1 = head1.next;
            location--;
        }
        head2 = head1.next.next;//找到他的下一个节点
        head1.next = head2;//将它的上一个节点和下一个节点连接在一起
        this.length--;
    }
    
}


 //修改指定位置的值
 ListNode.prototype.ModifyLc = function(location,val){
     location = location-1;//起始位置是从0开始的,而正常是从1开始
    if(this.length<location||location<0){ //判断是否越界
        return false;
    }
    if(location==0){//改变头节点的值
        this.head.val = val
    }else{//改变后面的值
        let count = 0;
        let head1 = this.head;
        while(count<location&&head1!==null){//找到需要修改的位置
        head1 = head1.next;
        count++;
    }
    head1.val=val;//找到指定的位置后修改值
    }
    

 }

 //向指定位置添加元素
 ListNode.prototype.insert = function(location,val){
     location = location-1//起始位置是从0开始的,而正常是从1开始
     //判断链表的长度和位置,如果需要插入的位置大于链表长度或者位置小于0,返回false
     if(this.length<location||location<0){
        return false;
     }
     let newNode = new Node(val);//创建需要插入的节点
     if(location==0){//如果在头部插入
        newNode.next = this.head;//将节点的next指向head
        this.head = newNode;//head指向第一个节点
     }else{//否则找到需要插入的位置
         let count = 0;
         let head1 = this.head;
         let head2 = null
         while(count<location&&head1!==null){
             head2 = head1;//找到需要插入的前一个节点
             head1 = head1.next;//找到需要插入的后一个节点
             count++;
         }
         head2.next = newNode;//将前一个节点的next指向插入的节点
         newNode.next = head1;//将插入节点的next指向后一个节点
     }
     this.length++;
 }
 //逆序
 ListNode.prototype.ReverseOrder = function(){
     let l1 = this.head;
    if(l1===null||(l1!==null&&l1.next==null)){//判断链表为空或者只存在一个节点,直接返回
    return l1;
    }else{//链表存在两个及以上的节点
    let head = l1.next;//让head指向l1的下一个节点
    let head1 = l1;//head1指向第一个节点
    while(head.next!==null){
        l1.next = head.next;//断开第二个指针,让第一个节点和第三个节点连接
        head.next = head1;//将第一个节点☞向头节点
        head1 = head;//head1更新到头节点上
        head=l1.next;//head重新指向l1的第二个节点
    }
    if(head!==null&&head.next==null){//将最后一个节点指向头节点
        l1.next = null;
        head.next = head1;
    }   
    this.head = head
    }
}

 let list = new ListNode();
 list.addNode(1);
 list.addNode(2);
 list.addNode(3)
 list.insert(4,5)
 list.ModifyLc(4,9)
 console.log("查找到的位置:",list.findValue(9))
 console.log("链表的长度",list.Length());
 console.log("链表的遍历:",list.display());
 list.DeleteValue(9)
 console.log("删除节点后链表的长度",list.Length());
 console.log("删除节点后链表的遍历:",list.display());
 list.ModifyValue(3,7)
 console.log("替换后的链表",list.display())
//  let list1 = list.head;
 list.ReverseOrder();
 console.log("逆序后的链表",list.display())

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力做一只合格的前端攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值