博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
有环单链表
阅读量:5067 次
发布时间:2019-06-12

本文共 2049 字,大约阅读时间需要 6 分钟。

      单链表中可能存在环, 那么如何判断单链表中是否有环呢?若单链表中存在环,怎么样确定环的位置?

      如果一个单链表中存在环,在遍历链表时,一旦进入环,就开始循环遍历环上的节点。如果只用一个指针来遍历单链表,我们无法判断单链表中是否存在环。用两个指针就可以完成这个任务。

      设有两个指针p1,p2。初始时p1和p2均指向链表的第一个节点。在遍历过程中,p1总是移向下一个节点(向前移动1步),同时p2总是指向下一个节点的后继节点(向前移动两步)。如果单链表中存在环,p2在遍历过程中一定会与p1指向同一个节点(这是一个相遇问题,p2的速度是p1的两倍,它们一定会在环上相遇);否则在遍历过程中p2不可能与p1相遇。

      图1中展示了一个有环单链表。环外有 n1 个节点,环上有 n2 个节点,环的入口节点是 x 。设 p2 和 p1 在 y 节点处相遇。将环上的节点从环的入口开始沿着链表编号,编号为1, 2, …, n2。 设 y 节点的编号为 n3 。则有:

2 *(n1 + k1 * n2 + n3)= n1 + k2 * n2 + n3

      其中k1,k2分别是在相遇之前p1,p2各自遍历环的次数。

      令 k = k2 - 2 * k1, k >= 1。于是,

n1 = k * n2 – n3 = (k - 1) * n2 + n2 – n3

      这就暗示了,如果令p1指向链表的第一个节点,p2指向y节点,p1和p2每次移向下一个节点遍历链表,它们会在x节点处相遇,即找到了环的入口。                                              

                                                     

图 1  有环单链表

 

      利用数组next[]来表示链表,节点从0开始编号,next[i]代表i节点的下一个节点,-1标识链表的结尾。例如数组{1, 2, 3, 4, 5, -1}表示链表 0->1->2->3->4->5->-1,这个链表中没有环。数组 {1, 2, 3, 4, 5, 6, 4} 表示链表 0->1->2->4->5->6->4,是一个有环的单链表。下面是找出链表中环的位置算法的C语言实现:

1 #include 
2 3 int find_circle(int next[], int n) { 4 int p1 = 0, p2 = 0; 5 do { 6 p1 = next[p1]; 7 if (p2 != -1 && next[p2] != -1) { 8 p2 = next[next[p2]]; 9 } else {10 return -1;11 }12 } while (p1 != p2);13 p1 = 0;14 do {15 p1 = next[p1];16 p2 = next[p2];17 } while (p1 != p2);18 return p1;19 }20 21 int main() {22 // 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 423 int next[7] = {
1, 2, 3, 4, 5, 6, 4}; 24 int node = find_circle(next, sizeof(next) / sizeof(int));25 if (node != -1) {26 printf("%d\n", node);27 } else {28 printf("no circle\n");29 }30 return 0;31 }

       这个算法可应用到另一个问题上。 问题描述如下:

       有 n 个整数, 这些整数的取值范围为 [1, n-1], 由鸽巢原理可知至少有一个整数出现了两次。 要求找到一个(只一个)重复出现的数字。

       如 {1, 3, 2, 4, 5, 4} 中的 4 和{1, 2, 3, 3, 2}中的 2, 3 均为重复出现的数字。

       我们利用find_circle解决这个问题基于这样一个观察,就是一个满足题目条件的数组可以看做多个循环单链表, 这些链表之间可能有公共节点, 我们从任何一个节点开始遍历链表都可以找到一个环。 从0节点开始遍历,环的入口就是一个重复出现的数字; 从其他节点开始遍历则不一定能够找到重复数字。(想一想,为什么?)

       如 {1, 3, 2, 4, 5, 4} 可以看做两个链表 0->1->3->4->5->4, 2->2 

       如 {1, 2, 3, 3, 2} 可以看做是 0->1->2->3->3, 4->2->3->3 

 

 

 

转载于:https://www.cnblogs.com/william-cheung/p/3757841.html

你可能感兴趣的文章
VMWARE虚拟机无法访问的三种方法分析
查看>>
enq: SQ - contention
查看>>
cer证书签名验证
查看>>
ant 安装
查看>>
新手Python第一天(接触)
查看>>
iOS中ARC内部原理
查看>>
【bzoj1029】[JSOI2007]建筑抢修
查看>>
synchronized
查看>>
你不得不了解的应用容器引擎---Docker
查看>>
easyui datagrid 弹出页面会出现两个上下滚动条处理办法!
查看>>
迭代器和生成器
查看>>
codevs 1080 线段树练习
查看>>
JS模块化库seajs体验
查看>>
Android内核sysfs中switch类使用实例
查看>>
POJ2288 Islands and Bridges(TSP:状压DP)
查看>>
[No0000195]NoSQL还是SQL?这一篇讲清楚
查看>>
IOS开发UI篇--UITableView的自定义布局==xib布局
查看>>
【深度学习】caffe 中的一些参数介绍
查看>>
Python-Web框架的本质
查看>>
Unrecognized Windows Sockets error: 0: JVM_Bind 异常解决办法
查看>>