【数据结构】双链表

链表(二)

文章目录

  • 链表(二)
    • 00 引入
    • 01 类的搭建
    • 02 得到链表的长度
    • 03 打印链表
    • 04 查找是否包含关键字key是否在链表当中
    • 05 头插法
    • 06 尾插法
    • 07 任意位置插入
    • 08 删除关键字为key的节点
    • 09 删除所有值为key的节点
    • 10 清空
    • 11 LinkedList常规一些操作
    • 12 ArrayList与LinkedList的区别

00 引入

衔接上文单链表,相较于本篇将要讲的双链表,单链表有以下弱势:

  1. 难以反向遍历:由于单链表只包含一个指针,即指向下一个节点的指针,无法直接访问前一个节点。因此,在单链表中反向遍历需要从头节点开始顺序遍历到目标节点,效率相对较低。
  2. 难以在任意位置快速插入和删除:在双链表中,可以通过两个指针的操作快速定位到目标节点的前后节点,从而在O(1)时间复杂度内进行插入和删除操作。而在单链表中,为了插入或删除目标节点,需要先找到目标节点的前一个节点,并修改其指针指向,操作相对复杂,时间复杂度为O(n)。
  3. 难以在尾部追加节点:由于单链表只有一个指针指向下一个节点,如果要在单链表的尾部追加节点,就需要遍历整个链表找到尾节点,然后进行操作。而双链表在尾部追加节点只需要修改尾节点的指针,操作更加简单和高效。

那么接下来就让我们来实现一下非循环双向链表。

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。

