有序連結串列的操作
阿新 • • 發佈:2018-12-12
有序連結串列的合併
要想合併後依舊有序,其實質是比較連結串列的值,按大小排序。
假設現給定兩個有序連結串列分別如下:
List1 = (1, 3, 4, 5), List2 = (1, 2, 5, 7, 8, 9),則合併後的有序連結串列List3 = (1, 1, 2, 3, 4, 5, 5, 7, 8, 9)
從上述分析可知,首先對於List1和List2是有序的,我們只需用兩個指標cur1和cur2分別指向List1和List2,然後依次向後比遍歷並進行資料的比較。
由於List1的連結串列長度比List2的連結串列長度要小,則當List1為空的時候,List2剩餘的元素的值一定是大於List1的最後一個值,此時只需要將List2的剩餘資料插入到result後面即可。
非遞迴方法實現:
List *MergeList(List *pList1, List *pList2) { List *cur1 = pList1; //指向連結串列1 List *cur2 = pList2; //指向連結串列2 List *result = NULL; //儲存合併後的連結串列 List *tail = NULL; List *node; List *last; while(cur1 != NULL && cur2 != NULL) { //比較連結串列1和連結串列2的值的大小 if(cur1->data > cur2->data) { node = cur2; }else { node = cur1; } last = node->next; //將值存入result if(result != NULL) { tail->next = node; }else { result = node; } node->next = NULL; tail = node; if(node == cur1) { cur1 = last; }else { cur2 = last; } } //如果連結串列1為空,就將連結串列2的剩餘內容加到result後面,反之亦然 if(cur1 == NULL) { tail->next = cur2; } if(cur2 == NULL) { tail->next = cur1; } return result; }
遞迴方法實現:
List *MergeList(List *pList1, List *pList2) { List *result = NULL; if(pList1 == NULL) { return pList2; } if(pList2 == NULL) { return pList1; } if(pList1->data > pList2->data) { result = pList2; result->next = MergeList(pList1, pList2->next); }else { result = pList1; result->next = MergeList(pList1->next, pList2); } return result; }
如何得到兩個有序連結串列的相同資料呢?此題思路與合併有序連結串列的思路一致,即通過指標遍歷,比較資料的大小即可。程式碼實現如下:
void SameData(List *pList1, List *pList2)
{
List *cur1 = pList1;
List *cur2 = pList2;
while(cur1 != NULL && cur2 != NULL)
{
if(cur1->data > cur2->data)
{
cur2 = cur2->next;
}else if(cur1->data < cur2->data)
{
cur1 = cur1->next;
}else
{
printf("%d", cur1->data);
cur1 = cur1->next;
cur2 = cur2->next;
}
}
}
對於有序連結串列的合併問題,本程式碼實現的是不帶頭結點的有序單鏈表。對於帶有頭結點的兩個有序單鏈表的合併,思路大體一致,其中值得注意的一點就是頭結點的釋放。由於兩個單鏈表都具有頭結點,當合並完成後,只需保留一個頭結點,即釋放掉另一個頭結點。舉例:
觀察下圖:經過第一次比較之後,我們發現 0 < 1, 此時需要將List1的第一個結點儲存到result中,由於頭結點的next域中存放的是連結串列的第一個結點的起始地址,此時只需要將List1的頭結點作為result的頭結點即可。當連結串列合併完成之後,此時連結串列2除頭結點之外,已經全部存入新連結串列,則需要釋放List2的頭結點即可。