在單鏈表上實現插入排序

問題

給單鏈表排序(升序排列,要保持穩定性),要求通過改變結點的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; 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章