LinkedList与链表

news/2024/11/13 4:23:17/

目录

1. 链表的概念:

2.链表的实现

ArrayList和LinkedList的对比:


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

根据前一章顺序表的介绍,我们发现对于顺序的删除和添加元素很麻烦,如果是一个非常大的基数那么我们所消耗的时间非常大,所以我们还有一种表可以极大的减少添加元素和删除元素操作的时间。那就是本章的主题:链表。   

1. 链表的概念:

定义:

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

特点:

      链表由一系列节点(链表中每一个元素称为节点)组成 ,每个节点包括两个部分:  

      一个是存储数据元素的数据域

     另一个是存储下一个节点地址的指针域

看代码:

我们有很多种方法,可以在一个类中创建一个内部类,是否静态任选;也可以自己创建一个ListNode类,再创建一个

SingleLinkedList 类把代码写在里面。 

随便选择一种,我这里选择再SingleLinkedList内写一个静态内部类。

static class ListNode  {public int val;//存储的数据public ListNode  next;//存储下一个节点的地址public ListNode(int val) {this.val = val;}}

在我们创建链表时,每new一个都是随机的地址,在物理上不连续,但是在逻辑上是连续的。

图示:

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
1. 单向或者双向
 

2. 带头或者不带头
 

 3. 循环或者非循环

虽然有这么多的链表的结构,但是我们重点掌握两种:
无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。
无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。
那么链表究竟是如何实现的呢?

2.链表的实现

 我们先写一个初始化

 public ListNode head;// 代表当前链表的头节点的引用// 初始化public ListNode CreateLinkedList () {ListNode node1 = new ListNode(2);ListNode node2 = new ListNode(4);ListNode node3 = new ListNode(6);ListNode node4 = new ListNode(2);head = node1;//记录头节点node1.next = node2;//我们用next链接后一个结点node2.next = node3;node3.next = node4;return head;};

对链表的插入分为头插和尾插:

 //头插法public void addFirst(int data) {ListNode node = new ListNode(data);node.next = head;head = node;};//尾插法public void addLast(int data) {ListNode node = new ListNode(data);if (head == null) {head = node;}ListNode cur = head;while (cur.next != null) {cur = cur.next;}cur.next = node;};

我们也可以选择在任意位置去下表选择型的插入:

 //任意位置插入,第一个数据节点为0号下标public boolean addIndex(int index,int data) {checkIndex(index);//判断下表是否合理if(index == 0) {addFirst(data);return true;}if(index == size()) {addLast(data);return true;}ListNode cur = findIndexSubOne(index);//找到下表前一个位置处ListNode listNode = new ListNode(data);listNode.next = cur.next;cur.next = listNode;return true;};private ListNode findIndexSubOne(int index) {ListNode cur = head;int count = 0;while (count != index-1) {cur = cur.next;count++;}return cur;}private void checkIndex(int index) {if(index < 0 || index > size()) {throw new ListIndexOutOfException("index位置不合法");}}
public class ListIndexOutOfException extends RuntimeException{public ListIndexOutOfException() {}public ListIndexOutOfException(String message) {super(message);}
}

删除操作:

    //查找是否包含关键字key是否在单链表当中public boolean contains(int key){ListNode cur = head;while (cur != null) {if(cur.val == key) {return true;}cur = cur.next;}return false;}//删除第一次出现关键字为key的节点public void remove(int key) throws NothingnessException {if (!contains(key)) {//contains方法用于查询是否有该元素throw new NothingnessException("key不存在");}if (head == null) {throw new NullPointerException("头节点为空");//抛出异常}if(head.val == key) {head = head.next;return;}ListNode cur = searchPrev(key);//找到需要删除结点的前一个结点ListNode del = cur.next;cur.next = del.next;};private ListNode searchPrev(int key) {ListNode cur = head;while (cur.next != null) {if(cur.next.val == key) {return cur;}cur = cur.next;}return null;//没有你要删除的节点}
public class NothingnessException extends Exception{public NothingnessException() {}public NothingnessException(String message) {super(message);}
}

删除所有结点为key的值

 //删除所有值为key的节点public void removeAllKey(int key) throws NothingnessException {if (!contains(key)) {throw new NothingnessException("key不存在");}if (head == null) {throw new NullPointerException("头节点为空");}ListNode cur = head;while (cur.next != null) {if (cur.next.val == key) {cur.next = cur.next.next;}cur = cur.next;}};

还有其他的操作:求链表长度,我们链表长度不同于顺序表,顺序表可以直接得到表长,我们链表只能通过计数器一个个去加加。

​//得到单链表的长度public int size() {int count = 0;ListNode cur = head;while (cur != null) {count++;cur = cur.next;}return count;};
//清除表public void clear() {head = null;};
//移除所有元素public ListNode removeElements( int val) {if (head == null) {throw new NullPointerException("头节点为空");}ListNode slow = head;ListNode fast = head;while(fast.next != null) {if(fast.val != val) {slow = slow.next;} else {slow.next = fast;}fast = fast.next;}return head;}
}​

 测试:

