148 Sort List [Leetcode]

13 篇文章 0 订阅
1 篇文章 0 订阅

题目内容:

Sort a linked list in O(n log n) time using constant space complexity.

根据给出的时间复杂度,可以想到满足的排序方法有:
1. 快速排序
2. 堆排序
3. 归并排序

再考虑空间复杂度:
1. 快速排序主要要实现partition算法,在数组中它实现的算法复杂度为O(n),利用链表,同样可以在O(n)时间内实现,且不需要额外的空间,可行。
2. 堆排序需要能够在O(1)时间内获得某个节点的父节点或者子节点,因此需要有一个类似于数组的容器装。而这里本身链表就会有O(n)的空间装指针,将这些指针装入priority_queue中不需要额外的开辟空间,因此也是可行的
3. 归并排序在数组中本来需要开辟O(n)的空间存储合并后的节点,但是在链表中可以在原地实现,这在之前的Leetcode题中已经解过,因此归并排序也是可行的。

下面给出这三种方法的代码实现:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

struct ListCompare {
    bool operator()(ListNode *n1, ListNode *n2) {
        return n1->val < n2->val;
    }
};

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head == NULL)
            return NULL;

        //quickSort(head);
        //mergeSort(head);
        heapSort(head);
        return head;
    }

    void heapSort(ListNode *&head) {
        ListNode *p(head);
        priority_queue<ListNode *, vector<ListNode *>, ListCompare> ListHeap;

        while(p != NULL) {
            ListHeap.push(p);
            p = p->next;
        }

        head = NULL;
        // 这里使用了最大堆,前插法构建链表
        while(!ListHeap.empty()) {
            ListNode *temp = ListHeap.top();
            ListHeap.pop();
            temp->next = head;
            head = temp;
        }
    }

    void mergeSort(ListNode *&head) {
        if(head == NULL || head->next == NULL)
            return;
        ListNode *mid = getMidPoint(head);
        mergeSort(head);
        mergeSort(mid);
        head = mergeList(head, mid);
    }

    // return the mid point of list and split the list
    ListNode *getMidPoint(ListNode* head) {
        if(head == NULL)
            return NULL;
        ListNode *one(head), *two(head), *pre(NULL);
        while(two != NULL && two->next != NULL) {
            pre = one;
            one = one->next;
            two = two->next->next;
        }
        pre->next = NULL;
        return one;
    }

    ListNode *mergeList(ListNode *l1, ListNode *l2) {
        if(l1 == NULL && l2 == NULL)
            return NULL;
        if(l1 == NULL)
            return l1;
        if(l2 == NULL)
            return l2;

        ListNode *p1(l1), *p2(l2), *head = new ListNode(0), *p = head;
        while(p1 != NULL && p2 != NULL) {
            if(p1->val < p2->val) {
                p->next = p1;
                p1 = p1->next;
            }
            else {
                p->next = p2;
                p2 = p2->next;
            }
            p = p->next;
            p->next = NULL;
        }

        if(p1 != NULL)
            p->next = p1;
        else if(p2 != NULL)
            p->next = p2;

        p = head;
        head = head->next;
        p->next = NULL;
        delete p;

        return head;
    }

    void quickSort(ListNode *&head) {
        partition(head, NULL);
    }

    // end is not included in the list
    void partition(ListNode *&start, ListNode *end) {
        //printList(start, end);
        if(start == end || start->next == end)
            return;

        ListNode *pts = start, *pte = start, *small = start, *large = end;

        while(small->next != end) {
            if(small->next->val > pts->val) {
                ListNode *temp = small->next;
                small->next = small->next->next;
                temp->next = large;
                large = temp;
            }
            else if(small->next->val == pts->val) {
                ListNode *temp = small->next;
                small->next = small->next->next;
                temp->next = pts;
                pts = temp;
            }
            else {
                small = small->next;
            }
        }

        small->next = pts;
        small = pte->next;

        partition(small, pts);
        partition(large, end);

        pte->next = large;
        start = small;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值