Sequential And Linked Lists - 顺序表 和 链表 - 单向链表部分 - java(图文并茂,你值得一看)

本文深入介绍了链表的概念,包括带头、不带头、单向、双向、循环和不循环的链表类型。通过代码详细展示了如何创建单向不带头非循环链表,以及实现头插法、尾插法、查找、删除等基本操作。强调了遍历时保护头引用的重要性,并提供了相应代码示例和效果展示。

文章目录

回顾 和 链表

在这里插入图片描述


接下来我们来通过代码 来认识链表

1 准备工作

在这里插入图片描述


2 根据 前面 所说的,根据节点的特性写一个类

在这里插入图片描述


3. new 节点

在这里插入图片描述
执行到这里,我们就有了这样一个节点,而链表就是由这一个个节点,串成的。


 

我们已经知道怎么实例化一个节点,但是我们又怎么做,才能知道下一个节点的地址呢?

      要想知道它怎么做,我们必须实现 它 的 一个 头插 和 尾插, 等等一系列操作,但是我们目前先不管它
      我们现在最重要的是 了解 链表的结构

我先来把前面的东西讲清楚。

链表的头引用 head

在这里插入图片描述


理解链表中: 带头、不带头、单向、双向、循环、不循环的意思。

带头 和 不带头

在这里插入图片描述


循环 和 不循环

在这里插入图片描述


单向 和 双向

在这里插入图片描述


至此 我们将链表的结构 全部分析完了。


接下来,我会以代码的形式 来带你们认识 链表。

以穷举的方式 创建一个链表 (这方法很low,不建议去这样写,现在只是为了帮助我们去理解链表)

现在 我要实现 单向 不带头 非循环的链表

在这里插入图片描述


回到代码

在这里插入图片描述


 

创建一个函数,来实现链表的结构

先创建五个节点

在这里插入图片描述


将五个节点连接起来。

在这里插入图片描述


现在链表结构,已经构造好了,它的头节点就是节点1,将 节点一 的地址 赋给 头引用 head

在这里插入图片描述


遍历链表数据

 首先,我要区分清楚,链表 不是顺序表,不是一块连续的空间。 链表的每个元素 是由地址来连接起来的。
   也就是说 我们不能使用普通思维模式 去思考 遍历链表的数据域的值

 既然 链表是靠地址联系起来的,也就是说 靠 next域中 存储的地址来联系个节点的数据
 这就是我们突破点。
  利用 head 遍历每个每个节点的数据  写法 head =  head/next,你可以参考上面的图,来细品。
  这样我们就跳转到下一个节点,算了我还是画个图,请看下图(注意我埋了一个坑,你们等会就知道,只有被打过,才会知道疼)

在这里插入图片描述


揭秘坑

在这里插入图片描述


解决方法 (创建一个head的替身 【cur == current — 目前的】,来代替head去遍历链表数据)

代码如下:

在这里插入图片描述


调用者程序

在这里插入图片描述

效果图

在这里插入图片描述

另外注意一点

在这里插入图片描述


效果图

在这里插入图片描述


总结:

 遍历链表的时候, 尤其是我们现在所讲的 不带头的链表,一定注意,不要让 头引用丢失,创建一个替身变量,让它去做。
 保证头引用指向的永远都是 头节点,

链表要实现的功能

在这里插入图片描述


查找关键字key是否在链表当中

    public boolean contains(int key){
        ListNode cur = this.head;
        while(cur!=null){
            if(cur.val==key){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

附图

在这里插入图片描述


效果图(最好两边加中间,还有找不到的情况都要测试一下)

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


 

得到单链表的长度

  public int size(){
        int count=0;
        ListNode cur = this.head;
        while(cur!=null){
            count++;
            cur=cur.next;
        }
        return count;
    }

附图

在这里插入图片描述


头插法

public void addFirst(int data){
           ListNode node = new ListNode(data);
           node.next = this.head;
           this.head = node;
        }

附图

在这里插入图片描述


效果图

在这里插入图片描述


使用头插法,创建链表

在这里插入图片描述


尾插法

public void addLast(int data){
             ListNode node = new ListNode(data);
             if(this.head == null){
               this.head = node;
             }else{
                 ListNode cur = this.head;
                 while(cur.next!=null){
                     cur = cur.next;
                 }
                 cur.next = node;
             }

        }

附图

在这里插入图片描述*****

效果图

在这里插入图片描述


任意位置插入一个数据节点

public void addIndex(int index,int data){
     if(index<0 || index>size()){
         System.out.println("插入数据节点的位置不合法");
         return;
     }
     if(index==0){
         addFirst(data);// 调用头插
         return;
    }
     if(index== size()){
         addLast(data);
         return;
     }
      ListNode cur = findIndex(index);// 接收 index-1位置节点的地址
      ListNode node = new ListNode(data);// 根据 data的值,新建一个节点
      
      // 插入节点程序
      node.next = cur.next;
      cur.next = node;

}
// 找到index-1位置的节点位置
// 跟图解解释的一样,如果你要插入一个位置,你就需要找它的前一个节点的位置
// 而我们是链表没有下标,所以返回是 前一个节点的地址
public ListNode findIndex(int index){
      ListNode cur = this.head;
    while(index-1 != 0){
        cur = cur.next;
        index--;
    }
    return cur;
}

附图

在这里插入图片描述


效果图

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


删除第一次出现关键字为key的节点

public void remove(int key){
if(this.head == null){// head为空
    System.out.println("链表为空,无数字可删除!");
    return;
}
if(this.head.val == key){// 判断头节点是为删除数字
    this.head = this.head.next;
    return;
}
ListNode cur = searchPrev(key);// 找到删除节点的前一个节点
if(cur == null){
    System.out.println("没有你要删除元素");
    return;
}
ListNode del = cur.next;// 要删除的节点地址
cur.next =  del.next;// 删除节点

}
// 寻找删除节点的前一个节点(key的前驱)
public  ListNode searchPrev(int key){
  ListNode cur = this.head;
  while(cur.next != null){
      if(cur.next.val == key)
      {
          return cur;
      }
      cur = cur.next;
  }
  return null;// 表示没找到
}

附图

在这里插入图片描述


效果图

在这里插入图片描述


在这里插入图片描述


删除所有值为key的节点

public ListNode removeAllKey(int key){
      if(this.head == null){
          return null; // 防止后面的cur出现空指针错误
      }
      ListNode prev = this.head;
      ListNode cur = this.head.next;
      while(cur!=null){
          if(cur.val == key){
              prev.next = cur.next;
              cur=cur.next;
          }else{
               prev = cur;
               cur=cur.next;
          }
      }
      // 最后处理头
      if(this.head.val==key){
          this.head = this.head.next;
      }
      return head;
}

附图

在这里插入图片描述


效果图

在这里插入图片描述


清除链表的所有的节点

public void clear(){
// this.head = null; 粗暴方法

// 温柔的(最稳的)
    while(this.head!=null){
        ListNode headNext = head.next;
        this.head.next = null;
        this.head = headNext;
    }
}

附图

在这里插入图片描述


效果图

在这里插入图片描述


还有一种更直观的方法,请看连续图

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

附上链表程序

在这里插入图片描述


调用者程序

在这里插入图片描述

本文至此,就将链表的所有功能都实现了。有疑问的可以在下方评论,大家一起共同进步

评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Dark And Grey

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

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

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

打赏作者

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

抵扣说明:

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

余额充值