鍊錶的插入排序

2021-10-22 14:27:03 字數 2828 閱讀 2234

給你鍊錶的頭結點 head ,請將其按 公升序 排列並返回 排序後的鍊錶 。

高階:

你可以在 o(n log n) 時間複雜度和常數級空間複雜度下,對鍊錶進行排序嗎? 

題目分析:

要求使用插入排序的方法對鍊錶進行排序,插入排序的時間複雜度是 o(n^2),其中 nn 是鍊錶的長度。這道題考慮時間複雜度更低的排序演算法。題目的高階問題要求達到 o(nlogn) 的時間複雜度和 o(1) 的空間複雜度,時間複雜度是 o(nlogn) 的排序演算法包括歸併排序、堆排序和快速排序(快速排序的最差時間複雜度是 o(n^2)),其中最適合鍊錶的排序演算法是歸併排序。

歸併排序基於分治演算法。最容易想到的實現方式是自頂向下的遞迴實現,考慮到遞迴呼叫的棧空間,自頂向下歸併排序的空間複雜度是 o(logn)。如果要達到 o(1) 的空間複雜度,則需要使用自底向上的實現方式。

對鍊錶自頂向下歸併排序的過程如下。

找到鍊錶的中點,以中點為分界,將鍊錶拆分成兩個子鍊錶。尋找鍊錶的中點可以使用快慢指標的做法,快指標每次移動 2 步,慢指標每次移動 1 步,當快指標到達鍊錶末尾時,慢指標指向的鍊錶節點即為鍊錶的中點。

對兩個子鍊錶分別排序。

將兩個排序後的子鍊錶合併,得到完整的排序後的鍊錶。

上述過程可以通過遞迴實現。遞迴的終止條件是鍊錶的節點個數小於或等於 1,即當鍊表為空或者鍊錶只包含 1 個節點時,不需要對鍊錶進行拆分和排序。

class solution 

public listnode sortlist(listnode head, listnode tail)

if (head.next == tail)

listnode slow = head, fast = head;

while (fast != tail)

} listnode list1 = sortlist(head, slow);

listnode list2 = sortlist(slow, tail);

listnode sorted = merge(list1, list2);

return sorted;

}public listnode merge(listnode head1, listnode head2) else

temp = temp.next;

}if (head1!= null) else if (head2!= null)

return dummyhead.next;

}}

複雜度分析

時間複雜度:o(nlogn),其中 n 是鍊錶的長度。

空間複雜度:o(logn),其中 n 是鍊錶的長度。空間複雜度主要取決於遞迴呼叫的棧空間。 

使用自底向上的方法實現歸併排序,則可以達到 o(1) 的空間複雜度。

首先求得鍊錶的長度length,然後將鍊錶拆分成子鍊錶進行合併。

具體做法如下。

用 sublength 表示每次需要排序的子鍊錶的長度,初始時 sublength=1。 

每次將鍊錶拆分成若干個長度為 sublength 的子鍊錶(最後乙個子鍊錶的長度可以小於sublength),按照每兩個子鍊錶一組進行合併,合併後即可得到若干個長度為 sublength×2 的有序子鍊錶(最後乙個子鍊錶的長度可以小於sublength×2)。合併兩個子鍊錶仍然使用「21. 合併兩個有序鍊錶」的做法。

將sublength 的值加倍,重複第 2 步,對更長的有序子鍊錶進行合併操作,直到有序子鍊錶的長度大於或等於 length,整個鍊錶排序完畢。

如何保證每次合併之後得到的子鍊錶都是有序的呢?可以通過數學歸納法證明。

初始時sublength=1,每個長度為 11 的子鍊錶都是有序的。

如果每個長度為 sublength 的子鍊錶已經有序,合併兩個長度為 sublength 的有序子鍊錶,得到長度為 sublength×2 的子鍊錶,一定也是有序的。

當最後乙個子鍊錶的長度小於sublength 時,該子鍊錶也是有序的,合併兩個有序子鍊錶之後得到的子鍊錶一定也是有序的。

class solution 

int length = 0;

listnode node = head;

while (node != null)

listnode dummyhead = new listnode(0, head);

for (int sublength = 1; sublength < length; sublength <<= 1)

listnode head2 = curr.next;

curr.next = null;

curr = head2;

for (int i = 1; i < sublength && curr != null && curr.next != null; i++)

listnode next = null;

if (curr != null)

listnode merged = merge(head1, head2);

prev.next = merged;

while (prev.next != null)

curr = next;}}

return dummyhead.next;

}public listnode merge(listnode head1, listnode head2) else

temp = temp.next;

}if (head1!= null) else if (head2!= null)

return dummyhead.next;

}}

複雜度分析

鍊錶插入排序

void insertsort list sortascount,node node else p prior next q q next p int sortwithinsetmethod list sortasdata wchar pp p data if isnum pp int i 0 i ...

鍊錶插入排序

題目 用插入排序對鍊錶排序 樣例 given1 3 2 0 null,return0 1 2 3 null 思路 新建乙個以dummy開頭的鍊錶,並將dummy賦初值為0。令node dummy,通過移動新煉表中的node與要排序的鍊錶中的head,並比較node與head的值,來實現排序。如果he...

鍊錶插入排序

題目 用插入排序對鍊錶排序 思路 建立乙個新的鍊錶,將目標鍊錶依次插入先煉表中,小就插到前面,大就插到後面,如此一來,新的鍊錶就是目標鍊錶按大小次序排列的了。先看第一步,將目標鍊錶的第乙個元素插入所建立的空鍊錶,具體是先建立乙個地值存下頭節點的下乙個節點的位置,將頭節點的next變為空,連到一開始建...