資料結構—連結串列經典面試題
阿新 • • 發佈:2018-12-10
連結串列面試題:
- 從尾到頭列印單鏈表
- 刪除一個無頭單鏈表的非尾節點(不能遍歷連結串列)
- 在無頭單鏈表的一個節點前插入一個節點(不能遍歷連結串列)
- 單鏈表實現約瑟夫環(JosephCircle)
- 逆置/反轉單鏈表
- 單鏈表排序(氣泡排序&快速排序)
- 合併兩個有序連結串列,合併後依然有序
- 查詢單鏈表的中間節點,要求只能遍歷一次連結串列
- 查詢單鏈表的倒數第k個節點,要求只能遍歷一次連結串列
- 刪除連結串列的倒數第K個結點
- 判斷單鏈表是否帶環?若帶環,求環的長度?求環的入口點?並計算 每個演算法的時間複雜度&空間複雜度。
- 判斷兩個連結串列是否相交,若相交,求交點。(假設連結串列不帶環)
- 判斷兩個連結串列是否相交,若相交,求交點。(假設連結串列可能帶環) 【升級版】
- 複雜連結串列的複製。一個連結串列的每個節點,有一個指向next指標指向 下一個節點,還有一個random指標指向這個連結串列中的一個隨機節點 或者NULL,現在要求實現複製這個連結串列,返回複製後的新連結串列。
- 求兩個已排序單鏈表中相同的資料。void UnionSet(Node* l1, Node* l2);
從尾到頭列印單鏈表
問題分析:
方法一:利用兩層迴圈完成 ,外迴圈用 end 指標控制邊界,從最後一個節點指向的NULL開始走,每一次迴圈向前走一步;內迴圈完成輸出任務,讓內層迴圈的指標 cur 每次從連結串列的頭指標開始不斷往後走,直到指向 end 指標指向的前一個節點,完成對該節點資料域的列印工作
void SListPrintTailToHead(SListNode* pHead) { assert(pHead); SListNode* end = NULL; while (end != pHead) { //控制邊界,每次從後往前走一步 SListNode* cur = pHead; while (cur->_next != end) { //從頭開始遍歷,讓cur指向給end的前一個節點 cur = cur->_next; } printf("%d ", cur->_data); end = cur; } printf("\n"); }
方法二:遞迴列印,實質是從第一個節點開始在棧空間中不斷向下建立函式棧幀,直到為最後一個節點建立完棧幀,然後從下往上不斷銷燬棧幀,這個過程中節點的遍歷其實是從後向前的,所以可以利用遞迴完成逆序列印
void SListPrintTailToHeadR(SListNode* pHead)
{
if (pHead == NULL)
return;
SListPrintTailToHeadR(pHead->_next);
printf("%d ",pHead->_data);
}
刪除一個無頭單鏈表的非尾節點(不能遍歷連結串列)
問題分析:題目中說的無頭連結串列不是連結串列沒頭的意思,只是命題者沒給你頭指標而已。這個題目中直接刪除 pos 指向的節點是無法實現的,需要做適當處理
void SListDelNonTailNode(SListNode* pos)
{
assert(pos && pos->_next != NULL); //pos不應該指向最後一個節點
SListNode* next = pos->_next; //pos指向的節點的下一個節點
DataType tmp = pos->_data; //進行資料交換
pos->_data = next->_data;
next->_data = tmp;
pos->_next = next->_next; //將pos指向的節點和next指向的節點的下一個節點連線起來
delete next;
next = NULL;
}
在無頭單鏈表的一個節點前插入一個節點(不能遍歷連結串列)
問題分析:同樣題目中說的無頭連結串列不是連結串列沒頭的意思,只是命題者沒給你頭指標而已。很明顯在 pos 指向的節點前直接插入是無法實現的,需要做適當處理
void SListInsertFrontNode(SListNode* pos, DataType x)
{
assert(pos);
SListNode* newnode = BuySListNode(pos->_data); //給的資料是pos指標指向節點的
newnode->_next = pos->_next; //將新節點連到Pos指向的節點之後
pos->_next = newnode;
pos->_data = x; //將pos指標指向的節點的資料改為新節點的初值
}
單鏈表實現約瑟夫環(JosephCircle)