重新认识链表(下)

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

内容简介:写链表代码是最考验有些语言有“指针”的概念,比如 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的节点放入新链表后即可。

重新认识链表(下)

测试结果:

重新认识链表(下)


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

查看所有标签

猜你喜欢:

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

暗时间

暗时间

刘未鹏 / 电子工业出版社 / 2011-7 / 35.00元

2003年,刘未鹏在杂志上发表了自己的第一篇文章,并开始写博客。最初的博客较短,也较琐碎,并夹杂着一些翻译的文章。后来渐渐开始有了一些自己的心得和看法。总体上在这8年里,作者平均每个月写1篇博客或更少,但从未停止。 刘未鹏说—— 写博客这件事情给我最大的体会就是,一件事情如果你能够坚持做8年,那么不管效率和频率多低,最终总能取得一些很可观的收益。而另一个体会就是,一件事情只要你坚持得足......一起来看看 《暗时间》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

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

HEX CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具