【Java数据结构】通过Java理解和实现——顺序表和单链表(二)

简介: 线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…

🍉链表

🌵链表概念及结构

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。

链表结构非常多样,以下情况组合起来有8种链表结构:

  • 单向、双向
  • 带头、不带头
  • 循环、非循环

我们重点学习以下两种链表

61e7d2624a1747ed818944373f0f89d2.png

981e17d8406641f1b46bd57eb7c535dd.png

🍌无头单向非循环链表接口实现(注释非常详细,我👴👴都能看懂)

先写两个类,一个是链表类(包含有一个可变的头结点和实现各种功能的接口,因为是无头链表,所以这个头结点是可变的),一个是节点类(成员属性有value和next)


3676f9567f53494c863e1d3b8f4900f0.png

d37ae62301634e54bc47cd5df1583c50.png

接下来的接口都是写在链表类里的,因为链表是一个对象,我们要实现的就是一个链表对象所有的功能

🍈打印链表

打印链表其实和打印顺序表类似,遍历链表就好了,不过要注意一个点,这里需要引入一个局部变量cur来代替头节点去遍历,因为头结点在没添加或者删除节点之前是固定的,不要让头结点变来变去

//打印链表
   public void display(){
       ListNode cur = this.head;//利用创建一个局部变量cur来替代head,这样头结点就不会改变了
       while (cur!=null) {//遍历的条件就是下一个节点的引用(地址)不为null
           System.out.print(cur.value+" ");
           cur = cur.next;//找到下一个节点
       }
       System.out.println();
   }

🍈头插法插入

顾名思义,头插法就是从头部插入节点,使新创建的节点成为新的头结点,这里需要额外考虑一个点,就是头结点是否存在(链表是否为空),不过以下代码能处理头结点为空的情况(注意要先将原头结点的地址先存入新节点,再将新节点引用赋给原头结点成为新头结点)

//头插法
   public void addFirst(int data){
        ListNode node = new ListNode(data);//创建新节点并初始化节点的data
        node.next = this.head;//将当前头结点地址存到新节点的next里
        this.head = node;//将新创建的节点变为头结点
        //这两行代码包含了头结点为null的情况
   }

🍈尾插法插入

尾插法不同于头插法,必须先判断链表是否为空(判断头结点是否为null),然后引入局部变量cur遍历链表,直到cur.next为空的时候,说明找到尾节点了,此时的cur就是尾巴结点

//尾插法
   public void addLast(int data){
   //找尾巴,cur.next为null了,说明这是尾节点了
       ListNode node = new ListNode(data);//创建新节点并初始化节点的data
       if (this.head == null){ //尾插的第一次必须判断头结点是否为空
           this.head = node;//如果是第一次插入,则新节点就是头结点
       }
       ListNode cur = this.head; //引入局部变量cur遍历链表
           while(cur.next != null){ //next等于null了就跳出while了
               cur = cur.next;//找到下一个节点
           }
       cur.next = node;
   }

🍈查找是否包含关键字key在单链表当中

传入关键字key,依旧引入局部变量cur遍历链表,哪个节点的value等于key了,说明链表里有这个关键字,返回true,否则返回false

//查找是否包含关键字key是否在单链表当中
   public boolean contains(int key){
       ListNode cur = this.head;//引入局部变量cur遍历
           while(cur != null){//循环条件为节点引用不为null
               if (key == cur.value)
                   return true;//如果找到了,返回true
               cur = cur.next;//找到下一个节点
           }
           return false;
   }

🍈得到单链表的长度

依旧采取引用局部变量cur来遍历链表,还要多设置一个局部变量size来计数,只要节点不为null,size就+1,最后返回size的值就是链表长度了

//得到单链表的长度
   public int size(){
       int size=0;//引入局部变量来计数
       ListNode cur = this.head;
          while(cur != null){//遍历并计数
              size++;//节点不为null,计数器+1
              cur = cur.next;//找到下一个节点
          }
          return size;//返回链表长度
   }

🍈任意位置插入,第一个数据节点为0号下标

首先得判断你要插入的这个位置是否合法,然后这里需要额外写一个查找插入位置前一个节点的方法findIndex()用于插入节点,插入原理

9782adb441354eec90f66d0d152fee4b.png

//根据传入的index查找前一个节点并返回地址
   public ListNode findIndex(int index){
       ListNode cur = this.head;//引入局部变量遍历至index前一节点
       while (index-1 != 0){//停止条件就是index-1等于0了
       //也就是说遍历到index位置上一个节点了
           cur = cur.next;//向后遍历
           index--;//每向后找一个节点index减1
       }
       return cur;//返回index上一个节点引用
   }
