點擊查看如何實現單鏈表以及單鏈表的一些基本操作函數
點擊查看基於單鏈表經常見的面試題——基礎篇
1.判斷單鏈表是否帶環?若帶環,求環的長度?求環的入口點?
判斷是否帶環:
ListNode *IfRing(ListNode *list)//判斷單鏈表是否帶環,返回交點
{
ListNode* slow = list;
ListNode* fast = list;
//是否帶環
while (fast&&fast->next)//注意邊界問題
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)//如果相遇,則帶環
{
return fast;
}
}
return NULL;
}
求環的長度,只需要讓快慢指針再遍歷一遍環,再次相遇就可以求出長度了
int LengthRing(ListNode *list)//環的長度
{
ListNode* fast = IfRing(list);
if (fast!=NULL)
{
int count = 1;
ListNode* slow = fast;
while (fast&&fast->next)//注意邊界問題
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)//如果再相遇,則能求出長度
{
break;
}
count++;
}
return count;
}
else
{
return 0;
}
}
求環的入口點
ListNode *OepRing(ListNode *list)//環的入口點
{
ListNode *fast = IfRing(list);
if (fast != NULL)
{
ListNode *cur = list;
while (fast != cur)
{
fast = fast->next;
cur = cur->next;
}
return cur;
}
else
{
return NULL;
}
}
在這裏我也直接寫了一個一次性求出的封裝函數
void IfLengOepRing(ListNode *list)
//判斷單鏈表是否帶環?若帶環,求環的長度?
//求環的入口點?
{
assert(list);
ListNode* slow = list;
ListNode* fast = list;
//是否帶環
while (fast&&fast->next)//注意邊界問題
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)//如果相遇,則帶環,求環的長度和入口點
{
printf("此鏈表帶環\n");
//求環的長度
{
int count = 1;
while (fast&&fast->next)//注意邊界問題
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)//如果再次相遇,跳出循環,輸出循環多少次,也就是環的長度
{
printf("環的長度爲%d\n",count);
break;
}
count++;
}
}
//環的入口點
{
ListNode *cur = list;
while (fast != cur)
{
fast = fast->next;
cur = cur->next;
}
printf("入口點爲%d\n",cur->data);
}
break;
}
}
if ((fast==NULL)||(fast->next==NULL))//如果爲空了,表示不帶環
{
printf("此鏈表不帶環\n");
}
}
2.判斷兩個鏈表是否相交,若相交,求交點。(假設鏈表不帶環)
ListNode *Intersect(ListNode *list, ListNode *plist)
//判斷兩個鏈表是否相交,若相交,求交點。(假設每個鏈表不帶環)
{
//找到第一個鏈表的尾結點,
ListNode *cur = list;
ListNode *tail = list;
while (tail->next)
{
tail = tail->next;
}
//第一個鏈表的尾節點指向第二個鏈表的開始結點
tail->next = plist;
//判斷是否相交(轉換爲是否帶環問題)
ListNode*ret = IfRing(cur);
return ret;
}
3.判斷兩個鏈表是否相交,若相交,求交點。(假設鏈表可能帶環)【升級版】
ListNode *IntersectRing(ListNode *list, ListNode *plist)
//判斷兩個鏈表是否相交,若相交,求交點。
//(假設鏈表可能帶環)【升級版】
{
ListNode* oep1 = OepRing(list);
ListNode* oep2 = OepRing(plist);
//兩個鏈表都不帶環(也就是上一題的解決方案)
if ((oep1 == NULL) && (oep2 == NULL))
{
return Intersect(list, plist);
}
//一個帶環,一個不帶環(不可能相交)
else if (((oep1 == NULL) && oep2) || ((oep2 == NULL) && oep1))
{
return NULL;
}
//兩個都帶環
else
{
//尾交(一個交點,一個入口點)
//若兩個鏈表的入口點一樣則只有一個交點(交點也是入口點)
//兩鏈表各自環入口點已經求出,把list的環從入口點斷開
//可以轉換成求不帶環的相交鏈表求交點
if (oep1 == oep2)
{
oep1->next = NULL;
return Intersect(list, plist);//交點
}
else
{
//環交
//環交會有兩個入口點,從一個入口點出發遍歷環
//遍歷的過程中有結點等於另一個入口點,則表示環交,返回指向那個結點的指針(就是交點)
//有兩個交點,交點也是入口點。
//否則,就是兩個帶環鏈表不相交
//在這裏返回的是第二個鏈表的入口點
//也是第一個鏈表在第二個鏈表中的交點
ListNode* cur = oep1->next;
while (cur != oep1)
{
if (cur == oep2)
{
return oep1;
}
cur = cur->next;
}
/*//在這裏返回的是第一個鏈表的入口點
//也是第二個鏈表在第一個鏈表中的交點
ListNode* cur = oep2->next;
while (cur != oep2)
{
if (cur == oep1)
{
return oep2;
}
cur = cur->next;
}*/
return NULL; //不相交
}
}
}
4.複雜鏈表的複製。一個鏈表的每個節點,有一個指向next指針指向下一個節點,還有一個random指針指向這個鏈表中的一個隨機節點或者NULL,現在要求實現複製這個鏈表,返回複製後的新鏈表。
//ps: 複雜鏈表的結構
struct ComplexNode
{
int _data ; // 數據
struct ComplexNode * _next; // 指向下一個節點的指針
struct ComplexNode * _random; // 指向隨機節點(可以是鏈表中的任意節點 or 空)
};
複製複雜鏈表思路:
1)第一步,把新創建的每個結點鏈接到原先結點的後面
void NewBackPrime(ComplexNode *list)
//第一步,把新創建的每個結點鏈接到原先結點的後面
{
ComplexNode *cur = list;
while (cur)
{
//每次新創建一個結點,讓它指向原先結點指向的結點
//新創建結點的data和原先結點一樣
ComplexNode *head = Init(cur->_data);
head->_next = cur->_next;
//新創建結點的指向的隨機結點置空
head->_random = NULL;
//原先結點指向新創建的結點,這樣整個鏈表就連到了一塊
cur->_next = head;
//cur依次後移
cur = head->_next;
}
}
2)第二步,複製隨機結點
void ComplexNodeRandom(ComplexNode *list)
//第二步,複製隨機結點
{
ComplexNode *cur = list;
while (cur)
{
//找到插入的新結點
ComplexNode *head = cur->_next;
//讓新結點指向的隨機結點
//去指向
//原先結點指向隨機結點的後一個
if (cur->_random)
{
head->_random = cur->_random->_next;
}
cur = head->_next;
}
}
3)第三步,讓新創建鏈表的結點鏈接起來,原先鏈表的結點鏈接起來
ComplexNode *RemoveNewCode(ComplexNode *list)
//第三步,讓新創建鏈表的結點鏈接起來,原先鏈表的結點鏈接起來
{
ComplexNode *cur = list;
ComplexNode *head = NULL;
ComplexNode *tmp = NULL;
if (cur)
{
head = tmp = cur->_next;
cur->_next = tmp->_next;
cur = cur->_next;
}
while (cur)
{
//讓新創建鏈表的結點鏈接起來
tmp->_next = cur->_next;
tmp = tmp->_next;
//原先鏈表的結點鏈接起來
cur->_next = tmp->_next;
cur = cur->_next;
}
return head;
}
將這三步放到一塊就是複雜鏈表的複製;
ComplexNode *ComplexList(ComplexNode *list)
//複雜鏈表的複製
{
NewBackPrime(list);
ComplexNodeRandom(list);
return RemoveNewCode(list);
}
同樣,提供全部測試代碼:
singlelinkedlist.h頭文件
#ifndef __SINGLELINKEDLIST_H__
#include<stdio.h>
#include<windows.h>
#include<assert.h>
typedef int DataType;
typedef struct ListNode
{
DataType data;
struct ListNode *next;
}ListNode;
typedef struct ComplexNode
{
int _data; // 數據
struct ComplexNode *_next; // 指向下一個節點的指針
struct ComplexNode *_random; // 指向隨機節點(可以是鏈表中的任意節點 or 空)
}ComplexNode;
ListNode *InitList(DataType num);//初始化並賦值
void PushBack(ListNode **pplist, DataType num);//尾插
void PrintList(ListNode *plist);//輸出
void PopBack(ListNode **pplist);//尾刪
void PushFront(ListNode **pplist, DataType num);//頭插
void PopFront(ListNode **pplist);//頭刪
ListNode *Find(ListNode *plist, DataType num);//查找
void Insert(ListNode** pplist, ListNode* pos, DataType x);//插入
void Erase(ListNode** pplist, ListNode* pos);//刪除
void reverse(ListNode* pplist);//從尾到頭打印鏈表
void DelHeadlessTail(ListNode* pos);//刪除非尾結點
void InsertNotHeadNode(ListNode *pos, DataType num);//在一個節點前插入一個節點
void YueSeFu(ListNode *plist, DataType num);//約瑟夫環問題
void ReverseList(ListNode **pplist);//逆序單鏈表
void SortList(ListNode *plist);//冒泡排序
ListNode *MergeList(ListNode *list, ListNode *plist);//(尾插法)合併有序鏈表並輸出有序
ListNode *MidNode(ListNode *list);//查找單鏈表的中間節點,要求只能遍歷一次鏈表
ListNode *CountBackwards(ListNode *list, DataType num);//查找單鏈表的倒數第k個節點,要求只能遍歷一次鏈表
ListNode *Ring(ListNode *list);//給鏈表帶環
void IfLengOepRing(ListNode *list);//判斷單鏈表是否帶環?若帶環,求環的長度?求環的入口點?
ListNode *IfRing(ListNode *list);//判斷單鏈表是否帶環,返回交點
int LengthRing(ListNode *list);//環的長度
ListNode *OepRing(ListNode *list);//環的入口點
ListNode *Intersect(ListNode *list, ListNode *plist);//判斷兩個鏈表是否相交,若相交,求交點。(假設每個鏈表不帶環)
ListNode *IntersectRing(ListNode *list, ListNode *plist);//判斷兩個鏈表是否相交,若相交,求交點。(假設鏈表可能帶環)【升級版】
ComplexNode *ComplexList(ComplexNode *list);//複雜鏈表的複製
ComplexNode *Init(DataType num);//定義一個新結構體鏈表結點
void NewBackPrime(ComplexNode *list);//第一步,把新創建的每個結點鏈接到原先結點的後面
void ComplexNodeRandom(ComplexNode *list);//第二步,複製隨機結點
ComplexNode *RemoveNewCode(ComplexNode *list);//第三步,讓新創建鏈表的結點鏈接起來,原先鏈表的結點鏈接起來
void PushBackComplex(ComplexNode **pplist, DataType num);//尾插,爲了方便複製複雜鏈表使用
ComplexNode *FindComplex(ComplexNode *plist, DataType num);//查找
#endif//__SINGLELINKEDLIST_H__
singlelinkedlist.c實現部分
#include "singlelinkedlist.h"
ListNode *InitList(DataType num)//定義一個新的結點
{
ListNode *node = (ListNode*)malloc(sizeof(ListNode));
node->data = num;
node->next = NULL;
return node;
}
void PushBack(ListNode **pplist, DataType num)//尾插
{
if (*pplist == NULL)//空鏈表
{
*pplist = InitList(num);//定義一個結點
}
else if ((*pplist)->next == NULL)//只有一個結點
{
(*pplist)->next = InitList(num);
}
else//正常情況(多個結點)
{
ListNode *tail = *pplist;
while (tail->next)
{
tail = tail->next;//依次指向下一個結點,找到爲空的尾結點
}
tail->next = InitList(num);//找到以後直接添加一個結點
}
}
void PrintList(ListNode *plist)//打印鏈表
{
ListNode *tail = plist;
while (tail)
{
printf("%d->", tail->data);
tail = tail->next;
}
printf("NULL");
printf("\n");
}
void PopBack(ListNode **pplist)//尾刪
{
if (*pplist == NULL)//空鏈表
{
return;
}
else if ((*pplist)->next == NULL)//只有一個結點,直接釋放
{
free(*pplist);
*pplist = NULL;
}
else
{
ListNode* tail = *pplist;
ListNode* pos = tail;
while (tail->next)//tail指向pos的後一個結點
{
pos = tail;
tail = tail->next;
}
free(tail);//釋放最後一個結點就相當於刪除了尾結點
tail = NULL;
pos->next = NULL;
}
}
void PushFront(ListNode **pplist, DataType num)//頭插
{
if (*pplist == NULL)//空鏈表
{
*pplist = InitList(num);
}
else
{
ListNode *tmp = InitList(num);//開闢一個新的結點
tmp->next = *pplist;//讓它指向原先的開始結點
*pplist = tmp;//pplist依然開始結點
}
}
void PopFront(ListNode **pplist)//頭刪
{
if (*pplist == NULL)//空鏈表
{
return;
}
else if ((*pplist)->next == NULL)//只有一個結點
{
*pplist = NULL;
}
else
{
ListNode *tmp = (*pplist)->next;//tmp指向原先頭結點指向的下一個位置
free(*pplist);
*pplist = tmp;
}
}
ListNode *Find(ListNode *plist, DataType num)//查找
{
assert(plist);//斷言其是否爲空鏈表
while (plist)
{
if (plist->data == num)
{
return plist;
}
plist = plist->next;
}
return NULL;
}
void Insert(ListNode** pplist, ListNode* pos, DataType num)//插入
{
assert(*pplist&&pos);
if (((*pplist)->next == NULL) || (pos == *pplist))
//只有開始結點或者是要插入的正好在開始結點的前面
{
PushFront(pplist, num);
}
else
{
ListNode* tmp = NULL;
ListNode* tail = *pplist;
while (tail->next != pos)
{
tail = tail->next;
}
tmp = InitList(num);
tail->next = tmp;
tmp->next = pos;
}
}
void Erase(ListNode** pplist, ListNode* pos)//刪除
{
assert(*pplist&&pos);
if (((*pplist)->next == NULL) || (*pplist == pos))
{
PopFront(pplist);
}
else
{
ListNode* tmp = *pplist;
while (tmp->next != pos)
{
tmp = tmp->next;
}
tmp->next = pos->next;
free(pos);
pos = NULL;
}
}
void reverse(ListNode* plist)
//要實現反過來輸出鏈表,我們每訪問到一個結點的時候
//先遞歸輸出它後面的結點,再輸出該結點自身
//問題:當鏈表非常長的時候,就會導致函數調用的層級很深
//從而有可能導致函數調用棧溢出。
{
if (NULL == plist)
{
printf("NULL");
return;
}
reverse(plist->next);
printf("<-%d", plist->data);
}
void DelHeadlessTail(ListNode *pos)//刪除無頭鏈表的非尾結點
//由於鏈表的單向性,我們只能知道一個結點所指向的下一個結點
//我們可以把問題想象成是此結點與後一個結點交換
//只要把兩個結點的數據域交換,把結點指向後一個結點所指向的結點
{
assert(pos);
ListNode *ppos = pos->next;
pos->data = ppos->data;
pos->next = ppos->next;
free(ppos);
ppos = NULL;
}
void InsertNotHeadNode(ListNode *pos,DataType num)
//4.在無頭單鏈表的一個節點前插入一個節點
//實現原理
//A->pcur->B->C.....
//A->pcur->new->B->C.....
//A->new->pcur->B->C.....
{
assert(pos);
ListNode *tmp = InitList(num);
ListNode *ppos = pos; //記住原來節點的位置
tmp->next = pos->next;
pos->next = tmp;
tmp->data = pos->data;
pos->data = num;
}
void YueSeFu(ListNode *plist, DataType num)//約瑟夫環問題,報數爲num的人出局
{
assert(plist);
ListNode *cur = plist;
ListNode *tmp = plist;
if (plist->next == NULL)
{
return;
}
while (cur->next != NULL)
{
cur = cur->next;
}
cur->next = tmp;//環形鏈表
cur = plist;
while (cur->next != cur)//頭不等於尾,也就是剩下1個人就終止循環
{
DataType n = num;
while (--n)
{
tmp = cur;
cur = cur->next;
}
tmp->next = cur->next;//刪除cur也就是報數爲num的人
printf("出局的爲%d\n", cur->data);
free(cur);
cur = tmp->next;//頭往後走,也就是下一個人開始報數
}
printf("剩下的是%d\n",cur->data);
}
void ReverseList(ListNode **pplist) //逆序單鏈表
{
ListNode *cur = *pplist;//cur當前結點
ListNode *prev = NULL;//前一個結點
ListNode *pnext = NULL;//後一個結點
if (NULL == *pplist || NULL == (*pplist)->next)
return;
while (cur)
{
pnext = cur->next;
cur->next = prev;
prev = cur;
cur = pnext;
}
*pplist = prev;
}
void SortList(ListNode *plist)//冒泡排序
{
if ((plist == NULL) || (plist->next == NULL))
{
return;
}
int exchange = 0;
ListNode *tail = NULL;
while (tail != plist->next)
{
ListNode *cur = plist;
ListNode *next = plist->next;
while (next != tail)
{
if (cur->data > next->data)
{
DataType num = cur->data;
cur->data = next->data;
next->data = num;
exchange = 1;
}
cur = cur->next;
next = next->next;
}
if (exchange == 0)//冒泡優化
{
break;
}
tail = cur;
}
}
ListNode *MergeList(ListNode *list, ListNode *plist)//合併有序鏈表並輸出有序
{//歸併法(尾插法)
if (list == NULL)//如果鏈表1爲空,則直接返回鏈表2的頭指針
{
return list;
}
else if (plist == NULL)//如果鏈表2爲空,則直接返回鏈表1的頭指針
{
return list;
}
else
{
//找出新鏈表的頭結點
ListNode *head = NULL;
if (list->data < plist->data)
{
head = list;
list = list->next;
}
else
{
head = plist;
plist = plist->next;
}
//尾插
ListNode *tail = head;
while (list && plist)
{
if (list->data < plist->data)
{
tail->next = list;
list = list->next;
}
else
{
tail->next = plist;
plist = plist->next;
}
tail = tail->next;
}
if (list)//循環結束,一個鏈表爲空,頭指針直接指向非空鏈表的開始結點
{
tail->next = list;
}
else
{
tail->next = plist;
}
return head;
}
}
ListNode *MidNode(ListNode *list)//查找單鏈表的中間節點,要求只能遍歷一次鏈表
{
//鏈表個數爲偶數時,輸出中間兩個結點的後一個,也就是slow
//當面試官說把兩個中間值都輸出來,那就把Slow和slow,這裏用大寫區分
//要輸出中間值的第一個,那就更改循環條件爲fast&&fast->next->next
ListNode *slow = list;
//ListNode *Slow = list;
ListNode *fast = list;
while (fast&&fast->next)//while (fast&&fast->next->next)
//要注意邊界問題
{
//Slow = slow; //Slow比slow後一個位置
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
ListNode *CountBackwards(ListNode *list, DataType num)
//查找單鏈表的倒數第k個節點,要求只能遍歷一次鏈表
{
ListNode *slow = list;
ListNode *fast = list;
while (--num)
{
fast = fast->next;
if (fast == NULL)
{
return NULL;
}
}
while (fast->next)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
ListNode *Ring(ListNode *list)//給鏈表帶環
{
ListNode *cur = list;
ListNode *tail = list;
//找到尾結點
while (tail->next)
{
tail = tail->next;
}
//找到中間節點
ListNode*mid = MidNode(cur);
//帶環,返回頭指針
tail->next = mid;
return list;
}
void IfLengOepRing(ListNode *list)
//判斷單鏈表是否帶環?若帶環,求環的長度?
//求環的入口點?
{
assert(list);
ListNode* slow = list;
ListNode* fast = list;
//是否帶環
while (fast&&fast->next)//注意邊界問題
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)//如果相遇,則帶環,求環的長度和入口點
{
printf("此鏈表帶環\n");
//求環的長度
{
int count = 1;
while (fast&&fast->next)//注意邊界問題
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)//如果再次相遇,跳出循環,輸出循環多少次,也就是環的長度
{
printf("環的長度爲%d\n",count);
break;
}
count++;
}
}
//環的入口點
{
ListNode *cur = list;
while (fast != cur)
{
fast = fast->next;
cur = cur->next;
}
printf("入口點爲%d\n",cur->data);
}
break;
}
}
if ((fast==NULL)||(fast->next==NULL))//如果爲空了,表示不帶環
{
printf("此鏈表不帶環\n");
}
}
ListNode *IfRing(ListNode *list)//判斷單鏈表是否帶環,返回相遇的那個點
{
ListNode* slow = list;
ListNode* fast = list;
//是否帶環
while (fast&&fast->next)//注意邊界問題
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)//如果相遇,則帶環
{
return fast;
}
}
return NULL;
}
int LengthRing(ListNode *list)//環的長度
{
ListNode* fast = IfRing(list);
if (fast!=NULL)
{
int count = 1;
ListNode* slow = fast;
while (fast&&fast->next)//注意邊界問題
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)//如果再相遇,則能求出長度
{
break;
}
count++;
}
return count;
}
else
{
return 0;
}
}
ListNode *OepRing(ListNode *list)//環的入口點
{
ListNode *fast = IfRing(list);
if (fast != NULL)
{
ListNode *cur = list;
while (fast != cur)
{
fast = fast->next;
cur = cur->next;
}
return cur;
}
else
{
return NULL;
}
}
ListNode *Intersect(ListNode *list, ListNode *plist)
//判斷兩個鏈表是否相交,若相交,求交點。(假設每個鏈表不帶環)
{
//找到第一個鏈表的尾結點,
ListNode *cur = list;
ListNode *tail = list;
while (tail->next)
{
tail = tail->next;
}
//第一個鏈表的尾節點指向第二個鏈表的開始結點
tail->next = plist;
//判斷是否相交(轉換爲是否帶環問題)
return OepRing(cur);
}
ListNode *IntersectRing(ListNode *list, ListNode *plist)
//判斷兩個鏈表是否相交,若相交,求交點。
//(假設鏈表可能帶環)【升級版】
{
ListNode* oep1 = OepRing(list);
ListNode* oep2 = OepRing(plist);
//兩個鏈表都不帶環(也就是上一題的解決方案)
if ((oep1 == NULL) && (oep2 == NULL))
{
return Intersect(list, plist);
}
//一個帶環,一個不帶環(不可能相交)
else if (((oep1 == NULL) && oep2) || ((oep2 == NULL) && oep1))
{
return NULL;
}
//兩個都帶環
else
{
//尾交(一個交點,一個入口點)
//兩個鏈表的入口點一樣,只有一個交點
//兩鏈表各自環入口點已經求出,把list的環從入口點斷開
//可以轉換成求不帶環的相交鏈表求交點
if (oep1 == oep2)
{
oep1->next = NULL;
return Intersect(list, plist);//交點
}
else
{
//環交
//環交會有兩個入口點,從一個入口點出發遍歷環
//遍歷的過程中有結點等於另一個入口點,則表示環交,返回指向那個結點的指針(就是交點)
//有兩個交點,交點也是入口點。
//否則,就是兩個帶環鏈表不相交
//在這裏返回的是第二個鏈表的入口點
//也是第一個鏈表在第二個鏈表中的交點
ListNode* cur = oep1->next;
while (cur != oep1)
{
if (cur == oep2)
{
return oep1;
}
cur = cur->next;
}
/*//在這裏返回的是第一個鏈表的入口點
//也是第二個鏈表在第一個鏈表中的交點
ListNode* cur = oep2->next;
while (cur != oep2)
{
if (cur == oep1)
{
return oep2;
}
cur = cur->next;
}*/
return NULL; //不相交
}
}
}
ComplexNode *Init(DataType num)//定義一個新結構體鏈表結點
{
ComplexNode *node = (ComplexNode*)malloc(sizeof(ComplexNode));
node->_data = num;
node->_next = NULL;
node->_random = NULL;
return node;
}
void NewBackPrime(ComplexNode *list)
//第一步,把新創建的每個結點鏈接到原先結點的後面
{
ComplexNode *cur = list;
while (cur)
{
//每次新創建一個結點,讓它指向原先結點指向的結點
//新創建結點的data和原先結點一樣
ComplexNode *head = Init(cur->_data);
head->_next = cur->_next;
//新創建結點的指向的隨機結點置空
head->_random = NULL;
//原先結點指向新創建的結點,這樣整個鏈表就連到了一塊
cur->_next = head;
//cur依次後移
cur = head->_next;
}
}
void ComplexNodeRandom(ComplexNode *list)
//第二步,複製隨機結點
{
ComplexNode *cur = list;
while (cur)
{
//找到插入的新結點
ComplexNode *head = cur->_next;
//讓新結點指向的隨機結點
//去指向
//原先結點指向隨機結點的後一個
if (cur->_random)
{
head->_random = cur->_random->_next;
}
cur = head->_next;
}
}
ComplexNode *RemoveNewCode(ComplexNode *list)
//第三步,讓新創建鏈表的結點鏈接起來,原先鏈表的結點鏈接起來
{
ComplexNode *cur = list;
ComplexNode *head = NULL;
ComplexNode *tmp = NULL;
if (cur)
{
head = tmp = cur->_next;
cur->_next = tmp->_next;
cur = cur->_next;
}
while (cur)
{
//讓新創建鏈表的結點鏈接起來
tmp->_next = cur->_next;
tmp = tmp->_next;
//原先鏈表的結點鏈接起來
cur->_next = tmp->_next;
cur = cur->_next;
}
return head;
}
ComplexNode *ComplexList(ComplexNode *list)
//複雜鏈表的複製
{
NewBackPrime(list);
ComplexNodeRandom(list);
return RemoveNewCode(list);
}
void PushBackComplex(ComplexNode **pplist, DataType num)//尾插,爲了方便複製複雜鏈表使用
{
if (*pplist == NULL)//空鏈表
{
*pplist = Init(num);//定義一個結點
}
else if ((*pplist)->_next == NULL)//只有一個結點
{
(*pplist)->_next = Init(num);
}
else//正常情況(多個結點)
{
ComplexNode *tail = *pplist;
while (tail->_next)
{
tail = tail->_next;//依次指向下一個結點,找到爲空的尾結點
}
tail->_next = Init(num);//找到以後直接添加一個結點
}
}
ComplexNode *FindComplex(ComplexNode *plist, DataType num)//查找
{
assert(plist);//斷言其是否爲空鏈表
while (plist)
{
if (plist->_data == num)
{
return plist;
}
plist = plist->_next;
}
return NULL;
}
test.c測試部分
#include "singlelinkedlist.h"
void test()
{
ListNode *list = NULL;
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 3);
PushBack(&list, 4);
PrintList(list);
PopBack(&list);
PrintList(list);
PopBack(&list);
PrintList(list);
PopBack(&list);
PrintList(list);
PopBack(&list);
PrintList(list);
}
void test1()
{
ListNode *list = NULL;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 3);
PushFront(&list, 4);
PushFront(&list, 5);
PrintList(list);
PopFront(&list);
PrintList(list);
PopFront(&list);
PrintList(list);
PopFront(&list);
PrintList(list);
PopFront(&list);
PrintList(list);
PopFront(&list);
PrintList(list);
}
void test2()
{
ListNode *list = NULL;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 4);
PushFront(&list, 5);
PushFront(&list, 6);
PrintList(list);
ListNode *ret = Find(list, 2);
//測試使用
/*if (ret != NULL)
{
printf("%p\n", ret);
}
else
{
printf("沒有這個值!\n");
}*/
Insert(&list, ret, 3);
PrintList(list);
Erase(&list, ret);
PrintList(list);
}
void test3()
{
ListNode *list = NULL;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 3);
PushFront(&list, 4);
PushFront(&list, 5);
PrintList(list);
reverse(list);//從尾到頭打印鏈表
printf("\n");
}
void test4()
{
ListNode *list = NULL;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 3);
PushFront(&list, 4);
PushFront(&list, 5);
PrintList(list);
ListNode *ret = Find(list, 2);
DelHeadlessTail(ret);//刪除非尾結點
PrintList(list);
}
void test5()
{
ListNode *list = NULL;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 4);
PushFront(&list, 5);
PushFront(&list, 6);
PrintList(list);
ListNode *ret = Find(list, 2);
InsertNotHeadNode(ret, 3);//在一個節點前插入一個節點
PrintList(list);
YueSeFu(list, 2);//約瑟夫環問題
}
void test6()
{
ListNode *list = NULL;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 3);
PushFront(&list, 4);
PushFront(&list, 5);
PrintList(list);
ReverseList(&list);//單鏈表的逆置
PrintList(list);
}
void test7()
{
ListNode *list = NULL;
PushFront(&list, 3);
PushFront(&list, 2);
PushFront(&list, 5);
PushFront(&list, 4);
PushFront(&list, 8);
PrintList(list);
SortList(list);//冒泡排序
PrintList(list);
}
void test8()
{
ListNode *tmp = NULL;
PushFront(&tmp, 5);
PushFront(&tmp, 3);
PushFront(&tmp, 1);
PrintList(tmp);
ListNode *num = NULL;
PushFront(&num, 6);
PushFront(&num, 4);
PushFront(&num, 2);
PrintList(num);
//ListNode *ret = MergeList(tmp, num);//尾插法
//PrintList(ret);
}
void test9()
{
ListNode *list = NULL;
//PushFront(&list, 3);
//PushFront(&list, 2);
//PushFront(&list, 5);
//PushFront(&list, 4);
//PushFront(&list, 8);
//ListNode *ret = MidNode(list);//查找單鏈表的中間節點,要求只能遍歷一次鏈表
//printf("%d\n",ret->data);//鏈表個數如果是奇數個,輸出中間那個
PushFront(&list, 3);
PushFront(&list, 2);
PushFront(&list, 4);
PushFront(&list, 8);
ListNode *Ret = MidNode(list);//查找單鏈表的中間節點,要求只能遍歷一次鏈表
printf("%d\n", Ret->data);//鏈表個數如果是偶數個,輸出中間兩個結點的後一個
}
void test10()
{
ListNode *list = NULL;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 3);
PushFront(&list, 4);
PushFront(&list, 5);
PrintList(list);
ListNode *ret = CountBackwards(list, 2);
printf("%d\n",ret->data);
}
void test11()
{
ListNode *list = NULL;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 3);
PushFront(&list, 4);
PushFront(&list, 7);
PushFront(&list, 8);
PushFront(&list, 9);
PushFront(&list, 10);
PushFront(&list, 11);
PrintList(list);
ListNode *ret = Ring(list);//給鏈表帶環
//IfLengOepRing(ret);//判斷單鏈表是否帶環?若帶環,求環的長度?求環的入口點
/*ListNode* Ret = IfRing(ret);//判斷單鏈表是否帶環
if (Ret)
{
printf("該鏈表帶環\n");
}
else
{
printf("該鏈表不帶環\n");
}*/
//printf("環的長度爲:%d\n", LengthRing(ret));//環的長度
ListNode *Ret = OepRing(ret);//環的入口點
if (Ret)
{
printf("環的入口點爲:%d\n",Ret->data);
}
else
{
printf("該鏈表沒有環\n");
}
}
void test12()
{
ListNode *list = NULL;
PushFront(&list, 8);
PushFront(&list, 7);
PushFront(&list, 6);
PushFront(&list, 5);
PushFront(&list, 4);
PushFront(&list, 3);
PushFront(&list, 2);
PushFront(&list, 1);
PrintList(list);
ListNode *plist = NULL;
PushFront(&plist, 5);
PushFront(&plist, 4);
PushFront(&plist, 3);
PushFront(&plist, 2);
PrintList(plist);
//Find(plist, 5)->next = Find(list, 6);//讓兩個鏈表相交
ListNode *ret = Intersect(list, plist);//判斷兩個鏈表是否相交,若相交,求交點。(假設鏈表不帶環)
if (ret)
{
printf("兩個鏈表相交,交點爲:%d\n", ret->data);
}
else
{
printf("兩個鏈表不相交\n");
}
}
void test13()
{
ListNode *list = NULL;
PushFront(&list, 4);
PushFront(&list, 3);
PushFront(&list, 2);
PushFront(&list, 1);
ListNode *ret = Ring(list);//給鏈表帶環
ListNode *plist = NULL;
PushFront(&plist, 4);
PushFront(&plist, 3);
PushFront(&plist, 2);
PushFront(&plist, 1);
ListNode *Ret = Ring(plist);//給鏈表帶環
//Find(plist, 3)->next = Find(list, 3);//讓兩個鏈表尾交
//Find(plist, 4)->next = Find(list, 3);//讓兩個鏈表環交
ListNode *oep = IntersectRing(ret, Ret);//判斷兩個鏈表是否相交,若相交,求交點。(假設鏈表可能帶環)
if (oep != NULL)
{
printf("交點爲:%d\n",oep->data);
}
else
{
printf("無交點\n");
}
}
void test14()
{
ComplexNode *list = NULL;
PushBackComplex(&list, 4);
PushBackComplex(&list, 3);
PushBackComplex(&list, 2);
PushBackComplex(&list, 1);
FindComplex(list, 1)->_random = FindComplex(list, 3);
FindComplex(list, 2)->_random = FindComplex(list, 4);
FindComplex(list, 3)->_random = NULL;
FindComplex(list, 4)->_random = NULL;
ComplexNode *plist = ComplexList(list);
}
int main()
{
//test();
//test1();
//test2();
//test3();
//test4();
//test5();
//test6();
//test7();
//test8();
//test9();
//test10();
//test11();
//test12();
//test13();
test14();
system("pause");
return 0;
}