IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 链表的概念和结构及基本功能函数的实现(单链表的实现) -> 正文阅读

[数据结构与算法]链表的概念和结构及基本功能函数的实现(单链表的实现)

🎓??引言

??顺序表的问题及思考,之前我写了一篇顺序表的博客,发现数组和顺序表基本一样,很简单地就实现了,但存在一些问题比如:

  • 顺序表中间/头部的插入删除,时间复杂度为O(N)
  • 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
  • 增容一般是呈2倍的增长也可以是其他,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

那么 如何解决以上问题呢?答案是我们可以通过链表来解决上面存在的问题,链表适合插入和删除元素,可以做到随用随取不浪费空间,顺序表则适合给定要查找元素的下标进行查找,

各有各的有点,下面给出了链表的结构来简单地看一下。

🎓??链表的概念及结构

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用变量来实现的 ,如下图的链表:
在这里插入图片描述
下面是链表节点的基本结构:
在这里插入图片描述
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
单/双向—>带/不带头——>循环/非循环(2x2x2)

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

📝📐本篇博客重点实现单链表的基本功能,双链表后期博文讲解,而单向链表中,比较难,重要,面试经常遇到的就是单向不带头非循环的链表了,因此我们重点讲解它。单向的带头和循环的很简单,我们把不带头的非循环的明白了,其他的学习起来也很简单了。
注意事项:
对于这里所说的链表带不带头,我们需要好好理解下,

  • 不带头的单向非循环链表,这个链表没有真正的头结点,但是我们把第一个节点叫做头结点,这个节点是个虚拟的,只起一个标识作用,标识这个链表的头结点
  • 这个头结点的位置随时可能发生这变化,是不固定的,之后通过这个头结点我们要完成一些链表的增删查改。从头开始,因此头很重要
  • 带头结点的链表,有正真的头结点,这个头结点也是用来标识头结点的位置的,这个节点的位置不会发生改变, 但这个头结点里面的值不被使用,带头的就很简单,比如每次头插,头都不变。

下面看代码的时候你就会真正地感受到了,下面是几种循环的结构:

单向不带头非循环链表
在这里插入图片描述
单向带头非循环链表
在这里插入图片描述
单向不带头循环链表
在这里插入图片描述

🎓??单链表的实现及图示分析

通过分析上面的链表,我们可以抽象出两个类,一个是链表本身是一个类(链表这种类型)定义在MyLinkedList.java这个java文件中,另外链表里面的节点也可以看做一个类,定义在Node.java这个文件中,这两个链表里面有不同的成员属性,利用面向对象的思想来实现我们所要的单链表。
在这里插入图片描述

📝🔷单链表之创建单链表

以穷举的方式创建单链表
分别实例化了四个对象,并且调用构造方法进行值的初始化,在通过节点里面引用变量的指向使所有节点连接起来。

public void createList() {
        Node node1 = new Node(12);
        Node node2 = new Node(3);
        Node node3 = new Node(5);
        Node node4 = new Node(2);
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        this.head = node1;
    }

在这里插入图片描述

📝🔷单链表之计算单链表的长度

这个很简单遍历链表元素就行, 创建一个临时节点,代替头结点遍历,头结点的位置很重要起到标识作用不能随便改变, 没有了头就不能找到这个链表了,还要注意遍历的结束条件。

 //得到单链表的长度
    public int size() {
        Node cur = this.head;//创建一个临时节点,代替头结点遍历,头结点的位置很重要起到标识作用不能随便改变,没有了头就不能找到这个链表了
        int count = 0;
        while (cur != null) {
            count++;//4
            cur = cur.next;//cur这个节点向后移动一步
        }
        return count;
    }

在这里插入图片描述

📝🔷单链表之打印单链表

打印单链表也很简单,遍历打印就行,只是链表元素向后移动是通过引用变量指向对象的移动移动的。

 public void show() {
        Node cur = this.head;
        while(cur != null) {
            System.out.print(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();
    }

在这里插入图片描述

📝🔷单链表之单链表的增删查改

📝🔷头插法插入元素

头插法插入元素的时候需要注意:

  1. 在插入一个节点的时候,一定要先使插入节点的空指针域指向下一个节点的地址,再更换头结点
  2. 新插入的节点是头结点
  3. 如果插入时,head为空,则证明之前链表没有数据,直接this.head=node即可,之后又按第一个节点不是null的方法插入即可
//头插法
    public void addFirst(int data) {
        Node node = new Node(data);
        if(this.head == null) {
            this.head = node;
        }else {
            node.next = this.head;
            this.head = node;
        }
    }

在这里插入图片描述

🐮🐵尾插法插入元素

如果一个链表为空,也就是头结点head==null,直接插入一个元素既是头也是尾,不为空的时候通过while循环找到尾巴节点,**当 cur.next为null时候是尾巴节点,**再使这个尾巴节点里面存储node节点的地址,这样把所有的节点都连接起来了。

//尾插法
    public void addLast(int data) {
        Node node = new Node(data);
        if(this.head == null) {//链表为空没有元素
            this.head = node;
        }else {
            Node cur = this.head;
            while (cur.next != null) {
                cur = cur.next;
            }
            cur.next = node;//连接下一个节点
        }
    }

在这里插入图片描述

🐮🐵把一个节点插入到链表的任意位置

对于链表里面的元素,假设第一个元素的下标为0,第二个元素下标为2,以此类推,插入元素之前要判断元素位置的合法性,插入位置,0=<index<=size,当插入位置为0的时候,相当于头插法,当index=size的时候,相当于尾插法,插入元素在中间的时候,插入到插入位置的前面,之后连接前后两个元素即可。

寻找插入点的前一个节点
在这里插入图片描述

//寻找前驱节点
 public Node searchPrev(int index) {
        Node cur = this.head;
        int count = 0;
        while(count != index-1) {
            cur = cur.next;
            count++;
        }
        return cur;//
    }

中间插入元素
在这里插入图片描述

    //任意位置插入,第一个数据节点为0号下标
    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;
        }
        Node cur = searchPrev(index);
        Node node = new Node(data);
        node.next = cur.next;
        cur.next = node;
    }

