在單鏈表上實現插入排序
阿新 • • 發佈:2019-01-06
問題
給單鏈表排序(升序排列,要保持穩定性),要求通過改變結點的next指標從而改變結點的位置,而不是隻交換結點的值來使得其有序!時間複雜度為O(N^2),空間複雜度為O(1)。已知連結串列結點的實現如下:
struct ListNode
{
int value;
ListNode* next;
ListNode(int v)
: value(v), next(NULL) {}
};
思路
這裡很明顯就是要我們做插入排序了,當然,冒泡也不是不可以,只是冒泡寫起來麻煩,且效能是最差的。
插入排序怎麼寫呢?
這個演算法的思想是這樣的:
1. 維護兩部分,一是已排序的部分,一是待排序的部分;
2. 一開始已排序部分為NULL;
3. 每次取出待排序部分的第一個元素A,和已排序的部分逐個比較(從頭往後或從後往前都可以,不過單鏈表只能夠從頭往後比較),找到第一個大於A的元素B;
4. 將A插在B的前面一個位置(這時需要注意了,如果B原來是連結串列頭,那麼A將變成新的連結串列頭,此時要記得更新連結串列頭指標)。
程式碼
#include <iostream>
#include <string>
using namespace std;
struct ListNode
{
int value;
ListNode* next;
ListNode(int v)
: value(v), next(NULL) {}
};
ListNode* sortList(ListNode* head) {
// 注意這樣寫,是不需要額外判斷head是否為NULL的
ListNode *newHead = NULL, *toInsert = head;
while (toInsert != NULL) {
ListNode *current = newHead, *last = NULL, *next = toInsert->next;
// 從頭往後找到第一個大於toInsert->value的元素
while (current != NULL && current->value <= toInsert->value) {
last = current;
current = current-> next;
}
if (last == NULL) {
// 如果比任何已排序的數字都要小,那麼就成為新的頭部
toInsert->next = newHead;
newHead = toInsert;
} else {
// 否則插入到last的後面
toInsert->next = last->next;
last->next = toInsert;
}
toInsert = next;
}
return newHead;
}
// 列印連結串列
void display(ListNode* head) {
while (head != NULL) {
cout << head->value << ' ';
head = head->next;
}
cout << endl;
}
int main() {
ListNode* head = new ListNode(5);
head->next = new ListNode(4);
head->next->next = new ListNode(3);
head->next->next->next = new ListNode(2);
head->next->next->next->next = new ListNode(1);
display(head);
ListNode* head2 = sortList(head);
display(head2);
return 0;
}