【数据结构】单链表--进阶题目

来源:互联网 发布:黑马程序员官网 编辑:程序博客网 时间: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;}}}



原创粉丝点击