单链表的建立、插入等替他操作见本人博客:
单链表的基本操作
【面试题】单链表的操作1
介绍了4种有关单链表的面试题,对于以下链表要求的实现,解题的思路很重要。例如两个有序链表的合并,实现约瑟夫环及链表成环问题。
各函数的实现,代码如下:
SListNode* MergeList(SListNode* L1, SListNode* L2)//合并两个有序链表,合并后依然有序{//认为不带头结点的单链表,注意应判断两个链表是否为空 if (L1 == NULL) return L2; if (L2 == NULL) return L1; //if (L1 || L2) // return L1 = NULL ? L2 : L1; SListNode* NewHead = NULL; SListNode* pHead1 = L1; SListNode* pHead2 = L2; //进行一次比较,找出较小的值,使NewHead指向新链表的头结点 if (pHead1->data < pHead2->data) { NewHead = pHead1; pHead1 = pHead1->next; } else { NewHead = pHead2; pHead2 = pHead2->next; } //用tail指针进行比较和移动 SListNode* tail = NewHead; while (pHead1 && pHead2) { if (pHead1->data < pHead2->data) { tail->next = pHead1; pHead1 = pHead1->next; } else { tail->next = pHead2; pHead2 = pHead2->next; } tail = tail->next; } //如果两个链表不一样长时,将其链接在新链表的后面 if (pHead1) tail->next = pHead1; else tail->next = pHead2; return NewHead;}void BubbleSort(SListNode* pHead)//冒泡排序单链表{ if (pHead == NULL || pHead->next == NULL) return; int exchange = 0;//标志位判断排序是否已达到有序 SListNode* tail = pHead->next;//比较n-1趟 while (tail) {//两个指针cur,next进行比较和移动 SListNode* cur = pHead; SListNode* next = pHead->next; while (next) { if (cur->data > next->data) { exchange = 1; DataType tmp = cur->data; cur->data = next->data; next->data = tmp; } cur = cur->next; next = next->next; } if (exchange == 0)//如果没有发生交换,则链表已有序 break; tail = tail->next; }}SListNode* JosephCycle(SListNode* pHead, int k)//单链表实现约瑟夫环{//判断链表及k是否有效 if (pHead == NULL || k <= 0) return NULL; SListNode* cur = pHead; while (1) { if (cur->next == cur) return cur; int count = k; while (--count) cur = cur->next; //替换法删除结点 SListNode* next = cur->next; cur->data = next->data; cur->next = next->next; free(next); } return NULL;}//判断单链表是否带环?若带环,求环长度,求环入口点SListNode* CheckCycle(SListNode* pHead)//检查是否带环{//利用快慢指针,慢指针走一步,快指针走两步;如果存在环,两个指针一定会相遇。 if (pHead == NULL || pHead->next == NULL) return NULL; SListNode* slow = pHead; SListNode* fast = pHead; while (fast && fast->next)//条件为fast和fast->next都不为空 { slow = slow->next; fast = fast->next->next; if (fast == slow) return slow;//如何带环返回相遇的结点 } return NULL;}int GetCycleLength(SListNode* MeetNode)//求环的长度{//检查是否带环,即存在相遇点,走一圈就可以求出环的长度 assert(MeetNode); SListNode* cur = MeetNode; int count = 0; do { count++; cur = cur->next; } while (cur != MeetNode); return count;}SListNode* GetEntryNode1(SListNode* pHead)//求环的入口地址{//检查是否有环,通过快慢指针分别从头结点和相遇结点处开始走,相遇点即为入口结点 if (pHead == NULL || pHead->next == NULL) return NULL; SListNode* meetnode = CheckCycle(pHead); SListNode* slow = pHead; SListNode* fast = meetnode; while(slow && fast) { if (slow == fast) return fast; slow = slow->next; fast = fast->next; } return NULL;}int SListLength(SListNode* pHead)//分别求环形链表被拆成两条链表的链表长度{ if (pHead == NULL) return 0; int count = 0; SListNode* cur = pHead; while (cur) { cur = cur->next; count++; } return count;}SListNode* GetEntryNode2(SListNode* pHead)//求环的入口地址---两个链表相交思想{//检查是否有环,在聚点处截断,求出两个链表相交点即为入口地址 if (pHead == NULL || pHead->next == NULL) return NULL; SListNode* cur1 = pHead; SListNode* cur2 = CheckCycle(pHead)->next; CheckCycle(pHead)->next = NULL;//此法造成数据丢失 int len1 = SListLength(cur1); int len2 = SListLength(cur2); PrintSList(cur1); printf("\n---------------------\n"); PrintSList(cur2); int errand;//两个链表的长度差 //长链表先走errand步 if (len1 > len2) { errand = len1 - len2; while (errand--) cur1 = cur1->next; } else { errand = len2 - len1; while (errand--) cur2 = cur2->next; } //两个链表同步前进 while (cur1 != cur2) { cur1 = cur1->next; cur2 = cur2->next; } return cur2;}
各函数测试用例如下:
void Test10(){//【面试题七】合并两个有序链表,合并后依然有序 SListNode* phead1 = NULL; SListNode* phead2 = NULL; PushBack_Cpp(phead1, 1); PushBack_Cpp(phead1, 3); PushBack_Cpp(phead1, 6); PushBack_Cpp(phead2, 2); PushBack_Cpp(phead2, 4); PushBack_Cpp(phead2, 5); PushBack_Cpp(phead2, 7); SListNode* phead = MergeList(phead1,phead2); PrintSList(phead); printf("\n---------------------\n");}void Test11(){//【面试题八】冒泡排序单链表 SListNode *phead = NULL; PushBack_Cpp(phead, 4); PushBack_Cpp(phead, 5); PushBack_Cpp(phead, 3); PushBack_Cpp(phead, 2); PushBack_Cpp(phead, 6); PushBack_Cpp(phead, 1); PrintSList(phead); printf("\n---------------------\n"); BubbleSort(phead); PrintSList(phead);}void Test12(){//【面试题九】单链表实现约瑟夫环 SListNode *phead = NULL; PushBack_Cpp(phead, 1); PushBack_Cpp(phead, 2); PushBack_Cpp(phead, 3); PushBack_Cpp(phead, 4); PushBack_Cpp(phead, 5); PushBack_Cpp(phead, 6); PrintSList(phead); printf("\n---------------------\n"); Find(phead, 6)->next = Find(phead, 1);//将链表构成一个环,尾接头 SListNode* FindNode = JosephCycle(phead,3); printf("%d\n",FindNode->data);}void Test13(){//【面试题十】判断单链表是否带环?若带环,求环长度,求环入口点 SListNode *phead = NULL; PushBack_Cpp(phead, 1); PushBack_Cpp(phead, 2); PushBack_Cpp(phead, 3); PushBack_Cpp(phead, 4); PushBack_Cpp(phead, 5); PushBack_Cpp(phead, 6); PushBack_Cpp(phead, 7); PrintSList(phead); printf("\n---------------------\n"); Find(phead, 6)->next = Find(phead, 3); SListNode* meetnode = CheckCycle(phead);//检查是否带环 printf("%d\n", meetnode->data); if (meetnode==NULL) printf("该单链表不带环!\n"); else { printf("该单链表带环!\n"); int len = GetCycleLength(meetnode);//求环的长度 printf("length = %d\n", len); SListNode* entry1 = GetEntryNode1(phead);//求环的入口地址 printf("入口处为:%d\n", entry1->data); printf("\n---------------------\n"); SListNode* entry2 = GetEntryNode2(phead);//求环的入口地址 printf("\n入口处为:%d\n", entry2->data); } }int main(){ Test7(); printf("\n***********************\n"); Test8(); printf("\n***********************\n"); Test9(); printf("\n***********************\n"); Test10(); printf("\n***********************\n"); Test11(); printf("\n***********************\n"); Test12(); printf("\n***********************\n"); Test13(); system("pause");}