🐮🐵查找链表中是否含有某个元素

从链表的头到尾遍历,看是否含有某个值, 注意遍历链表的条件是cur==null;

//查找是否包含关键字key是否在单链表当中 
    public boolean contains(int val) {
        Node cur = this.head;
        while (cur != null) {
            if(cur.val == val) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

🐮🐵删除链表中第一次出现value值的节点

删除链表中第一次出现value值的节点,首先这个链表要不为空,为null就直接返回什么都不用做了,不为空,找到要删除节点的前面一个节点,**使前驱节点连接要删除节点后面的一个节点就把那个值给删除了,**另外如果头结点为删除的节点要单独判断,更换头结点就删除了。详细解释看图
在这里插入图片描述

public Node searchPrevNode(int val) {
        Node cur = this.head;
        while (cur.next != null) {
            if(cur.next.val == val) {
                return cur;
            }
            cur = cur.next;
        }
        return null;
    }

    //删除第一次出现关键字为key的节点
    public void remove(int val) {
        if(this.head == null) return;
        //单独判断头节点的问题
        if(this.head.val == val) {
            this.head = this.head.next;
            return;
        }
        Node cur = searchPrevNode(val);
        if(cur == null) {
            System.out.println("没有你要删除的节点!");
            return;
        }
        Node del = cur.next;
        cur.next = del.next;
    }

如果是头结点是要删除的节点
在这里插入图片描述

🐮🐵删除链表中出现value值得所有节点

👀😄删除链表中出现的value值的所有节点,和之前删除出现value值的方法差不多,定义一个prev标记要删除节点的前驱,找到要删除的节点跳过它就行了, 但要注意出现连续要删除的value值和头节点是要删除的节点的情况。
在这里插入图片描述

//删除所有值为key的节点
    public void removeAllKey(int val) {
        if(this.head == null) {
            return;
        }
        Node prev = this.head;
        Node cur = this.head.next;
        while (cur != null) {
            if(cur.val == val) {
                prev.next = cur.next;
                cur = cur.next;
            }else {
                prev = cur;
                cur = cur.next;
            }
        }
        //最后判断头节点
        if(this.head.val == val) {
            this.head = this.head.next;
        }
    }

因为在删除节点时,**前驱节点一定是在判断是否要删除的节点cur的前面,**也就是说通过上面的方法删除节点,头结点的值没判断,要删除后面出现的value值后,要单独判断头结点的情况。

🐮🐵清空单链表

👀😄jvm有自动回收机制,当一个对象没有被引用的时候就被回收了,当然我们也可以手动的将其设置了不被引用,而回收,最简单的清空链表的方法把头结点置为null,它不引用别的节点,别的节点也都不被引用,整个链表就被jvm回收了,当然最好还是一个一个节点的next域置为null,使他们都不被引用。
在这里插入图片描述

 public void clear() {
        while (this.head != null) {
            Node curNext = this.head.next;
            this.head.next = null;
            this.head = curNext;
        }
    }

📝📐有三个类文件,最后把所有链表功能代码放在代码组合在一起放在MyLinkedList.java就是完整功能代码了,下面是测试类的代码,用于测试我们单链表的功能,还有一个链表节点的类文件Node.java。

public class Test {
    public static void main(String[] args) {
        MyLinkedList myLinkedList = new MyLinkedList();
        //myLinkedList.createList();
        myLinkedList.addLast(8);
        myLinkedList.addLast(9);
        myLinkedList.addLast(1);
        myLinkedList.addLast(1);
        myLinkedList.addLast(16);
        myLinkedList.addLast(7);
        myLinkedList.show();//1  2  3  4
        myLinkedList.removeAllKey(1);
        myLinkedList.show();
   System.out.println(myLinkedList.contains(21));//false*/

    }
}

Node.java类文件

public class Node {
    public int val;
    public Node next;//null

    public Node(int val) {
        this.val = val;
    }

如🈶?题请🈯正,记🉐点👍🏻🍹持,🦀🦀,🦀🦀

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-21 15:43:11  更:2021-08-21 15:43:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:54:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码