問題
給單鏈表排序(升序排列,要保持穩定性),要求通過改變結點的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;
}