//任意位置插入,第一个数据节点为0号下标
   public void addIndex(int index,int data){//需要创建一个查找index位置前一节点的函数
       if (index > 0 && index < size()) {//判断插入位置是否合法
           ListNode node = new ListNode(data);//创建新节点并初始化节点的data
           node.next = findIndex(index).next;//通过上边写的查找方法将index位置前一节点的下一节点引用赋给新插入节点的next
           findIndex(index).next = node;//将新节点的引用存到查找到的节点的next达到链接效果
       }
       else if (index==0) {//如果插入位置是0,则直接使用头插法插入
           addFirst(data);
           return;
       }
       else if(index==size()) {//如果插入位置是链表长度值,则直接使用尾插法插入
           addLast(data);
           return;
       }
       else
           System.out.println("位置不合法!");
       return;
   }

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

首先判断头结点是否为null(链表是否为空),然后有两种情况
①关键字在头结点:将头结点下一个节点设置为新头结点
②关键字不在头结点:将有关键字的节点的下一节点引用赋给有关键字节点的上一节点的next

//删除第一次出现关键字为key的节点
   public void remove(int key){
       if (this.head == null){//判断链表是否为空
           System.out.println("链表为空,不能删除");
           return;
       }
       ListNode cur = this.head;
       while(cur.next != null){//遍历链表
           if(cur.value == key) {//①关键字在头结点:将头结点下一个节点设置为新头结点
               head = cur.next;
               return;
           }
           else if(cur.next.value == key) {//②关键字不在头结点:将有关键字的节点的下一节点引用赋给有关键字节点的上一节点的next
               cur.next = cur.next.next;
               return;
           }
           cur = cur.next;
       }
       System.out.println("没有你要删除的节点");
   }

🍈删除所有值为key的节点

和上边删除第一次出现的key类似,只不过return换成了continue,再有就是需要设置一个局部变量size,删除过程进行完之后若删除前设置的size值没发生改变,则说明没有删除节点

//删除所有值为key的节点
   public void removeAllKey(int key){
       int size = size();
       if (this.head == null){
           System.out.println("链表为空,不能删除");
           return;
       }
       ListNode cur = this.head;
       while(cur.next != null){
           if(cur.value == key) {
               head = cur.next;
               continue;//删除之后不要return,继续遍历
           }
           else if(cur.next.value == key) {
               cur.next = cur.next.next;
               continue;//删除之后不要return,继续遍历
           }
           cur = cur.next;
       }
       if(size()==size) {//如果进行删除前设置的size等于进行删除后size()方法返回的值,说明没有进行删除操作
           System.out.println("没有你要删除的节点");
       }
   }

🍈清空链表

暴力清空,直接将头结点置空,这样整个链表就无法找到了

//清空链表
   public void clear(){
       this.head = null;
   }

顺序表和链表的区别与联系

顺序表

顺序表:一白遮百丑
白:空间连续、支持随机访问
丑:1.中间或前面部分的插入删除时间复杂度O(N) 2.增容的代价比较大。

链表

链表:一(胖黑)毁所有
胖黑:以节点为单位存储,不支持随机访问
所有:1.任意位置插入删除时间复杂度为O(1) 2.没有增容问题,插入一个开辟一个空间



相关文章
|
8天前
|
存储
数据结构—顺序表(如果想知道顺序表的全部基础知识点,那么只看这一篇就足够了!)
数据结构—顺序表(如果想知道顺序表的全部基础知识点,那么只看这一篇就足够了!)
|
8天前
|
存储 Java API
Java数据结构之ArrayList(如果想知道Java中有关ArrayList的知识点,那么只看这一篇就足够了!)
Java数据结构之ArrayList(如果想知道Java中有关ArrayList的知识点,那么只看这一篇就足够了!)
Java数据结构之ArrayList(如果想知道Java中有关ArrayList的知识点,那么只看这一篇就足够了!)
|
3天前
|
存储 缓存 安全
Java中的数据结构:选择与优化
Java中的数据结构:选择与优化
|
5天前
|
存储 测试技术
【数据结构】最最基础的链式结构——单链表,还不会你就吃大亏了!
【数据结构】最最基础的链式结构——单链表,还不会你就吃大亏了!
16 5
|
3天前
|
存储 C语言
顺序表(数据结构)
顺序表(数据结构)
|
8天前
|
存储 Java 索引
Java中ArrayList(顺序表)的自我实现(如果想知道Java中怎么自我实现ArrayList,那么只看这一篇就足够了!)
Java中ArrayList(顺序表)的自我实现(如果想知道Java中怎么自我实现ArrayList,那么只看这一篇就足够了!)
|
2天前
|
存储 算法 Java
解密Java中的运行时数据结构
解密Java中的运行时数据结构
|
2天前
|
存储 算法 Java
老程序员分享:java之数据结构【入门篇】
老程序员分享:java之数据结构【入门篇】
|
4天前
|
算法 程序员 数据处理
【数据结构与算法】使用单链表实现队列:原理、步骤与应用
【数据结构与算法】使用单链表实现队列:原理、步骤与应用
|
4天前
|
算法 C语言
【数据结构与算法 经典例题】返回单链表的倒数第 k 个节点
【数据结构与算法 经典例题】返回单链表的倒数第 k 个节点