【数据结构】单链表--进阶题目
来源:互联网 发布:黑马程序员官网 编辑:程序博客网 时间:2024/05/22 07:45
在实现单链表的基本与基础的操作后:
我们可以在单链表中考虑环与相交以及复杂单链表的问题。
1.判断单链表是否带环?若带环,求环的长度?求环的入口点?并计算每个算法的时间复杂度&空间复杂度:
首先判断是否有环,可以定义快慢指针,fast走俩步,slow走一步,如果是带环链表fast最后一定会在环内与slow相遇,无环的fast会先到头。
因为fast比slow走的快,所以进入环是fast一定在slow前面(或相遇),假设领先n步,fast每次必slow先走一步,所以每走一次俩者间距离减少为n-1步,最后俩者一定会相遇。相遇时返回相遇点。
最后我写了一个制作环的函数,用以测试以后的代码。
ListNode* IsCycle(ListNode *pList)//是否带环{if ((pList == NULL) || (pList->next == NULL))return NULL;ListNode *fast = pList->next->next;ListNode *slow = pList->next;while ((fast != slow) && fast && fast->next){fast = fast->next->next;slow = slow->next;}if (fast == slow)return fast;elsereturn NULL;}//pos在链表内void GetCycle(ListNode **ppList, ListNode *pos)//做带环链表{assert(ppList && *ppList);ListNode *tail = *ppList;while (tail->next){tail = tail->next;}tail->next = pos;}
首先为了求环的长度,我们想到只要让某个指针在环内走一圈(不停走,再次遇到自己)时,所走的步数就是环的长度。我们不知道尾巴的长度无法判断一个指针何时进入环,所以可以利用上面的快慢指针,求出快慢指针的相遇点,然后走一圈即可。因为此情况必定带环,所以不用考虑控的情况。
为求环的入口点我们对环进行推论。fast在与slow相遇时比他多走了N圈,最后得出结论L=NC-X 所以让俩个指针分别从相遇点与头节点开始走,最后一定会在入口处相遇。
//该链表带环ListNode* CycldeMeNode(ListNode *pList)//求环的相遇点{ListNode *fast = pList->next->next;ListNode *slow = pList->next;while (fast != slow){fast = fast->next->next;slow = slow->next;}return fast;}int GetCycleLen(ListNode *meetNode)//求环长度{ListNode *cur = meetNode->next;int count = 1;while (cur != meetNode){cur = cur->next;count++;}return count;}ListNode* GetCycleEntry(ListNode* pList, ListNode *meetNode)//求环入口点{ListNode* cur = pList;ListNode* ent = meetNode;while (ent != cur){ent = ent->next;cur = cur->next;}return ent;}
用以测试上面代码的主函数,注意空链表等特殊条件。
void TestList(){ListNode *list = NULL;Pushback(&list, 1);Pushback(&list, 2);Pushback(&list, 3);Pushback(&list, 4);Pushback(&list, 5);PrintList(list);ListNode *pos = Find(list, 2);GetCycle(&list, pos);ListNode *meetNode = IsCycle(list);if (meetNode)printf("***带环***\n");elseprintf("***不带***\n");printf("***meetNode: %d\n", meetNode->data);int len = GetCycleLen(meetNode);printf("***Len: %d\n", len);ListNode *ent = GetCycleEntry(list, meetNode);printf("***Enter: %d\n", ent->data);//DestoryList(&list);}int main(){TestList();return 0;}
2.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
首先分析相交情况,只有一种 >— 其余都为他的特殊情况。
1判断俩链表是否相交,同时找到俩链表的尾节点看他们是否指向同一块空间。
2找交点,算出俩链表的长度差gap,然后让长的链表指针向前走gap步,另一链表指针指向头,俩指针同时开始走,当指向同一块空间时就为交点。
3如果俩链表中,有为空即没有交点。
void GetCress(ListNode **ppList, ListNode *pos)//做相交链表{assert(ppList);if (*ppList == NULL)return;ListNode *tail = *ppList;while (tail->next){tail = tail->next;}tail->next = pos;}ListNode* CressNoc(ListNode* pList1, ListNode* pList2)//无环链表是否相交{if ((pList1 == NULL) && (pList2 == NULL))return NULL;ListNode *tail1 = pList1;ListNode *tail2 = pList2;int count1 = 1;int count2 = 1;while (tail1->next){tail1 = tail1->next;count1++;}while (tail2->next){tail2 = tail2->next;count2++;}if (tail1 != tail2)return NULL;int gap = abs(count1 - count2);ListNode *cur1 = pList1;ListNode *cur2 = pList2;if (count1 > count2){while (gap--){cur1 = cur1->next;}}else{while (gap--){cur2 = cur2->next;}}while (cur1 != cur2){cur1 = cur1->next;cur2 = cur2->next;}return cur1;}
3.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
图为可能带环所有的状况,将状况条理化分析并逐步解决。
1.俩者都无环,判断同无环函数(无环链表判断相交函数)
2.其中一个有环, 必不相交
3.俩个都有环,交点在尾部。可类似无环链表的判断,把环的入口点看作相交链表的尾部,判断同无环函数
4.俩个都有环,交点为环。定义快慢指针,分别在俩入口点走,一圈之内必相交。
5.俩个都有环,不相交。在4的条件下不相交。
ListNode* CressMc(ListNode* pList1, ListNode* pList2)//可能带环链表是否相交{if ((pList1 == NULL) && (pList2 == NULL))return NULL;ListNode* c1 = IsCycle(pList1);ListNode* c2 = IsCycle(pList2);//1.俩个都不带环if ((c1 == NULL) && (c2 == NULL)){return CressNoc(pList1, pList2);}//2.只有一个带环 必不相交else if (c1 == NULL || c2 == NULL)return NULL;//俩都带环 else{ListNode* ent1 = GetCycleEntry(pList1, c1);ListNode* ent2 = GetCycleEntry(pList1, c2);//3.俩都带环 交点在尾巴if (ent1 == ent2){ListNode *tail1 = pList1;ListNode *tail2 = pList2;int count1 = 1;int count2 = 1;while (tail1->next != ent1){tail1 = tail1->next;count1++;}while (tail2->next != ent2){tail2 = tail2->next;count2++;}int gap = abs(count1 - count2);ListNode *cur1 = pList1;ListNode *cur2 = pList2;if (count1 > count2){while (gap--){cur1 = cur1->next;}}else{while (gap--){cur2 = cur2->next;}}while (cur1 != cur2){cur1 = cur1->next;cur2 = cur2->next;}return cur1;}//4.俩个都带环 交点为环else{ListNode *fast = ent1->next->next;ListNode *slow = ent2->next;int count = GetCycleLen(pList1);while ((fast != slow) && (--count)){fast = fast->next->next;slow = slow->next;}if (fast == slow)return ent1;elsereturn NULL;}}}
- 【数据结构】单链表--进阶题目
- 数据结构题目
- 数据结构题目
- 数据结构-题目
- POJ题目分类进阶
- 数据结构-排序进阶代码
- 图论进阶题目分类
- 进阶的基本程序题目
- 经典数据结构题目
- 经典数据结构题目
- 数据结构实习题目
- 数据结构课程设计题目
- 数据结构笔试题目总汇
- 数据结构笔试题目总汇
- 微软 数据结构面试题目
- 数据结构相关经典题目
- 无敌的数据结构题目
- 关于数据结构的题目
- 排序总结
- 打劫房屋III
- 第一次就记录给java的第五次作业吧
- insmod: can't insert 'led.ko': invalid module format
- spring是什么鬼
- 【数据结构】单链表--进阶题目
- 洛谷Oj-奖学金-排序
- windows网络编程之Select模型基础知识
- python Socket之客户端和服务端握手
- java利用zxing生成二维码
- 读懂Dubbo源码必备知识点之三
- #2 定义路由
- XDOJ1156: 等待队列
- leetcode中两道关于中位数的题295和480