public class Main {public static void main(String[] args) throws NothingnessException {SingleLinkedList myLinkedList = new SingleLinkedList();myLinkedList.CreateLinkedList();myLinkedList.display();myLinkedList.addFirst(1);myLinkedList.addLast(100);myLinkedList.addIndex(2,20);myLinkedList.display();System.out.println(myLinkedList.contains(100));myLinkedList.remove(100);myLinkedList.display();System.out.println(myLinkedList.size());myLinkedList.clear();myLinkedList.display();}
}

结果:

ArrayList和LinkedList的对比:

一、ArrayList和LinkedList查询之间的区别

首先,从名字就可以看出,ArrayList和LinkedList的区别,ArrayList是基于数组的,LinkedList是基于链表的。

从这一点,我们可以推理出来,ArrayList适合查询,LinkedList适合插入,但是这只是一个广泛的结论,我们应该了解的更细致一点。

比如,对于ArrayList,它真正的优点是按下标查询元素,相比于LinkedList,LinkedList也可以按下标查询元素,但是LinkedList需要对底层链表进行遍历,才能找到指定下标的元素,而ArrayList不用,所以这是ArrayList的优点。

但是,如果我们讨论的是获取第一个元素,或最后一个元素,ArrayList和LinkedList在性能上是没有区别的,因为LinkedList中有两个属性分别记录了当前链表中的头结点和尾结点,并不需要遍历链表。

以上,是对于ArrayList和LinkedList在查询方面的区别。

二、ArrayList和LinkedList插入之间的区别

ArrayList可以插入到指定下标位置,或者数组末尾,这种插入普通情况下是很快的,但是如果某次插入操作触发了扩容,那么本次插入就增加了额外的扩容成本。

对于LinkedList,如果是插在链表的头部或者是尾部都是很快的,因为LinkedList中有单独的属性记录的链表的头结点和尾结点,不过,如果是插在指定下标位置,那么就需要遍历链表找到指定位置,从而降低了效率。

但是,使用LinkedList是不用担心扩容问题的,链表是不需要扩容的。


http://www.ppmy.cn/news/3483.html

相关文章

linux批量操作文件命令总结

总结下常用的linux命令&#xff0c;linux下的命令组合着实强大。有时候即便是使用的windows系统也可以在Dos窗口下使用linux下的一些命令工具&#xff0c;完成一些文本日常处理。 查找所有文件 find ./ -name "*.log" 查找某一后缀的文件并删除 find ./ -name &qu…

C# !(null包容)运算符的使用

总目录 文章目录总目录前言一、!(null包容&#xff09;运算符是什么&#xff1f;二、!(null包容&#xff09;运算符如何使用&#xff1f;1.使用2.扩展-预处理器指令启用或关闭null检查总结前言 本文主要讲解&#xff01;&#xff08;null包容&#xff09;运算符的使用&#xf…

内核动力之源——内存管理

目录 内存管理背后的故事 内存管理概述 常见内存分配策略 LwIP的宏配置及内存管理 见招拆招——动态内存堆 数据结构描述 函数实现 ​以不变应万变——动态内存池 数据结构描述 函数实现 使用C库管理内存策略 无论在哪种系统中&#xff0c;动态内存都是一个非常重要的…

【内网安全-基础】基础知识、信息收集、工具

目录 一、基础知识 1、内网&#xff1a; 2、工作组&#xff1a; 3、域(Domain)&#xff1a; 二、基础信息收集 1、判断是否在域内 2、机器角色判断 3、出网协议判断 4、端口判断 三、常规信息收集 1、常用命令 2、常用命令 3、工具&插件 LadonGO CS插件 Adfi…

基于PHP和MySQL的新闻发布系统

关于世界杯⚽️ 国际足联世界杯&#xff08;FIFA World Cup&#xff09;&#xff0c;简称“世界杯”&#xff0c;是由全世界国家级别球队参与&#xff0c;象征足球界最高荣誉&#xff0c;并具有最大知名度和影响力的足球赛事。世界杯全球电视转播观众超过35亿 。世界杯每四年举…

传输层协议 —— TCP(图解2)

​ 目录 一、前言 二、重传机制 1. 超时重传 2. 快速重传 3. SACK 4. D-SACK 三、滑动窗口 1. 发送方的滑动窗口 2. 程序是如何表示发送方的四个部分 3. 接收方的滑动窗口 四、流量控制 五、拥塞控制 1. 慢启动 2. 拥塞避免 3. 拥塞发生 4. 快速恢复 六、TCP…

内卷起来,2023年外贸B2B企业怎么通过独立站吸引客户的注意

从国外疫情解封后&#xff0c;中国在2022年的最后一个月也解封了&#xff0c;我们努力了三年&#xff0c;现在不再查核酸、健康码&#xff0c;多家航空公司重新开通了国际航班。对许多外贸公司来说&#xff0c;是“外贸春天”的到来。那么即将到来的2023年&#xff0c;外贸B2B企…

什么才是写博客初心如何坚持

为何写机器人课程博客并一直坚持&#xff1f;&#xff08;2021&#xff09; 创新源自真心&#xff0c;“乱”创新的课程徒有其表&#xff0c;“不”创新的课程逐渐凋零。 个人觉得&#xff0c;课程教学创新宏观上的目标是让学生更好的认识自己并适应社会发展和变化&#xff1b…