本系列的第一節概括性地簡單介紹了一下資料結構和演算法的概念,說實話有點虛,因為誰都知道鍊錶和陣列是什麼,也都能說出雜湊和二叉樹,但真正有難度的是,在實際開發中如何去用這些資料結構,根據不同的開發需求選擇不同的資料結構和演算法,才是真正需要並且很難掌握的。
以後的章節中,我都會通過一道實際程式設計題目或者乙個場景,針對一種資料結構或者演算法來解決問題,只有將資料結構和演算法用來解決實際問題,才有意義,這一節我們要解決的題目是,合併兩個有序鍊錶。
題目要求:現在有兩個鍊錶a和鍊錶b,a中元素是公升序排列的,b中元素是降序排列的,現在要求將a和b合併為乙個公升序排列的鍊錶。
題目的意思很明確,相信大家一眼都能看明白,不過先別著急寫**,先分析分析題目的要求,首先是用到的資料結構自然是鍊錶了,由於給定的鍊錶已經是有序的了,因此不需要排序,不過我們注意到,兩個鍊錶,乙個是公升序,乙個是降序,這個需要額外注意,最後關於兩個鍊錶的合併,涉及到鍊錶的拆分,也是個難點。綜上所述,這道題的關鍵點有:
1、資料結構要用鍊錶,並且是已經排序的鍊錶
2、合併兩個鍊錶,需要注意指標的指向
話不多說,直接擼**,作為程式設計師,最好的**就是**,先簡單定義單向鍊錶的結構體:
typedef
struct listnode
listnode;
這就是個最最簡單的單鏈表了,裡面儲存的資料是32位無符號整型資料,現在我們要考慮一下如何合併兩個鍊錶,假如說兩個鍊錶都是公升序排列,那麼合併的方法就比較容易了,我們可以逐個比較兩個鍊錶的元素,根據大小然後較小的元素進入到新的鍊錶中,並且指向它的下乙個,這一段的**如下:
/* 合併兩個鍊錶為乙個鍊錶 */
listnode* mergelist(listnode* listheadnodeone, listnode* listheadnodetwo)
else
if (null
== listheadnodetwo)
listnode* listresultnode =
null;
if (listheadnodeone->nodevalue < listheadnodetwo->nodevalue)
else
return listresultnode;
}
**的思路很明確,入參就是兩個鍊錶中需要比較的結點,如果說傳入的某乙個結點為空,則直接返回另乙個入參結點即可,如果說傳入的結點均不為空,則比較兩個結點所帶的資料的大小,將較小的結點返回,同時要注意到,**中用到了遞迴,這點比較好理解,因為對於我們需要合併的某乙個結點來說,完成一次合併後,其下乙個結點,自然也能用相同的方法來找到,這樣就找到了遞迴開始的條件,作為乙個遞迴演算法,還需要找到遞迴結束的條件,**一開始的判斷,如果說有乙個入參為空,這說明已經到鍊錶末尾,如果說兩個入參均為空,這說明已經遍歷完兩個鍊錶,整個遞迴結束,合併完成。
合併的演算法寫完了,但大家別忘記,題目中給的鍊錶,乙個是公升序排列,乙個是降序排列,而我們的合併演算法,前提是兩個鍊錶均為公升序排列才行,因此我們還需要寫乙個將乙個降序的鍊錶反轉,這部分的**如下:
/*反轉鍊錶的全部元素*/
listnode* invertlist(listnode *listheadnode)
listoldnode->nextnode = listtempnode;
listtempnode = listoldnode;
listoldnode = listtempnode2;
}return listnewnode;
}
這段**實際上不難理解,只需要做到,記住將需要反轉的結點的下乙個結點暫存起來,然後將需要反轉的結點與它指向的下乙個結點交換指標位置,交換完畢以後,再將指標指向暫存的結點即可,這樣相當於是改變了鍊錶指標的指向,同時要注意到,返回值是原先鍊錶的鍊錶尾,可以通過判斷下一結點是否為空,如果為空這說明到達鍊錶末尾,此時就可以將結果返回,鍊錶已經被反轉成功。
經過上面鍊錶的合併與反轉,題目已經做完了,回顧一下這道題,不是很難,但是考察了對鍊錶指標的掌握,如果說對於鍊錶掌握不夠熟練,在實際程式設計中很容易出現訪問空指標這樣的異常情況,因此建議大家在寫**時,要充分考慮**的魯棒性和健壯性,寫完**後盡可能再寫一些測試用例去測一下自己的**是否能夠正常執行,順便附上我這個程式的執行畫面:
before merge list1 is :
node 0, nodevalue is 0
node 1, nodevalue is 1
node 2, nodevalue is 2
node 3, nodevalue is 3
node 4, nodevalue is 4
before merge list2 is :
node 0, nodevalue is 9
node 1, nodevalue is 8
node 2, nodevalue is 7
node 3, nodevalue is 6
node 4, nodevalue is 5
after merge list is :
node 0, nodevalue is 0
node 1, nodevalue is 1
node 2, nodevalue is 2
node 3, nodevalue is 3
node 4, nodevalue is 4
node 5, nodevalue is 5
node 6, nodevalue is 6
node 7, nodevalue is 7
node 8, nodevalue is 8
node 9, nodevalue is 9
process returned 0 (0x0) execution time : 0.283 s
press any key to continue.
資料結構 合併兩個有序鍊錶,合併後依然有序
解題思路 假設有兩個有序單鏈表list1 list2 首先建立新的空鍊錶,用於存放結果 如果兩個有序單鏈表均為空,結果鍊錶為空 如果有乙個有序單鏈表為空,則結果鍊錶為另乙個鍊錶 如果兩個有序單鏈表均不為空,則根據以下方法進行合併 合併結束的條件 兩個鍊錶有乙個為空 合併兩個有序鍊錶,合併後依然有序 ...
演算法 合併兩個有序鍊錶
有兩種方法,迭代和遞迴。迭代 不帶頭結點 node merge node head1 node head2 else 當前排序好的鍊錶的末尾節點 node pcurrent head while p1 null p2 null else 還有一方沒有遍歷完的情況 if p1 null pcurren...
演算法 合併兩個有序鍊錶
1.迭代,新建乙個哨兵節點,通過它的next指標指向串聯起兩個鍊錶 比較 l1 和 l2哪乙個比較小,讓哨兵節點的next指向比較小的節點 哨兵節點 l1 l2依次後推,直到又乙個鍊錶為空 如果 l1 為空,則哨兵節點指向l2 注意返回值為哨兵節點的next,因為哨兵節點的第乙個值是隨意給的 cla...