关于单链表的一些面试题-进阶篇(C语言实现)
来源:互联网 发布:0耗材空气净化器 知乎 编辑:程序博客网 时间:2024/06/02 21:27
关于单链表的一些面试题-进阶篇(C语言实现)
1.判断单链表是否带环?若带环,求环的长度?求环的入口点?
上述问题可以分解成:
(1)判断单链表是否带环
(2)求带环单链表的环的长度
(3)求带环单链表的环的入口点
下面对上述问题分别进行求解:
* 判断单链表是否带环
易知带环单链表的特性,所以我们在这里使用快慢指针的方法来判断单链表是否带环。
若带环,则快慢指针最终会在环内相遇。
而若不带环,则快慢指针始终无法相遇。
以此为原理,我们即可实现判断单链表是否带环的函数。
示意图:
具体代码实现:
ListNode* IsCycle(ListNode* pList)//判断链表是否带环{ ListNode* slow = pList; ListNode* fast = pList; while(fast && fast->next) { slow = slow->next; fast = fast->next->next; if(slow == fast) return slow; } return NULL;}
思考:在代码实现中,我们给快指针的定义是fast->next->next,即快指针一次走两步。那么在此处,快指针为何不能一次走三步或者是走四步呢?
* 求带环单链表的环的长度
只要单链表带环,则快慢指针必定会在环内相遇。
我们可以通过IsCycle函数来求出这个相遇点,然后围绕着这个相遇点走一圈,并通过一个临时变量记录下这个次数,即可求出返回的长度
示意图:
具体代码实现:
int GetCycleLen(ListNode* pList)//求带环链表环的长度{ ListNode* meetNode = IsCycle(pList); ListNode* cur = meetNode->next; int count = 1; if(meetNode == NULL) { return 0; } else { while(meetNode != cur) { cur = cur->next; count++; } return count; }}
* 求带环单链表的环的入口点
如图所示,设头结点至入口点的长度为L,入口点至相遇点的长度为X,环长为C
易知,在快慢指针相遇时,
快指针已走过的步数为:L+N*C+X(相遇之前快指针可能已经绕环多次)
慢指针已走过的步数为:L+X
又慢指针每走一步,快指针移动两步,即快指针移动的步数是慢指针的两倍
故:2(L+X) = L + N*C+X
2L+2X = L + N*C+X
L = N*C-X
因此,从相遇点到入口点的距离 = 头结点至入口点的距离(即 绿色线区域 = L)
由以上推理出的原理,有具体代码实现如下:
ListNode* GetCycleEntry(ListNode* pList)//求带环链表的环的入口点{ ListNode* start = pList; ListNode* ret = IsCycle(pList); if(start == NULL) return NULL; else { while(start != ret) { start = start->next; ret = ret->next; } return ret; }}
2.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
链表相交(不带环)有两种情况,如下图所示:
采取gap结点计算长短链表的方法,可以很好的求出两链表是否带环,且返回交点或者空指针。
具体实现代码如下所示:
ListNode* CheckIsMeet(ListNode* pList1, ListNode* pList2)//求两链表是否相交(链表不带环){ ListNode* cur1 = pList1; ListNode* cur2 = pList2; ListNode* LongList = pList1; ListNode* ShortList = pList2; int gap = 0; int len1 = 0; int len2 = 0; while(cur1) { len1++; cur1 = cur1->next; } while(cur2) { len2++; cur2 = cur2->next; } if(len1<len2) { LongList = pList2; ShortList = pList1; } gap = abs(len1-len2); while(gap--) { LongList = LongList->next; } while(LongList) { if(LongList == ShortList) return ShortList; LongList = LongList->next; ShortList =ShortList->next; } return NULL;}
3.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
假设链表带环,则相交有以下几种情况,如图所示:
具体代码实现如下:
ListNode* CheckIsCross(ListNode* pList1, ListNode* pList2)//求两链表是否相交(链表可能带环){ ListNode* enter1 = GetCycleEntry(pList1); ListNode* enter2 = GetCycleEntry(pList2); ListNode* cur = enter1; //两链表都不带环 if(IsCycle(pList1) == NULL && IsCycle(pList2) == NULL) { CheckIsMeet(pList1,pList2); } //两链表中有一个带环,一个不带环-——即两链表不可能相交 else if(IsCycle(pList1) == NULL || IsCycle(pList2) == NULL) { return NULL; } else { //交点在环外 //去环,转化为链表不带环的相交问题 if(enter1 == enter2) { enter1->next = NULL; CheckIsMeet(pList1,pList2); } //交点在环内 //遍历环,若找到另一个入口点,则返回其中一个入口点 else { cur = enter1->next; if(cur != enter1) { if(cur == enter2) return enter2; cur = cur->next; } return NULL; } }}
4.复杂链表的复制。一个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL,现在要求实现复制这个链表,返回复制后的新链表。
- 复杂链表的复制具体思路如下:
1、在原链表的每个节点后面插入一个新结点,新结点的data与之前的结点data相同
2、将原结点的random赋给新结点的random
3、取出新结点,链成新链表
- 代码实现如下所示
ComplexNode* BuyNode(DataType x)//复杂链表的创建{ ComplexNode* ptr = (ComplexNode*)malloc(sizeof(ComplexNode)); ptr->_data = x; ptr->_next = NULL; ptr->_random = NULL; return ptr;}void PrintComplexList(ComplexNode* cList)//打印复杂链表{ ComplexNode* cur = cList; while(cur) { printf("%d->",cur->_data); cur = cur->_next; } printf("NULL\n");}ComplexNode* CopyNodeList(ComplexNode* cList)//复杂链表的复制{ ComplexNode* cur = cList; ComplexNode* tmp = NULL; ComplexNode* newList = NULL; //链表中没有元素 if(cList == NULL) return NULL; //链表中只有一个元素 else if(cList->_next == NULL) { return BuyNode(cList->_data); } //链表中有多个元素 else { //复制相同的元素到每个结点之后去 while(cur) { tmp = BuyNode(cur->_data); tmp->_next = cur->_next; cur->_next = tmp; cur = cur->_next->_next; } while(cur) { //讨论random是否为空 if(cur->_random == NULL) cur->_next->_random = NULL; else { cur->_next->_random = cur->_random->_next; } cur = cur->_next->_next; } //取出新链表 newList = cList->_next; cur = cList->_next; while(cur->_next) { cur->_next = cur->_next->_next; cur = cur->_next; } cur->_next = NULL; return newList; }}void PushComplexList(ComplexNode** ccList, DataType x)//复杂链表的尾插法{ ComplexNode* tmp = NULL; if((*ccList) == NULL) (*ccList) = BuyNode(x); else if((*ccList)->_next == NULL) (*ccList)->_next = BuyNode(x); else { tmp = *ccList; while(tmp->_next) { tmp = tmp->_next; } tmp->_next = BuyNode(x); }}
- 关于单链表的一些面试题-进阶篇(C语言实现)
- 关于单链表的一些面试题-基础篇(C语言实现)
- 关于C单链表的面试题(进阶题)
- C语言面试题进阶篇
- 关于数据结构的10个面试题(c语言实现)
- 嵌入式C语言的一些面试题
- 一些有趣的C语言面试题
- C语言实现单链表-面试题(基础篇)
- 一些c语言面试题
- 【C语言】一些面试题。
- C语言实现单链表面试题(进阶篇)
- C语言实现单链表---面试题详解
- c语言实现单链表基础面试题
- C语言实现单链表常见面试题
- 关于C单链表的面试题(基础篇)
- 单链表相关面试题(C语言实现)
- 有助于理解C语言一些函数的面试题
- 经典面试题---单链表的基本操作(C语言实现)
- TCP中的URG和PSH
- 【Java多线程】Volatile关键字详解
- Python 子字符串查询以及如何简单规避转义字符的麻烦
- F1V3.0-9 微服务功能介绍
- Java三大特性之封装、继承、多态
- 关于单链表的一些面试题-进阶篇(C语言实现)
- Stm32定时器中断触发AD采样
- Spring3-多个配置文件的整合
- 关于一下重要的资料路径
- Inventor API:用C++导出3D PDF
- Linux上传下载文件/文件夹
- 解析xml的四种方式:DOM JDOM DOM4J SAX
- 用于实时大数据处理的Lambda架构
- 利用SharePreferences保存实体对象