重新认识链表(下)

栏目: 数据库 · 发布时间: 6年前

内容简介:写链表代码是最考验有些语言有“指针”的概念,比如 C 语言;有些语言没有指针,取而代之的是“引用”,比如 Java、Python。不管是“指针”还是“引用”,实际上,它们的意思都是一样的,都是存储所指对象的内存地址。将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指针,或者反过来说,指针中存储了这个变量的内存地址,指向了这个变量,通过指针就能找到这个变量。

写链表代码是最考验 逻辑思维能力 的,指针来回指,指着指着就指迷糊,在写代码之前先注意这么几个问题。

问题1:什么是指针?

定义:

有些语言有“指针”的概念,比如 C 语言;有些语言没有指针,取而代之的是“引用”,比如 Java 、Python。不管是“指针”还是“引用”,实际上,它们的意思都是一样的,都是存储所指对象的内存地址。

将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指针,或者反过来说,指针中存储了这个变量的内存地址,指向了这个变量,通过指针就能找到这个变量。

举例:

最常见的指针代码应该是这个了, p->next=q 。它的意思是说p 结点中的 next 指针存储了 q 结点的内存地址。

问题2:什么是指针丢失和内存泄漏?

在插入结点时,一定要注意操作的顺序。

因为操作不当的时候,很容易造成指针丢失。比如a ->b之间插入一个c,同时不注意的时候很容易这么写

//声明一个p;

p->next = c; // 将 p 的 next 指针指向 c 结点; 

c->next = p->next; // 将 c 的结点的 next 指针指向 b 结点;

这就很容易让链表断成两半,造成指针丢失。正确的写法是将二三两行代码顺序换过来即可。

删除链表结点时,也一定要记得手动释放内存空间。

和插入一样,如果不及时释放内存空间,积少成多,很容易造成内存泄漏。

技巧:利用哨兵节点简化实现难度

哨兵节点主要是处理边界问题的,并不直接参与业务逻辑,当引入哨兵节点的时候,不管链表是不是空,head 指针都会一直指向这个哨兵结点。我们也把这种有哨兵结点的链表叫 带头链表 。相反,没有哨兵结点的链表就叫作 不带头链表

练习:

以单链表为例,所有源码均已上传至github: github.com/chaoaiqi/st…

声明一个单链表类

重新认识链表(下)

1.实现单链表、循环链表、双向链表,支持增删操作

顺序插入

重新认识链表(下)

删除,难点就一行q.next = q.next.next;

重新认识链表(下)

查询,分两个,一个是根据下标查询,一个是根据value查询

重新认识链表(下) 重新认识链表(下)

测试结果:

重新认识链表(下)

2.单链表反转

该实现的思想是: 从前往后反转各个结点的指针域的指向

将当前节点cur的next节点 缓存到nextNode,然后更改当前节点指针指向上一结点prevNode。也就是说在反转当前结点指针指向前,先把当前结点的指针域用nextNode临时保存,以便下一次使用

重新认识链表(下) .

测试结果:

重新认识链表(下)

3.链表中环的检测

该检测的核心思想是: 快慢指针法 。在这里,满指针每走一步,快指针走两步,可以用 数学归纳法 来考虑,首先,如果链表是个环,所以相遇的过程可以看作是快指针从后边追赶慢指针的过程。那么

1:快指针与慢指针之间差一步。此时继续往后走,慢指针前进一步,快指针前进两步,两者相遇。

2:快指针与慢指针之间差两步。此时继续往后走,慢指针前进一步,快指针前进两步,两者之间相差一步,转化为第一种情况。

...

N:快指针与慢指针之间差N步。此时继续往后走,慢指针前进一步,快指针前进两步,两者之间相差(N+1-2)-> N-1步。

代码如下:

重新认识链表(下)

测试结果:

重新认识链表(下)

4.求链表的中间结点

该实现也是用到了 快慢指针法

代码如下:

重新认识链表(下)

测试结果如下:

重新认识链表(下)

5.删除链表倒数第 n 个结点

该实现依旧用到了快慢指针法,不过和之前的有一点区别。以node长度为n,删倒数第k(k<n)个为例。首先,第一个while先计算如果正着删,需要让慢指针走几步,计算为n-k。第二个while循环则通过遍历快指针计算定位需要走n-k步,得到preNode。然后判断是否为空,不为空则常规方法删除。

测试结果

重新认识链表(下)

还有种思路是通过递归来进行删除,本次不做阐述。

6.两个有序的链表合并

该实现的思路是,首先比较两个有序链表,如果pNode为空,直接返回qNode,反之qNode为空,则返回pNode,然后比较p和q,将最小的节点赋值给resNode,同时将最小的节点向后移动一位。设置一个node指向resNode节点,用于方便连接其它节点,在继续比较p和q,同样选出小的那个节点,将该节点设为合并后的链表的第二个节点,用node.next表示该节点,一直重复上述过程,直到p和q有一个为null,然后再将不为null的节点放入新链表后即可。

重新认识链表(下)

测试结果:

重新认识链表(下)


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Parsing Techniques

Parsing Techniques

Dick Grune、Ceriel J.H. Jacobs / Springer / 2010-2-12 / USD 109.00

This second edition of Grune and Jacobs' brilliant work presents new developments and discoveries that have been made in the field. Parsing, also referred to as syntax analysis, has been and continues......一起来看看 《Parsing Techniques》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具