leetcode148.排序链表

在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4

示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

完整代码

看到时间复杂度为O(nlogn)的要求,就考虑用快排来实现,但是传统的快排(以第一个元素为基准)无法实现链表的移动,这里是单向链表。采用了如下的移动方法(以第一个元素为基准)
快排

#include<bits/stdc++.h>

using namespace std;

void swap(int &a, int &b){//交换两个元素
    int temp = a;
    a = b;
    b = temp;
}
void quickSort(vector<int> &nums, int s, int e){
    if(s >= e)//递归终止条件
        return;
    int flag = nums[e];
    int i = s - 1;
    for(int j = s; j < e; ++j){
        if(nums[j] < flag){
            swap(nums[j], nums[++i]);
        }
    }
    swap(nums[++i], nums[e]);
    quickSort(nums, s, i - 1);
    quickSort(nums, i + 1, e);
}

int main(){
    vector<int> nums = {4, 2, 3, 1};
    quickSort(nums, 0, nums.size() - 1);
    for(auto a : nums)
        cout << a << " ";
    cout <<"Dsa";
    return 0;
}

基本思想
快排

  • 交换两个节点时, 这里只是交换的链表的值,并没有改变链表的指向
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        //快排来实现
        if(head == NULL || head->next == NULL)
            return head;
        
        ListNode* n_head = new ListNode(0), *end_Node;
        n_head->next = head;//指向真正的头节点的节点
        ListNode* p = head;
        while(p){//尾节点
            end_Node = p;
            p = p->next;
        }
        fastSort(n_head, end_Node);
        return n_head->next;
    }
private:
    void fastSort(ListNode* n_head, ListNode* end_Node){
        if(n_head == end_Node)//递归结束的条件
            return;
        ListNode* flag = end_Node;
        ListNode* res = n_head, *left = n_head->next;
        while(left != end_Node){
            if(left->val < end_Node->val){
                res = res->next;
                swap(res, left);//所需交换的两个节点的前驱                
            }
            left = left->next;
        }
        //res是左半部分末尾的节点
        swap(end_Node, res->next);//已经排好序的值放在了res->next中        
        fastSort(n_head, res);
        fastSort(res->next, end_Node);        
    }
    void swap(ListNode* a, ListNode* b){//交换两个节点的值
        int temp = a->val;
        a->val = b->val;
        b->val = temp;
    }
};

在排序算法中除了快排,还有归并排序的时间复杂度也是O(nlogn)
归并排序
参考:添加链接描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        //归并排序
        if(head == NULL || head->next == NULL)
            return head;
        ListNode *slow = head, *fast = head->next;
        while(fast != NULL && fast->next != NULL){//寻找中间结点
            slow = slow->next;
            fast = fast->next->next;
        }
        ListNode* right_head = slow->next;
        slow->next = NULL;
        ListNode* left = sortList(head);
        ListNode* right = sortList(right_head);
        //归并链表
        ListNode* dummy = new ListNode(0), *p;
        p = dummy;
        while(left && right){
            if(left->val < right->val){
                p->next = left;
                left = left->next;
            }
            else{
                p->next = right;
                right = right->next;
            }
            p = p->next;
        }
        if(left)
            p->next = left;
        if(right)
            p->next = right;
        return dummy->next;
    }
};

非递归形式的归并排序
基本思想:
对于整个链表而言,先两两合并,再四四合并,知道待合并的长度大于等于链表长度时不再合并

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        //归并:从低向上,非递归形式
        if(head == NULL || head->next == NULL)
            return head;
        //1.统计链表长度
        int len = 0;
        ListNode *p = head;
        while(p){
            p = p->next;
            ++len;
        }
        int intv = 1;//间隔以2的整数次幂的方式递增
        ListNode *res = new ListNode(0);
        res->next = head;
        while(intv < len){
            ListNode *pre = res;
            p = res->next;
            while(p){//将间隔为intv的链表合并
                //第一段链表
                ListNode* h1 = p;
                int i = intv;
                while(i > 0 && p){
                    p = p->next;
                    i--;
                }
                if(p == NULL)//没有第二段链表,无需合并
                    break;
                //第二段链表,(长度不一定是intv)
                ListNode* h2 = p;
                i = intv;
                while(i > 0 && p){
                    p = p->next;
                    i--;
                }
                //合并两段链表
                int l1 = intv, l2 = intv - i;
                while(l1 > 0 && l2 > 0){
                    if(h1->val < h2->val){
                        pre->next = h1;
                        h1 = h1->next;
                        --l1;
                    }
                    else{
                        pre->next = h2;
                        h2 = h2->next;
                        --l2;
                    }
                    pre = pre->next;
                }
                while(l1){
                    pre->next = h1;
                    pre = pre->next;
                    h1 = h1->next;
                    --l1;
                }
                while(l2){
                    pre->next = h2;
                    pre = pre->next;
                    h2 = h2->next;
                    --l2;
                }      
                // pre->next = (l1 == 0) ? h2 : h1;
                // while (l1 > 0 || l2 > 0) {
                //     pre = pre->next;
                //     l1--;
                //     l2--;
                // }
                pre->next = p;//将已排好序的那一步分和后面的连接上
            }
            intv *= 2;
        }
        return res->next;
    }
};
发布了253 篇原创文章 · 获赞 9 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章