連結串列相關面試題
阿新 • • 發佈:2018-11-20
連結串列的基本操作在連結的部落格中已經有實現https://blog.csdn.net/Damn_Yang/article/details/83689944
下面我們來看看連結串列相關的面試題,非常重要
下面的題目都會一個一個實現
#include<stdio.h> typedef int DataType; typedef struct Node { DataType data; struct Node * next; }Node, *pNode, LinkList, *pLinkList; //比較順序表和連結串列的優缺點 //從尾到頭列印連結串列 void PrintLinkTailToHead(pLinkList ppl, stack* s); //刪除一個無頭單鏈表的非尾結點 void RmoveNodeNotTail(pLinkList *ppl, pNode pos); //用連結串列實現約瑟夫環 void JosephCircle(pLinkList *ppl, int k); //在無頭單鏈表的一個節點前插入一個節點(不能遍歷連結串列) void InsertNodeNotHead(pLinkList *ppl, DataType data, pNode pos); //連結串列的逆置 void Reverselist(pLinkList *ppl); //連結串列的氣泡排序 void BubbleSort(pLinkList *ppl); //合併兩個有序的連結串列,合併後依然有序 pNode Merge(pLinkList* list1, pLinkList* list2); //合併兩個有序的連結串列(遞迴版本) pNode Merge_R(pLinkList list1, pLinkList list2); //求單鏈表中間結點 pNode FindMidNode(pLinkList plist); //求單鏈表倒數第K個結點 pNode FindLastKNode(pLinkList plist, int k); //判斷連結串列是否帶環,帶環返回相遇點,不帶環返回NULL pNode IsCircle(pLinkList plist); //求環的長度 int GetCircleLength(pNode meet); //求環的入口點 pNode GetCircleEntryNode(pLinkList plist, pNode meet); //判斷連結串列是否相交(假設連結串列不帶環),相交返回1,不相交返回0 int IsCross(pLinkList plist1, pLinkList plist2); //求兩個連結串列的交點 pNode GetMeetNode(pLinkList plist1, pLinkList plist2); //求兩個連結串列中相同的資料(交集) void UnionSet(pLinkList plist1, pLinkList plist2);
1.比較順序表和連結串列的優缺點
1.順序表:
原理:順序表儲存是將資料元素放到一塊連續的記憶體儲存空間,存取效率高,速度快。但是不可以動態增加長度
優點:儲存速度高效,可以通過下標來直接儲存,建立而簡單。
缺點:1.插入和刪除比較慢,2.不可以增長長度
2.連結串列:
原理:連結串列儲存是在程式執行過程中動態的分配空間,只要儲存器還有空間,就不會發生儲存溢位問題
優點:插入刪除比較快,可以用不連續的空間
缺點:查詢速度慢,因為需要遍歷。
2.從尾到頭列印單鏈表
//2.從尾到頭列印連結串列 void PrintLinkTailToHead(pLinkList ppl) { pNode tail = NULL; while (ppl != tail) { pNode cur = ppl; while (cur->next != tail) { cur = cur->next; } printf("%d ", cur->data); tail = cur; } }
3.刪除一個無頭單鏈表的非尾結點
//3.刪除一個無頭單鏈表的非尾結點
void RmoveNodeNotTail(pLinkList *ppl, pNode pos)
{
pNode del = NULL;
pos->data = pos->next->data;//複製資料
del = pos->next;//改變要刪除的節點
pos->next = del->next;//刪除下一個節點
free(del);
del = NULL;
}
4.用連結串列實現約瑟夫環
//4.用連結串列實現約瑟夫環 void JosephCircle(pLinkList *ppl, int k) { pNode tmp = *ppl; pNode cur = *ppl; pNode del = NULL; //將單鏈表弄成一個環 while (tmp->next) { tmp = tmp->next; } tmp->next = *ppl; while (cur != cur->next) { int count = k; //走k-1步,清除一個 while (--count) { cur = cur->next; } del = cur->next; printf("刪除:%d \n", cur->data); cur->data = cur->next->data;//複製資料 cur->next = del->next;//刪除下一個節點 free(del); del = NULL; } printf("剩餘:%d\n", cur->data); }
5.在無頭單鏈表的一個節點前插入一個節點(不能遍歷連結串列)
//5.在無頭單鏈表的一個節點前插入一個節點(不能遍歷連結串列)
void InsertNodeNotHead(pLinkList *ppl, DataType data, pNode pos)
{
pNode newNode = NULL;
newNode = BuyNode(pos->data);
newNode->next = pos->next;
pos->next = newNode;
pos->data = data;
}
6.連結串列的逆置
//6.連結串列的逆置
void Reverselist(pLinkList *ppl)
{
pNode cur = *ppl;
pNode tmp = NULL;
pLinkList head = NULL;
if (*ppl == NULL || (*ppl)->next)
{
return;
}
while (cur)
{
tmp = cur->next;//儲存下一個節點,否則會丟失連結串列後面的內容
cur->next = head;
head = cur;
cur = tmp;
}
*ppl = head;
}
7.連結串列的氣泡排序
//7.連結串列的氣泡排序
void BubbleSort(pLinkList *ppl)
{
pNode cur = *ppl;
pNode tail = NULL;
while (cur != NULL)//趟數
{
while (cur->next != NULL)//比較次數
{
if (cur->data > cur->next->data)
{
DataType tmp = cur->data;
cur->next = cur->next->data;
cur->next->data = tmp;
}
cur = cur->next;
}
}
tail = cur;
cur = *ppl;
}
8.合併兩個有序的連結串列,合併後依然有序
//8.合併兩個有序的連結串列,合併後依然有序
pNode Merge(pLinkList list1, pLinkList list2)
{
pLinkList newhead = NULL;
//一個連結串列為空,一個不為空
if (list1 == NULL)
{
return list2;
}
if (list2 == NULL)
{
return list1;
}
//兩個連結串列都為空
if ((list1 == NULL) && (list2 == NULL))
{
return NULL;
}
if (list1->data < list2->data)
{
newhead = list1;
list1 = list1->next;
}
else
{
newhead = list2;
list2 = list2->next;
}
//儲存連結串列最後一個節點的位置
pNode tail = newhead;
//依次比較尾插
while ((list1 != NULL) && (list2 != NULL))
{
if (list1->data < list2->data)
{
tail->next = list1;
list1 = list1->next;
}
else
{
tail->next = list2;
list2 = list2->next;
}
tail = tail->next;
}
//將剩餘的節點插入到新連結串列中
if (list1 == NULL)
{
tail->next = list2;
}
else if (list2 == NULL)
{
tail->next = list1;
}
return newhead;
}
9.合併兩個有序的連結串列(遞迴版本)
//9.合併兩個有序的連結串列(遞迴版本)
pNode Merge_R(pLinkList list1, pLinkList list2)
{
pLinkList newhead = NULL;
if (list1 == NULL)
{
return list2;
}
if (list2 == NULL)
{
return list1;
}
if ((list1 == NULL) && (list2 == NULL))
{
return NULL;
}
if (list1->data < list2->data)
{
newhead = list1;
newhead->next = Merge_R(list1->next, list2);
}
else
{
newhead = list2;
newhead->next = Merge_R(list2->next, list1);
}
return newhead;
}
10.求單鏈表中間結點
//10.求單鏈表中間結點
pNode FindMidNode(pLinkList plist)
{
pNode first = plist;
pNode second = plist;
//連結串列沒有節點或者只有一個節點返回
if ((plist == NULL) || (plist->next == NULL))
{
return plist;
}
while ((second != NULL) && (second->next != NULL))
{
second = second->next->next;
first = first->next;
}
return first;
}
11.求單鏈表倒數第K個結點
//11.求單鏈表倒數第K個結點
pNode FindLastKNode(pLinkList plist, int k)
{
pNode slow = plist;
pNode fast = plist;
if (plist == NULL)
{
return plist;
}
//快指標走k-1步
while (--k)
{
if (fast == NULL)
{
return NULL;
}
fast = fast->next;
}
//快慢指標一起走,快的到終點,慢指標則指向倒數第k個結點
while (fast->next != NULL)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
12.判斷連結串列是否帶環,帶環返回相遇點,不帶環返回NULL
//12.判斷連結串列是否帶環,帶環返回相遇點,不帶環返回NULL
pNode IsCircle(pLinkList plist)
{
pNode slow = plist;
pNode fast = plist;
if (plist == NULL)
{
return plist;
}
while ((fast != NULL) && (fast->next != NULL))
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
return slow;
}
}
return NULL;
}
13.求環的長度
//13.求環的長度
int GetCircleLength(pNode meet)
{
pNode cur = meet->next;
int len = 1;
while (cur != meet)
{
len++;
cur = cur->next;
}
return len;
}
14.求環的入口點
//14.求環的入口點
pNode GetCircleEntryNode(pLinkList plist, pNode meet)
{
pNode cur = plist;
if (plist == NULL)
{
return NULL;
}
while (cur != meet)
{
cur = cur->next;
meet = meet->next;
}
return cur;
}
15.判斷連結串列是否相交(假設連結串列不帶環),相交返回1,不相交返回0
//15.判斷連結串列是否相交(假設連結串列不帶環),相交返回1,不相交返回0
int IsCross(pLinkList plist1, pLinkList plist2)
{
pNode cur1 = plist1;
pNode cur2 = plist2;
if ((plist1 == NULL) && (plist2 == NULL))
{
return 0;
}
while (cur1->next != NULL)
{
cur1 = cur1->next;
}
while (cur2->next != NULL)
{
cur2 = cur2->next;
}
if (cur1 == cur2)
{
return 1;
}
else
{
return 0;
}
}
16.求兩個連結串列的交點
//16.求兩個連結串列的交點
pNode GetMeetNode(pLinkList plist1, pLinkList plist2)
{
int len1 = 0;
int len2 = 0;
int gaps = 0;
pNode cur1 = plist1;
pNode cur2 = plist2;
while (cur1)//求連結串列一的長度
{
cur1 = cur1->next;
len1++;
}
while (cur2)//求連結串列二的長度
{
cur2 = cur2->next;
len2++;
}
cur1 = plist1;//長連結串列
cur2 = plist2;//短連結串列
gaps = len1 - len2;
if (len1 < len2)
{
cur1 = plist2;
cur2 = plist1;
}
//長連結串列走gaps步
while (gaps--)
{
cur1 = cur1->next;
}
//一起走
while (cur1 != cur2)
{
cur1 = cur1->next;
cur2 = cur2->next;
}
return cur1;
}
17.求兩個連結串列中相同的資料(交集)
//17.求兩個連結串列中相同的資料(交集)
void UnionSet(pLinkList plist1, pLinkList plist2)
{
if ((plist1 == NULL) || (plist2 == NULL))
{
return;
}
while ((plist1 != NULL) && (plist2 != NULL))
{
if (plist1->data < plist2->data)
{
plist1 = plist1->next;
}
else if (plist1->data > plist2->data)
{
plist2 = plist2->next;
}
else
{
printf("%d ", plist1->data);
plist1 = plist1->next;
plist2 = plist2->next;
}
}
}