【資料結構】連結串列面試題
阿新 • • 發佈:2018-12-28
1、倒序列印連結串列
(1)非遞迴方式
程式碼如下:
void ReversePrint(ListNode **pFirst) { ListNode *last = NULL; ListNode *cur = NULL; assert(*pFirst != NULL); while(last != *pFirst) { cur = *pFirst; while(cur != NULL) { if(cur->next == last) { printf("%d ",cur->data); last = cur; } cur = cur->next; } } printf("\n"); }
(2)遞迴方式
可以在遞迴的最後一層(即最後一次遞迴呼叫)時列印最後一個結點的元素,在每次函式呼叫結束返回時列印當前結點的元素。程式碼如下:
void ReversePrintR(ListNode *pFirst) { if(pFirst == NULL) { return ; } if(pFirst->next == NULL) { printf("%d ",pFirst->data); } else { ReversePrintR(pFirst->next); printf("%d ",pFirst->data); } }
2、逆置連結串列
程式碼如下:
ListNode *ReverseList(ListNode **pFirst) { ListNode *tmp = NULL; ListNode *pre = NULL; ListNode *cur = NULL; ListNode *result = NULL; assert(*pFirst != NULL); cur = *pFirst; while(cur != NULL) { tmp = cur->next; if(cur->next == NULL) { result = cur; } cur->next = pre; pre = cur; cur = tmp; } return result; }
3、刪除一個無頭連結串列的非尾結點
程式碼如下:
void RemoveNodeNotTail(ListNode *pos)
{
if(pos == NULL)
{
return ;
}
pos->data = pos->next->data;
pos->next = pos->next->next;
}
4、在無頭連結串列前插入一個結點
程式碼如下:
void InsertNoHead(ListNode *pos, int data)
{
ListNode *NewNode = NULL;
if(pos == NULL)
{
return ;
}
NewNode = CreateNode(data);
NewNode->data = pos->data;
NewNode->next = pos->next;
pos->data = data;
pos->next = NewNode;
}
5、單鏈表實現約瑟夫環
整體思路分為兩步走:
(1)先使連結串列構成一個環(最後一個結點的next等於第一個結點);
(2)如果連結串列中的剩餘結點超過一個,每次找到第k個結點,刪除它。
程式碼如下:
ListNode *JocephCircle(ListNode *pFirst, int k)
{
ListNode *result = NULL;
ListNode *pre = NULL;
ListNode *cur = NULL;
int i = 0;
assert(pFirst != NULL);
cur = pFirst;
//先使連結串列構成一個環(最後一個結點的next等於第一個結點)
while(cur->next != NULL)
{
cur = cur->next;
}
cur->next = pFirst;
//如果連結串列中剩餘結點超過一個,每次找到第k個結點,刪除它
cur = pFirst;
while(cur->next != cur)
{
for(i=0; i<k-1; i++)
{
pre = cur;
cur = cur->next;
}
//刪除元素
pre->next = cur->next;
//free(cur);
cur = pre->next;
}
result = cur;
result->next = NULL;
return result;
}
6、氣泡排序
程式碼如下:
void BubbleSort(ListNode **pFirst)
{
ListNode *cur = NULL;
ListNode *last = NULL;
ListNode *pre = NULL;
DataType tmp = 0;
DataType max = 0;
assert(*pFirst != NULL);
while(last != (*pFirst)->next)
{
cur = (*pFirst)->next;
max = (*pFirst)->data;
while(cur != last)
{
if(cur->data>max) //當前值大於最大值時,交換兩數
{
tmp = max;
max = cur->data;
cur->data = tmp;
}
pre = cur;
cur = cur->next;
}
//一次迴圈結束後,把最大值放入使迴圈結束的結點中,把該結點中的值放入連結串列開頭
tmp = pre->data;
pre->data = max;
(*pFirst)->data = tmp;
last = pre;
}
}
7、合併兩個有序連結串列
整體思路如下:
用result記錄新連結串列,兩個連結串列的當前數進行比較,哪個小,就先放入連結串列中,並且向後移動。直至兩個連結串列的最後一個結點,結束迴圈。程式碼如下:
ListNode *MergeOrderedList(ListNode *p1First, ListNode *p2First)
{
ListNode *cur1 = NULL;
ListNode *cur2 = NULL;
ListNode *result = NULL;
ListNode *tail = NULL;
ListNode *node = NULL;
assert(p1First);
assert(p2First);
cur1 = p1First;
cur2 = p2First;
while((cur1 != NULL)&&(cur2 != NULL))
{
if(cur1->data<=cur2->data)
{
node = cur1;
cur1 = cur1->next;
if(tail == NULL)
{
result = node;
}
else
{
tail->next = node;
}
node->next = NULL;
tail = node;
}
else
{
node = cur2;
cur2 = cur2->next;
if(tail == NULL)
{
result = node;
}
else
{
tail->next = node;
}
node->next = NULL;
tail = node;
}
}
if(cur1 != NULL)
{
tail->next = cur1;
}
if(cur2 != NULL)
{
tail->next = cur2;
}
return result;
}
8、查詢連結串列的中間結點(只能遍歷一次連結串列)
思路:
取兩個指標走;
一個快指標,一個慢指標;
快指標走兩步,慢指標走一步;
直至快指標走到連結串列末尾,結束迴圈;
慢指標所在位置就是連結串列的中間結點。
程式碼如下:
ListNode *FindMid(ListNode *pFirst)
{
ListNode *cur = NULL;
ListNode *mid = NULL;
int count = 0;
assert(pFirst != NULL);
cur = pFirst;
mid = pFirst;
while(cur != NULL)
{
cur = cur->next;
count++;
if((count%2)==0)
{
mid = mid->next;
count = 0;
}
//cur = cur->next;
//count++;
}
return mid;
}
9、查詢連結串列的倒數第k個結點(只能遍歷一次連結串列)
思路:
取快、慢兩個指標走;
快指標先走k步;
然後在快、慢指標一起走;
直至快指標走到連結串列末尾,結束迴圈;
慢指標所在位置即為連結串列的倒數第k個結點。
程式碼如下:
ListNode *FindK(ListNode *pFirst, int k)
{
ListNode *fast = NULL;
ListNode *slow = NULL;
assert(pFirst != NULL);
fast = pFirst;
slow = pFirst;
while(k)
{
fast = fast->next;
k--;
}
while(fast != NULL)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
10、刪除連結串列的倒數第k個結點(只能遍歷一遍連結串列,不能使用替換法刪除)
思路:
用快、慢兩個指標走;
快指標先走k+1步;
再快、慢指標一起走;
直至快指標走到連結串列末尾,結束迴圈;
找到倒數第k+1個結點,讓第k+1個結點指向第k個結點之後的結點,即刪除第k個結點。
程式碼如下:
void RemoveK(ListNode **pFirst, int k)
{
ListNode *del = NULL;
ListNode *fast = NULL;
ListNode *slow = NULL;
assert(*pFirst != NULL);
fast = *pFirst;
slow = *pFirst;
while(k+1)
{
fast = fast->next;
k--;
}
while(fast != NULL)
{
fast = fast->next;
slow = slow->next;
}
del = slow->next;
slow->next = slow->next->next;
//free(del);
}
11、求兩個已排序單鏈表中相同的資料,並用連結串列返回
思路:
兩個連結串列中的當前數進行比較,哪個小,哪個就往前走,兩個數相等時,就將其放入新連結串列中,直至迴圈結束。
程式碼如下:
ListNode *UnionSet(ListNode *list1, ListNode *list2)
{
ListNode *cur1 = NULL;
ListNode *cur2 = NULL;
ListNode *result = NULL;
ListNode *tail = NULL;
ListNode *node = NULL;
assert(list1 != NULL);
assert(list2 != NULL);
cur1 = list1;
cur2 = list2;
while((cur1 != NULL)&&(cur2 != NULL))
{
if(cur1->data<cur2->data)
{
cur1 = cur1->next;
}
else if(cur1->data>cur2->data)
{
cur2 = cur2->next;
}
else
{
node = cur1;
cur1 = cur1->next;
cur2 = cur2->next;
if(tail == NULL)
{
result = node;
}
else
{
tail->next = node;
}
node->next = NULL;
tail = node;
}
}
return result;
}
== 上述內容均為學習過程總結,如有不足之處,請指正 ==