排序演算法應該是最基礎的了,快速、歸併、選擇、堆排序等等
對於陣列而言可以隨機訪問,那麼對於鍊錶呢,比如快排,兩個指標分別網後往前走,而沒有前驅指標的單向鍊錶,無法完成這樣的操作,當然了可以採用快慢指標的方式,在提交leetcode的時候,發現快排是會超時的。
那麼對於鍊錶而言,可以採取一種怎麼樣的高效排序演算法呢
歸併排序
分而治之,分別拍好前後兩個部分,然後合併兩個有序鍊錶,在合適不過,並且由於鍊錶自帶屬性,合併鍊錶還無需0(n)額外的空間,因此歸併排序成為鍊錶排序的首選。
我一直認為歸併排序是挺好理解的,也比較簡單,但是看了看網上的部落格,為什麼總感覺要麼是放一堆**,要麼放一堆很長很長的**,不如自己寫個簡單點的,完全按照陣列的方式。
歸併排序有幾個子問題,鍊錶分割,有序鍊錶合併
鍊錶分割
將乙個鍊錶分為為兩個長度相等的鍊錶(單數時會多乙個)。
這個問題就相當於找到鍊錶的中點,很簡單的使用快慢指標,快指標走到尾節點,慢指標剛好走到一半。
第乙個鍊錶的頭為head,第二個鍊錶的頭為慢指標的next指標。先拍後面,在拍前面。
此時需要注意,鍊錶要分成兩份,從中間斷開,因此需要將慢節點的next指標設定為null很關鍵!!!。
listnode* sort_list(listnode *head)
if (r == head)//如果此時只有兩個節點,那麼中間節點就是頭節點,l=r=head,無限迴圈,因此特殊判斷
r=sort_list(l->next);//排序後半部分
l->next =
null;//注意,一定要把前面從中間節點切斷
l=sort_list(head);//排序前面一部分
listnode* temp = merge_list(l, r);//合併兩個有序鍊錶
return temp;
}
有序鍊錶合併類似於合併有序陣列,不過不需要額外的空間了。
比如 鍊錶1 1->3->7->9
鍊錶2 2->4->10->29
由於需要返回乙個新的頭部,而頭部必然為鍊錶1的頭部或鍊錶2的頭部,因此不需要另外新建了。
**如下
listnode * merge_list(listnode *head1, listnode *head2)
else
p = newhead;
while (head1 !=
null
&& head2 !=
null)
else
}while (head1 !=
null)
while (head2 !=
null)
p->next =
null;
return newhead;
}
然後就是乙個遞迴呼叫的過程
完整測試**
struct listnode
};class solution
else
p = newhead;
while (head1 !=
null
&& head2 !=
null)
else
}while (head1 !=
null)
while (head2 !=
null)
p->next =
null;
return newhead;
}listnode* sort_list(listnode *head)
if (r == head)//如果此時只有兩個節點,那麼中間節點就是頭節點,l=r=head,無限迴圈,因此特殊判斷
r=sort_list(l->next);//排序後半部分
l->next =
null;//注意,一定要把前面從中間節點切斷
l=sort_list(head);//排序前面一部分
listnode* temp = merge_list(l, r);//合併兩個有序鍊錶
鍊錶排序 歸併
遞迴方法的歸併排序三部曲 1,快慢指標找中點 2,遞迴呼叫mergesort,3,合併兩個鍊錶。class solution listnode mergesort listnode node breakn next nullptr listnode l1 mergesort node listnod...
演算法 鍊錶的歸併排序
複雜度分析 設定兩個指標,乙個步長為1,乙個步長為2,當快指標到達尾結點時,慢指標指向中間結點,時間複雜度為o n 平分為左鍊錶l1和右鍊錶l2,遞迴 直到鍊錶為空或者只有乙個結點 將鍊錶l2的每個結點插入到鍊錶l1中,時間複雜度為o m n m n分別為兩條鍊錶的長度。畫出遞迴樹,可知總的時間複雜...
鍊錶排序 歸併排序
要求在空間複雜度為o 1 的情況下對鍊錶進行排序,在不考慮時間複雜度的情況下可以考慮氣泡排序,只對鍊錶中的值進行操作,這樣時間複雜度為o n 2 用歸併排序,時間複雜度為o nlogn 以下為歸併排序 實現 public listnode sortlist listnode head private...