数据结构与算法分析:(三)单向链表


  • 单向链表

  • 双向链表

  • 循环链表

  • 松散链表

下面我重点分析一下单向链表的一些主要操作。

1、单向链表

我们刚刚讲到,链表通过“指针”将一组零散的内存块串联在一起。其中,我们把内存块称为链表的“结点”。为了将所有的结点串起来,每个链表的结点除了存储数据之外,还需要记录链上的下一个结点的地址。如下图所示,我们把这个记录下个结点地址的指针叫作后继指针 next。

在这里插入图片描述

从我画的单链表图中,你应该可以发现,其中有两个结点是比较特殊的,它们分别是第一个结点和最后一个结点。我们习惯性地把第一个结点叫作头结点,把最后一个结点叫作尾结点。其中,头结点用来记录链表的基地址。有了它,我们就可以遍历得到整条链表。而尾结点特殊的地方是:指针不是指向下一个结点,而是指向一个空地址 NULL,表示这是链表上最后一个结点。

(1)、申请一个链表

public class ListNode {

public int data;

public ListNode next;

public ListNode(int data) {

this.data = data;

}

public int getData() {

return data;

}

public void setData(int data) {

this.data = data;

}

public void setNext(ListNode next) {

this.next = next;

}

public ListNode getNext() {

return this.next;

}

}

链表的主要操作

  • 遍历链表

  • 插入一个元素:插入一个元素到链表中

  • 删除一个元素:移除并返回链表中指定位置的元素

链表的辅助操作

  • 删除链表:移除链表中的所有元素(清空链表)

  • 计数:返回链表中元素的个数

  • 查找:寻找从链表表尾开始的第n个节点(node)

(2)、链表的遍历

假设表头指针指向链表中的第一个结点。遍历链表需要完成以下几个步骤:

  • 沿指针遍历

  • 遍历时显示节点的内容

  • 当next指针的值为NULL时,结束遍历

通过遍历链表来对链表元素进行计数:

/**

  • 统计链表节点的个数

  • @param head 链表头结点

  • @return

*/

public int LinkedListLength(ListNode head) {

int len = 0;

ListNode cur = head;

while (cur != null) {

len++;

cur = cur.getNext();

}

return len;

}

时间复杂度为O(n),用于扫描长度为n的链表。

空间复杂度为O(1),仅用于创建临时变量。

(3)、单向链表的插入

单向链表的插入可以分为以下3种情况

  • 在链表的头前插入一个新结点(链表的开始出)

  • 在链表的尾后插入一个新结点(链表的结尾出)

  • 在链表的中间插入一个新结点(随机位置)

a、在单向链表的开头插入结点

若需要在表头节点前插入一个新结点,只需要修改一个next指针,可通过如下两步完成:

  • 更新新节点next指针,使其指向当前结点的表头节点。

在这里插入图片描述

  • 更新表头指针的值,使其指向新结点。

在这里插入图片描述

b、在单向链表的结尾插入结点

如果需要在表尾部插入新结点,则需要修改两个next指针。

  • 新结点的next指针指向NULL

在这里插入图片描述

  • 最后一个结点的指针指向新结点

在这里插入图片描述

c、在单向链表的中间插入结点

假设给定插入新结点的位置,在这种情况下,需要修改两个next指针:

  • 如果位置3增加一个元素,则需要将指针定位于链表的位置2,。即需要从表头开始经过两个结点,然后插入新结点。假设第二个结点为位置结点,新结点的next指针指向位置结点(我们要在此处增加新结点)的下一个结点

在这里插入图片描述

  • 位置结点的next指针指向新结点

在这里插入图片描述

d、单向链表插入的代码实现

/**

  • 单向链表List节点进行插入操作

  • @param head 链表头结点

  • @param insertNode 插入结点

  • @param position 插入位置

  • @return

*/

public ListNode insertInLinkedList(ListNode head, ListNode insertNode, int position) {

// 如果链表为空,则插入的节点即为头结点

if (head == null) return insertNode;

// 获取该链表的结点数

int size = linkedListLength(head);

if (position < 1 || position > size + 1) {

System.out.println("Position of node to insert is invalid.The valid input are 1 to "

  • (size + 1));

return head;

}

// 否则,插入元素要么是在头插入,要么是在尾节点,或是中间

if (position == 1) {

insertNode.setNext(head);

return insertNode;

} else {

// 在链表的中间或尾部插入

ListNode prev = head;

int count = 1;

while (count < position - 1) {

prev = prev.getNext();

count++;

}

ListNode cur = prev.getNext();

insertNode.setNext(cur);

prev.setNext(insertNode);

}

return head;

}

时间复杂度为O(n)。在最坏情况下,可能需要在链表尾部插入结点。

空间复杂度为O(1)。仅用于创建一个临时变量。

(4)、单向链表的删除

单向链表的删除操作,也分为三种情况:

  • 删除链表的表头(第一个)结点

  • 删除链表的表尾(最后一个)节点

  • 删除链表的中间的节点

a、删除单向链表表头结点

删除链表的第一个结点,可以通过两步实现:

  • 创建一个临时结点,它指向表头指针所指的结点。

在这里插入图片描述

  • 修改表头指针的值,使其指向下一个结点,并移除临时结点。

在这里插入图片描述

b、删除单向链表的最后一个结点

这种情况下,操作比删除第一个结点要麻烦一点,因为算法需要找到表尾节点的前驱节点。这需要三步来实现:

  • 遍历链表,在遍历时还要保存前驱(前一次经过)结点的地址。当遍历到链表的表尾时,将有两个指针,分别是表尾结点的指针tail(表尾)即指向表尾结点的前驱结点的指针。

在这里插入图片描述

  • 将表尾的前驱节点的next指针更新为NULL。

在这里插入图片描述

  • 移除表尾节点。

在这里插入图片描述

c、删除单向链表中间一个结点

在这种情况下,删除的结点总是位于两个结点之间,因此不需要更新表头和表尾的指针。该删除操作通过两步实现:

  • 在遍历时保存前驱(前一次经过的)结点的地址。一旦找到被删除的结点,将前驱结点next指针的值更新为被删除结点的next指针的值。

在这里插入图片描述

  • 移除需要删除的当前结点。
    自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

image.png

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!**

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

[外链图片转存中…(img-iPtjXxZc-1713713415666)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值