01 类的搭建

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QcuqlesW-1692202718939)(https://gitee.com/liuhb-clanguage/picture/raw/master/png/image-20230816161634477.png)]

示例代码如下:

static class ListNode{private int val;private ListNode prev;private ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;//定义双向链表的头节点public ListNode last;//定义双向链表的尾巴

02 得到链表的长度

这个其实就是遍历一下链表,和单链表的操作没有区别。

示例代码如下:

//得到单链表的长度public int size(){ListNode cur = this.head;int count = 0;while(cur != null){count++;cur = cur.next;}return count;}

03 打印链表

原则如02操作。

示例代码如下:

public void display(){ListNode cur = this.head;while(cur != null){System.out.println(cur + "->");cur = cur.next;}System.out.println("null");}

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

原则如02 03操作

示例代码如下:

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

05 头插法

注意考虑点:

  1. 考虑空链表的情况:如果链表为空,即没有任何节点,那么插入的节点将成为新的头节点。在这种情况下,需要特殊处理头节点的前后指针。
  2. 更新头节点的前驱指针:在头插法中,插入的节点将成为新的头节点,所以需要更新原头节点的前驱指针,让它指向新的头节点。
  3. 更新新头节点的后继指针:插入的节点作为新的头节点,它的后继指针需要指向原来的头节点,以连接链表的其他节点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-svd1z80U-1692202718941)(https://gitee.com/liuhb-clanguage/picture/raw/master/png/image-20230816173601219.png)]

示例代码如下:

//头插法public void addFirst(int data){ListNode node = new ListNode(data);if(head == null){head = node;last = node;}else {node.next = head;head.prev = node;head = node;}}

06 尾插法

注意点:

  1. 考虑空链表的情况:如果链表为空,即没有任何节点,那么插入的节点将成为新的头节点。在这种情况下,需要特殊处理头节点的前后指针。
  2. 更新尾节点的后继指针:在尾插法中,插入的节点将成为新的尾节点,所以需要更新原尾节点的后继指针,让它指向新的尾节点。
  3. 更新新尾节点的前驱指针:插入的节点作为新的尾节点,它的前驱指针需要指向原来的尾节点,以连接链表的其他节点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lMOLYOpQ-1692202718941)(https://gitee.com/liuhb-clanguage/picture/raw/master/png/image-20230816175501258.png)]

示例代码:

//尾插法public void addLast(int data){ListNode node = new ListNode(data);if (head == null){head = node;last = node;}else {last.next = node;node.prev = last;last = node;}}

07 任意位置插入

注意点:

  1. 判断插入位置是否合法:首先要确保插入的位置在链表的长度范围内,即在 0 到链表长度的范围之间。
  2. 更新插入节点的前驱指针和后继指针:在进行任意位置插入时,需要更新插入节点的前驱指针和后继指针,使其正确指向前一个节点和后一个节点。
  3. 更新前后节点的指针:需要更新前一个节点和后一个节点的后继指针和前驱指针,让它们正确地连接到插入节点上。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xGTg5bi9-1692202718942)(https://gitee.com/liuhb-clanguage/picture/raw/master/png/image-20230816222255142.png)]

示例代码:

//任意位置插入,第一个数据节点为0号下标public void addIndex(int index,int data){checkIndex(index);if(index == 0){addFirst(data);return;}else if (index == size()){addLast(data);return;}ListNode node = new ListNode(data);ListNode cur = head;while(index != 0){cur = cur.next;index--;}node.next = cur;cur.prev.next = node;node.prev = cur.prev;cur.prev = node;}private void checkIndex(int index){if (index < 0 || index > size()){throw new IndexOutOfException("index 不合法");}}

08 删除关键字为key的节点

  1. 查找要删除的节点:首先需要在双链表中找到第一次出现关键字为key的节点。遍历链表,逐个比较节点的值,直到找到目标节点或遍历到链表末尾。
  2. 更新前后节点的指针:找到目标节点后,需要更新前一个节点和后一个节点的后继指针和前驱指针,让它们正确地连接起来。
  3. 处理删除头节点的情况:如果需要删除头节点,需要特殊处理。即使要删除的节点是头节点,也要正确更新头指针。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R2SwLt4Z-1692202718942)(https://gitee.com/liuhb-clanguage/picture/raw/master/png/image-20230816234333333.png)]

示例代码:

//删除第一次出现关键字为key的节点public void remove(int key){ListNode cur = head;while (cur != null) {if (cur.val == key) {//删除头节点if (cur == head) {head = head.next;if (head != null) {//考虑只有一个节点的情况head.prev = null;}else {last = null;}} else {//删除中间节点以及尾巴节点if (cur.next != null) {//中间节点cur.prev.next = cur.next;cur.next.prev = cur.prev;} else {//尾巴节点cur.prev.next = cur.next;last = last.prev;}}return;} else {cur = cur.next;}}}

09 删除所有值为key的节点

这个与08其实大差不差。

示例代码:

//删除所有值为key的节点public void removeAllKey(int key){ListNode cur = head;while (cur != null) {if (cur.val == key) {//删除头节点if (cur == head) {head = head.next;if (head != null) {//考虑只有一个节点的情况head.prev = null;}else {last = null;}} else {//删除中间节点以及尾巴节点if (cur.next != null) {//中间节点cur.prev.next = cur.next;cur.next.prev = cur.prev;} else {//尾巴节点cur.prev.next = cur.next;last = last.prev;}}//return;//区别所在cur = cur.next;} else {cur = cur.next;}}}

唯一的区别就是,在寻找出第一个关键字key之后继续往后走cur = cur.next,继续删,直到删完为止。

10 清空

使用一个循环来遍历双链表中的每个节点,并且可以选择释放每个节点所占用的内存。最后,将头节点指针设置为null,以清空链表。

public void clear(){ListNode cur = head;while(cur != null){ListNode curNext = cur.next;cur.prev = null;cur.next = null;cur = curNext;}head = null;last = null;}

11 LinkedList常规一些操作

import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;/*** @date 2023/8/16*/
public class Test {public static void main(String[] args) {List<Integer> list = new LinkedList<>();list.add(1);list.add(1);list.add(1);list.add(1);System.out.println(list);for(int x : list) {System.out.println(x);}System.out.println("=====");ListIterator<Integer> it =  list.listIterator();while (it.hasNext()) {System.out.print(it.next()+" ");}System.out.println();System.out.println("=====");ListIterator<Integer> it2 =  list.listIterator(list.size());while (it2.hasPrevious()) {System.out.print(it2.previous()+" ");}System.out.println();}
}

在这里插入图片描述

12 ArrayList与LinkedList的区别

  1. 内部实现:ArrayList是基于数组实现的动态数组,而LinkedList是基于双向链表实现的。因此,在插入或删除元素时,ArrayList需要移动数组中的元素,而LinkedList只需要改变节点的指针。
  2. 访问效率:由于ArrayList是基于数组实现的,它可以通过索引直接访问元素,因此在随机访问元素时效率较高。而LinkedList需要从头节点或尾节点开始遍历链表,因此随机访问的效率较低。
  3. 插入和删除效率:在插入或删除元素时,ArrayList需要移动元素来保持数组的连续性,因而在特定位置的插入和删除操作的效率较低。而`LinkedList``只需要改变节点的指针,因此在特定位置的插入和删除操作的效率较高。
  4. 空间占用:由于ArrayList是基于数组实现的,它需要一段连续的内存空间来存储元素,因此在使用期间其大小是固定的。而LinkedList每个节点都需要额外的空间来存储前后节点的指针,因此在空间占用方面相对较大。

综上所述,ArrayList适用于有频繁的随机访问操作和插入/删除较少的场景,而LinkedList适用于有频繁的插入/删除操作和随机访问较少的场景。根据具体的应用场景和需求,可以选择合适的集合类。


那么至此,关于链表的一些总结到此暂时完结撒花🎊🎊🎊🎊🎊🎊,接下来会学习栈和队列,MySQL,以及不定时的算法总结,其实有额外时间的话,准备详细聊聊C中的动态内存管理以及结构体之类的知识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/45436.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode 198. 打家劫舍

2023.8.19 打劫问题是经典的动态规划问题。先设一个dp数组&#xff0c;dp[i]的含义为&#xff1a;前 i 个房屋能盗取的最高金额。 每间房屋无非就是偷&#xff0c;或者不偷这两种情况&#xff0c;于是可以写出递推公式&#xff1a; …

LeetCode235. 二叉搜索树的最近公共祖先

235. 二叉搜索树的最近公共祖先 文章目录 [235. 二叉搜索树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/)一、题目二、题解方法一&#xff1a;递归方法二&#xff1a;迭代 一、题目 给定一个二叉搜索树, 找到该树中两个指定…

依赖预构建与静态资源处理

依赖预构建 vite是一个基于浏览器原生ES-Module的前端构建工具。 当你首次启动vite的时候&#xff0c;vite会在本地加载你的站点之前预构建项目依赖。 原因&#xff1a; CommonJS和UMD兼容性&#xff1a;在开发阶段中&#xff0c;Vite的开发服务器将所有的代码视为原生ES模块。…

浅谈日常使用的 Docker 底层原理-三大底座

适合的读者&#xff0c;对Docker有过简单了解的朋友&#xff0c;想要进一步了解Docker容器的朋友。 前言 回想我这两年&#xff0c;一直都是在使用 Docker&#xff0c;看过的视频、拜读过的博客&#xff0c;大都是在介绍 Docker 的由来、使用、优点和发展趋势&#xff0c;但对…

VMWare Workstation 17 Pro 网络设置 桥接模式 网络地址转换(NAT)模式 仅主机模式

文章目录 网络模式配网要求CentOSDHCP虚拟网络桥接模式默认配置测试手动配置测试 网络地址转发模式 (NAT)还原配置虚拟网络配置默认配置测试手动配置测试 仅主机模式 网络模式 桥接模式: 主机与虚拟机对等, 虚拟机注册到主机所在的局域网, 会占用该网络的IP该局域网内的所有机…

简单认识镜像底层原理详解和基于Docker file创建镜像

文章目录 一、镜像底层原理1.联合文件系统(UnionFS)2.镜像加载原理3.为什么Docker里的centos的大小才200M? 二、Dockerfile1.简介2.Dockerfile操作常用命令 三、创建Docker镜像1.基于已有镜像创建2.基于本地模板创建3.基于Dockerfile创建4.Dockerfile多阶段构建镜像 一、镜像底…

产品经理如何提高用户画像效果?SIKT模型

产品经理做用户画像&#xff0c;最担心被业务方反馈&#xff1a;没效果。这往往是由用户画像与业务场景脱节造成的。那么我们该如何从业务场景出发&#xff0c;让用户画像更有效&#xff1f;一般来说&#xff0c;我们可以采用SIKT模型解决这个问题。 用户画像 ​ 1、SIK…

【操作系统】虚拟内存相关分段分页页面置换算法

虚拟内存是什么&#xff1f; 【进程地址空间虚拟地址空间C/C程序地址空间就是那个4G的空间】 虚拟内存是操作系统内核为了对进程地址空间进行管理&#xff0c;而设计的一个逻辑意义上的内存空间概念。在程序运行过程中&#xff0c;虚拟内存中需要被访问的部分会被映射到物理内…

漏洞指北-VluFocus靶场专栏-工具篇

漏洞指北-VluFocus靶场专栏-番外篇奇技淫巧 &#x1f338;1、burp suite 、中国蚁剑工具、Strut2扫描软件地址&#x1f338;&#x1f338;2、burp suite使用&#x1f338;step1 浏览器开启代理&#xff0c;**推荐使用&#xff1a;SwitchyOmega** step2 确认浏览器端口和burp su…

nginx反向代理、负载均衡

修改nginx.conf的配置 upstream nginx_boot{# 30s内检查心跳发送两次包&#xff0c;未回复就代表该机器宕机&#xff0c;请求分发权重比为1:2server 192.168.87.143 weight100 max_fails2 fail_timeout30s; server 192.168.87.1 weight200 max_fails2 fail_timeout30s;# 这里的…

LVS负载均衡群集部署(LVS-NAT模型实例)

一、集群 1.1集群的含义 Cluster&#xff0c;集群、群集,为解决某个特定问题将多台计算机组合起来形成的单个系统。 由多台主机构成&#xff0c;但对外只表现为一个整体。 1.2群集的三种类型 1.2.1负载均衡群集 LB&#xff1a; Load Balancing&#xff0c;负载均衡&#x…

Linux 虚拟机Ubuntu22.04版本通过远程连接连接不上,输入ifconfig只能看到127.0.0.1的解决办法

之前给虚拟机配置静态IP之后&#xff0c;可以直接通过主机Vscode远程连接。但是前一段时间把主机的TCP/IPV4静态IP设置了一下之后&#xff0c;再连接虚拟机就连不上了&#xff0c;于是参考解决虚拟机不能上网ifconfig只显示127.0.0.1的问题&#xff0c;又可以连接上了&#xff…

Linux系统下消息中间件RocketMQ下载、安装、搭建、配置、控制台rocketmq-dashboard的安装保姆级教程 rocketmq ui

这里给出我使用的 RocketMQ 版本&#xff08;5.1.3&#xff09;、RocketMQ-Dashboard 版本的百度网盘链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1HaKBBDGWZ0WKLGgVwIG9pw 提取码&#xff1a;1234 文章目录 一. 官网下载安装二、启动NameServer三、启动Broker四…

Qt项目报错:Cannot run compiler ‘clang++‘. /bin/sh: 1: clang++: not found

在一台旧电脑上装了深度系统&#xff0c;装了Qt&#xff0c;导入项目&#xff0c; build提示 clang找不到&#xff1a; Project ERROR: Cannot run compiler clang. Output: /bin/sh: 1: clang: not found Maybe you forgot to setup the environment? Error while parsing …

Jenkins+Jmeter集成自动化接口测试并通过邮件发送测试报告

一、Jenkins的配置 1、新增一个自由风格的项目 2、构建->选择Excute Windows batch command&#xff08;因为我是在本地尝试的&#xff0c;因此选择的windows&#xff09; 3、输入步骤&#xff1a; 1. 由于不能拥有相同的jtl文件&#xff0c;因此在每次构建前都需要删除jtl…

VS2022远程Linux使用cmake开发c++工程配置方法

文章目录 远程连接CMakePresets.json的配置Task.vs.json配置launch.vs.json配置最近使用别人在VS2015上使用visualgdb搭建的linux开发环境,各种不顺手,一会代码不能调转了,一会行号没了,调试的时候断不到正确的位置,取消的断点仍然会进。因此重新摸索了一套使用vs的远程开…

基于Python的高校学生成绩分析系统

随着计算机技术发展&#xff0c;计算机系统的应用已延伸到社会的各个领域&#xff0c;大量基于网络的广泛应用给生活带来了十分的便利。所以把高校成绩分析与现在网络相结合&#xff0c;利用计算机搭建高校成绩分析系统&#xff0c;实现高校成绩分析的信息化。则对于进一步提高…

深入理解 Flutter 图片加载原理 | 京东云技术团队

前言 随着Flutter稳定版本逐步迭代更新&#xff0c;京东APP内部的Flutter业务也日益增多&#xff0c;Flutter开发为我们提供了高效的开发环境、优秀的跨平台适配、丰富的功能组件及动画、接近原生的交互体验&#xff0c;但随之也带来了一些OOM问题&#xff0c;通过线上监控信息…

ubuntu 编译安装nginx及安装nginx_upstream_check_module模块

如果有帮助到你&#xff0c;麻烦点个赞呗&#xff5e; 一、下载安装包 # 下载nginx_upstream_check_module模块 wget https://codeload.github.com/yaoweibin/nginx_upstream_check_module/zip/master# 解压 unzip master# 下载nginx 1.21.6 wget https://github.com/nginx/…

【C++奇遇记】构造函数 | 初始化列表

&#x1f3ac; 博客主页&#xff1a;博主链接 &#x1f3a5; 本文由 M malloc 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;LeetCode刷题集 数据库专栏 初阶数据结构 &#x1f3c5; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如…