判断一个单链表是否有环。如果有,把指向环开始的指针返回;如果没有,返回NULL。
2015-12-22 22:47
477 查看
问题分析
判断一个单链表是否有环,这个算是经典问题了,前面的几篇博客我也提到过,这里就不再详细说了,应用的思想就是快慢指针,这个问题的关键在第二句:“如果有,把指向环开始的指针返回;如果没有,返回NULL”,那么怎么实现这个需求呢?,首先我们使用快慢指针找到环时,此时快慢指针指向环上的某一个节点,然后以此节点为其实节点一次向后遍历数出环上有几个节点,假设是K个,再定义两个指针指向链表开始节点,其中一个先走K步,然后比较两个指针是否相等,依次向后走一步再比较,直到相等时的指针就是题目要求的结果,代码如下。实现代码
#include <stdio.h> struct SNode { int nData; SNode *pNext; }; /* * 如果无环返回NULL,若有环返回环上某一节点地址 */ SNode* HaveLoop(SNode* pHead) { if(NULL == pHead) return NULL; SNode *pFlast = pHead; SNode *pSlow = pHead; while (pFlast && pFlast->pNext) { pSlow = pSlow->pNext; pFlast = pFlast->pNext->pNext; // 找到环上一点 if (pSlow == pFlast) return pFlast; } return NULL; } /* * 如果无环返回NULL,若有环返回环开始节点地址 */ SNode* FindLoopStart(SNode* pHead) { SNode *pLoopNode = HaveLoop(pHead); if (NULL == pLoopNode) return NULL; int nLoopNodeCount = 1; SNode *LoopEnd = pLoopNode; // 找出环上有几个节点K while(LoopEnd->pNext != pLoopNode) { LoopEnd = LoopEnd->pNext; ++nLoopNodeCount; } SNode *pFlast = pHead; SNode *pSlow = pHead; // 快指针先走环节点个数K个 for(int nIndex = 0; nIndex < nLoopNodeCount; ++nIndex) { pFlast = pFlast->pNext; } // 当慢指针追上快指针时的位置就是环的开始节点 while(true) { if (pFlast == pSlow) return pFlast; pFlast = pFlast->pNext; pSlow = pSlow->pNext; } } #define MAX_NODE_COUNT 10 #define LOOP_NODE_INDEX 6 int _tmain(int argc, _TCHAR* argv[]) { SNode arNode[MAX_NODE_COUNT]; SNode *pHead = &arNode[0]; // 构造链表 for(int nIndex = 0; nIndex < MAX_NODE_COUNT - 1; ++nIndex) { arNode[nIndex].nData = nIndex; arNode[nIndex].pNext = &arNode[nIndex + 1]; } // 制造环路 arNode[MAX_NODE_COUNT - 1].nData = MAX_NODE_COUNT - 1; arNode[MAX_NODE_COUNT - 1].pNext = &arNode[LOOP_NODE_INDEX]; //arNode[MAX_NODE_COUNT - 1].pNext = NULL; //末尾节点为空时无环 // 找环起始点 SNode *pStartNode = FindLoopStart(pHead); if (NULL == pStartNode) { printf("The listnode have not loop!\n"); } else { printf("The listnode have loop! The node index is %d\n", pStartNode->nData); } getchar(); return 0; }
运行结果
总结
实现步骤
使用快慢指针找到环上一点以此点为起始点数出环上的节点个数K
取两个指向链表头指针中的一个先向后走K步
比较两个指针,然后都向后走一步,重复此过程
当两个指针相等时,即找到了所要的指针
抛砖引玉
这只是我实现的一种方法,最差的情况大概是遍历3遍单链表,也就是时间复杂度O(3n),也就是O(n)了,可能我的方法还有不全面的地方,欢迎大家指出其中的错误,也希望大家有更好的方法和我分享。相关文章推荐
- 关于指针的一些事情
- C#定义并实现单链表实例解析
- C#数据结构之单链表(LinkList)实例详解
- C# Pointer指针应用实例简述
- C++智能指针实例详解
- C++指向函数的指针实例解析
- 关于c语言指针的两处小tip分享
- 浅析iterator与指针的区别
- 探讨C++中数组名与指针的用法比较分析
- 详解C++中的指针、数组指针与函数指针
- C语言实现单链表逆序与逆序输出实例
- C++中字符串以及数组和指针的互相使用讲解
- C语言安全之数组长度与指针实例解析
- C++中指向对象的常指针与指向常对象的指针详解
- 指向变量的常指针与指向常变量的指针详细解析
- C#通过指针实现快速拷贝的方法
- php中将指针移动到数据集初始位置的实现代码[mysql_data_seek]
- C#通过指针读取文件的方法
- C语言指针学习经验总结浅谈
- C语言单链表常见操作汇总