連結串列常見面試題-C語言實現
阿新 • • 發佈:2019-01-01
前面的部落格已經介紹過了實現連結串列的一些相關的功能,所以在這裡就不對連結串列多加解釋說明了。
對於連結串列相關面試題這裡解釋幾個有特點的題:
1.對於求查詢連結串列的中間結點,要求只能遍歷一次連結串列?
方式:使用兩個指標,一個快指標,一個慢指標,快指標走兩步慢指標走一步,這樣當快指標指向結尾空指標的時候,慢指標剛好指向中間結點。
圖示:
2.查詢連結串列倒數第K個結點要求只能遍歷一次連結串列?
方式:同樣運用快慢指標,先讓快指標走K-1次然後讓快慢指標一起走,當fast->next==NULL時,慢指標剛好指向倒數第K個結點,注意這裡的快指標還是一次走兩步。
圖示:
3判斷一個連結串列是否帶環,帶環求環的入口點?
方式:還是對快慢指標的運用,讓兩個指標一直走,如果相遇則帶環,否則不帶環。因為快慢的指標速度不一樣,如果帶環他們都上了環相當於跑圈,速度不一樣肯定會相遇,如果不帶環快指標肯定先指向NULL,也不會相遇。
圖示:
4.求環的入口點?
方式:還是使用快慢指標,不過這裡需要用到快慢指標在環上的相遇點,具體過程如下圖
圖示:
當然這個題的解法還有很多,大家可以自己思考一下其他的方法
5.判斷兩個連結串列是否相交,求交點?
方式:這裡還是對快慢指標的應用,具體過程如下圖
接下來給出所有問題的程式碼
首先給出標頭檔案List.h
接下來給出具體實現函式的檔案List.c#define _CRT_SECURE_NO_WARNINGS 1 #ifndef __LIST_H__ #define __LIST_H__ #include<stdio.h> #include<stdlib.h> #include<assert.h> typedef int Datatype; typedef struct Node { Datatype data; struct Node *next; }Node,*PLinklist; void initList(PLinklist* pplist);//初始化頭指標 void pushback(PLinklist* pplist,Datatype);//尾插法 void showlist(PLinklist pplist);//正順列印結點 void destory(PLinklist* pplist);//釋放所開闢的結點 void _showlist(PLinklist pplist);//逆序列印 void delnotetail(PLinklist pos);//刪除無頭非尾結點 PLinklist find_list(PLinklist pplist, Datatype d);//查詢連結串列 void inertfrontnode(PLinklist pos, Datatype d);//無頭結點非尾結點前插入一個元素 void josephcycle(PLinklist pplist,Datatype k);//約瑟夫環 void rever(PLinklist* pplist);//逆序連結串列 void bubble(PLinklist pplist);//排序連結串列 PLinklist Merge(PLinklist* pplist, PLinklist* pplists);//合併兩個有序連結串列和並後也為空 PLinklist findmiddle(PLinklist pplist);//查詢中間結點 void deletk(PLinklist pplist,int k);//查詢倒數第K個結點.只能遍歷一次離岸邊 PLinklist checkcircle(PLinklist pplist);//判斷一個連結串列帶不帶環,帶環返回兩個指標相遇點的地址 int getcirclelong(PLinklist meet);//如果有環求環的長度 PLinklist findenterpoint(PLinklist pplist, PLinklist meet);//如果帶環則找入口點,//meet為相遇點 PLinklist checklist(PLinklist pplist, PLinklist pplists);//判斷兩條連結串列是否相交,相交返回交點 #endif
最後給出test.c檔案主要是測試函式和main函式#define _CRT_SECURE_NO_WARNINGS 1 #include"List.h" void initList(PLinklist* pplist) { *pplist = NULL;//pplist裡面放的是指標變數head的地址,*pplist就是指標變數地址的值,在這裡賦值為空 } void pushback(PLinklist* pplist,Datatype d) { Node *p = *pplist;//P裡面存的是頭指標的地址 PLinklist cur= (PLinklist)malloc(sizeof(Node));//開闢第一個結點 if (cur == NULL) { perror("usr malloc "); exit(EXIT_FAILURE); } memset(cur, 0, sizeof(Node)); cur->data = d; cur->next = NULL; if (p== NULL) { *pplist = cur;//頭結點的地址給頭指標 } else { while (p->next != NULL) { p= p->next; } p->next = cur; } } void showlist(PLinklist pplist) { Node *cur = pplist; while (cur != NULL) { printf("%d--", cur->data); cur = cur->next; } } void destory(PLinklist* pplist) { Node *cur = *pplist;//cur裡面存的頭指標的地址 while (cur!= NULL) { Node *p = cur;//儲存第一個結點的地址 cur = cur->next;//cur儲存第二個結點的地址 free(p);// } *pplist = NULL; } void _showlist(PLinklist pplist) { if (pplist == NULL) return; else if (pplist->next == NULL) printf("%d ", pplist->data); else { _showlist(pplist->next); printf("%d ", pplist->data); } } PLinklist find_list(PLinklist pplist, Datatype d)//查詢連結串列返回地址 { Node *cur = pplist; while (cur) { if (cur->data == d) { return cur; } cur = cur->next; } return; } void delnotetail(PLinklist pos)//刪除無頭非尾結點 { Node *cur = NULL; assert(pos->next); cur = pos->next; pos->data = cur->data; pos->next = cur->next; free(cur); } void inertfrontnode(PLinklist pos, Datatype d) { assert(pos); Node *p = (PLinklist)malloc(sizeof(Node)); if (p == NULL) { perror("use malloc"); exit(EXIT_FAILURE); } p->data = pos->data; pos->data = d; p->next = NULL; p->next = pos->next; pos->next = p; } void josephcycle(PLinklist pplist, Datatype k)//約瑟夫環 { Node *cur = pplist; Node *del = NULL; int count = 0; while (1) { count = k; if (cur == cur->next)//剩一個數字退出 { break; } while (count-2>0) { cur = cur->next; --count; } printf("%d ", cur->next->data); del = cur->next; cur->next = del->next; cur = cur->next; free(del); } printf("%d\n", cur->data); } void rever(PLinklist* pplist)//逆序連結串列 { Node *cur = *pplist; Node *tem = NULL; Node *head = NULL; if ((cur == NULL) || (cur->next == NULL)) { return; } while (cur) { tem = cur->next; cur->next = head; head = cur; cur = tem; } *pplist = head; } void bubble(PLinklist pplist)//排序演算法 { int count = 1; Node *cur = pplist; Node *src = pplist; while (src->next != NULL) { count++; src = src->next; } int i = 0,j=0; for (i = 0; i < count; i++) { Node *cur = pplist; for (j = 0; j < count - 1 - i; j++) { int temp = 0; if ((cur->data)>(cur->next->data)) { temp = cur->data; cur->data = cur->next->data; cur->next->data = temp; } cur = cur->next; } } } PLinklist Merge(PLinklist* pplist, PLinklist* pplists)//連結兩個有序連結串列 { Node *cur1 = *pplist; Node *cur2 = *pplists; Node *head = NULL; Node *tail = NULL; if (cur1 == NULL&&cur2 == NULL)//兩條都為空不合並 return NULL; if (cur1 == cur2) return cur1; if (cur1 == NULL) return cur2; if (cur2 == NULL) return cur1; if (cur1->data > cur2->data) { head = cur1; cur2 = cur2->next; head->next = NULL; tail = head; } else { head = cur1; cur1 = cur1->next; } head->next = NULL; tail = head; while (cur1 != NULL&&cur2 != NULL) { if (cur1->data < cur2->data) { tail->next = cur1; cur1 = cur1->next; } else { tail->next = cur2; cur2 = cur2->next; } tail->next->next = NULL; tail = tail->next; } if (cur1 == NULL) { tail->next = cur2; } else tail->next = cur1; return head; } PLinklist findmiddle(PLinklist pplist)//查詢中間結點的元素 { Node *slow = pplist; Node *quic = pplist; while (quic != NULL&&quic->next != NULL)//這裡的順序很重要不然就會越界程式崩潰 { quic = quic->next->next; slow = slow->next; } return slow; } void deletk(PLinklist pplist, int k)//刪除倒數第K個結點 { Node *first = pplist; Node *second = pplist; while (first->next != NULL) { if (--k <= 0) { second = second->next;//指向刪除的結點 } first = first->next; } if (k <= 0) { Node *src = second->next; second->data = second->next->data; second->next = second->next->next;// free(src); /*second->next->next = NULL;*/ } } PLinklist checkcircle(PLinklist pplist)//判斷一個連結串列是否帶環 { Node *slow = pplist; Node *fast = pplist; while (fast&&fast->next) { fast = fast->next->next; slow = slow->next; if (fast == slow) { return fast; } } return NULL; } int getcirclelong(PLinklist meet)//meet為入口點 { Node *cur = meet; int count = 0; do { count++; cur=cur->next; } while (cur != meet); return count; } PLinklist findenterpoint(PLinklist pplist,PLinklist meet)//meet為相遇點點 { Node *cur = pplist; while (meet != cur) { meet = meet->next; cur = cur->next; } return meet; } PLinklist checklist(PLinklist pplist, PLinklist pplists)//判斷兩條連結串列是否相交,相交返回交點 { Node *src = pplist; Node *dest = pplists; assert(pplist&&pplist); while (src->next != NULL) { src = src->next; } while (dest ->next!= NULL) { dest = dest->next; } if (src == dest)//相交了 { Node *meet = NULL; src->next = pplists;//接成一個環 meet = checkcircle(pplist);//找環指標的相遇地點 Node *ret=findenterpoint(pplist, meet);//找環的入口點 return ret; } else { return NULL; } }
#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"
//void test2()
//{
// PLinklist head;
// initList(&head);
// int i = 0;
// for (i = 1; i < 42; i++)
// {
// pushback(&head, i);
// }
// find_list(head, 41)->next = head;
// josephcycle(head, 3);
// /*showlist(head);*/
//}
void test()
{
PLinklist head;//定義頭指標
//PLinklist heads;//定義頭指標
initList(&head);//將頭指初始化為空避免也指標的存在
//initList(&heads);//將頭指初始化為空避免也指標的存在,測試合併連結串列所定義的
pushback(&head, 1);
pushback(&head, 2);
pushback(&head, 3);
pushback(&head, 4);
pushback(&head, 5);
pushback(&head, 6);
//pushback(&heads, 7);
//pushback(&heads, 8);
//pushback(&heads, 9);
showlist(head);
printf("\n");
Node *ret = findmiddle(head);
printf("%d", ret->data);
//showlist(heads);
//printf("\n");
//find_list(heads, 9)->next = find_list(head, 5);
//Node *ptr=checklist(head, heads);
//printf("%d", ptr->data);
//Node *src=checkcircle(head);//檢查帶不帶環
//printf("%d", src->data);
//int ret=getcirclelong(src);
//printf("%d", ret);
//Node *dest=findenterpoint(head, src);//找入口點函式
//printf("%d", dest->data);
//showlist(head);
//printf("\n");
//deletk(head, 3);
//pushback(&head, 8);
//showlist(head);
//printf("\n");
//rever(&head);
//showlist(findmiddle(head)->dtaa);
//Node *x = findmiddle(head);//列印中間函式
//printf("%d",x->data );
//PLinklist pos=find_list(head, 4);
//inertfrontnode(pos, 10);
//test2();
//delnotetail(pos);
//bubble(head);
/* printf("\n");*/
//showlist(Merge(&head, &heads));
//showlist(heads);
//_showlist(head);//逆序列印
//destory(&head);
//showlist(head);
}
int main()
{
test();
system("pause");
return 0;
}
以上測試函式是我自己編寫時按自己想法測試的,比較凌亂,你可以根據自己的想法去測試!
有什麼問題歡迎留言一起交流學習!