Sort List系列

在严老师的数据结构书上学习了各种排序算法,比如插入排序,选择排序,堆排序,快速排序,归并排序等,不过书上代码的应用场景均是底层结构是顺序存储的情况,即数组。

今天总结下对于单链表,常用的排序算法能否使用。由于希尔排序、堆排序、计数排序都要求随机访问,而单链表只能顺序访问,故这 3 种是不能用于单向链表排序,其他常用的排序方法用于单链表时间复杂度和空间复杂度略有不同。下图是针对单链表的常用排序算法图:


 

Insertion Sort List

 

 

Sort a linked list using insertion sort.

 

使用简单插入排序和选择排序,代码如下:
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *insertionSortList(ListNode *head) {
        if( !head ) return head;
        ListNode node(0);
        node.next = head;   //增加头结点,便于插入
        ListNode* cur = head->next;     //认为第一个节点时有序,从第二个节点开始往前插
        head->next = 0;
        while( cur ) {
            ListNode* pre = &node;
            ListNode* p = node.next;
            while( p && p->val <= cur->val ) {  //查找第一个大于cur节点的节点
                pre = p;
                p = p->next;
            }
            p = cur->next;
            cur->next = pre->next;  //插入节点
            pre->next = cur;
            cur = p;
        }
        return node.next;
    }
    
    ListNode* selectionSortList(ListNode* head) {
        if( !head ) return head;
        for( ListNode* pi = head; pi->next; pi = pi->next ) {
            ListNode* minNode = pi;
            for( ListNode* pj = pi->next; pj; pj = pj->next )
                if( pj->val < minNode->val ) minNode = pj;
            swap(pi->val, minNode->val);
        }
        return head;
    }
};

Sort List

 

 

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

 

如果使用O(N2)的算法,会超时,但是使用快速排序,在极端情况下,时间复杂度依旧达到了O(N2),依然超时,使用归并排序,时间复杂度为O(NlogN),可以顺利AC,下面代码是快排和归并的算法
/**
 * 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) {
        return qSort(head);
    }
    
    ListNode* qSort(ListNode* head) {
        if( !head || !head->next ) return head;
        ListNode* lhead = head;     //左部分链表
        ListNode* rhead = NULL;     //右部分链表
        ListNode* mid = NULL;       //分区节点
        mid = partition(lhead, rhead);  //分区
        lhead = qSort(lhead);   //左链表快排
        rhead = qSort(rhead);   //右链表快排
        if( lhead ) {       //若左链表非空
            ListNode* p = lhead;
            while( p->next ) p = p->next;
            p->next = mid;
        }
        else {          //左链表为空
            lhead = mid;
        }
        mid->next = rhead;
        return lhead;
    }
    
    ListNode* partition(ListNode*& lhead, ListNode*& rhead) {
        ListNode node(0);
        node.next = lhead;
        ListNode* end = lhead;
        while( end->next ) end = end->next; //找到最后节点
        ListNode* pi = lhead;
        ListNode* pre = &node;
        for(ListNode* pj = lhead; pj != end; pj = pj->next) //单向扫描法。。。欲知详情有请度娘
            if( pj->val <= end->val ) {
                swap(pi->val, pj->val);
                pre = pi;
                pi = pi->next;
            }
        swap(pi->val, end->val);
        if( lhead == pi ) lhead = NULL; //左边部分为空的情况
        else pre->next = NULL;
        rhead = pi->next;   //分区后右边部分
        pi->next = NULL;
        return pi;      //中间节点
    }
    
    ListNode* mergeSort(ListNode* head) {
        if( !head || !head->next ) return head;     //若链表只有1个节点或没有,则直接返回
        ListNode* fast = head;
        ListNode* slow = head;
        while( fast && fast->next && fast->next->next ) {   //注意fast->next->next,不然当链表有两个节点时会死循环
            fast = fast->next->next;
            slow = slow->next;
        }
        fast = slow->next;
        slow->next = NULL;      //链表分成两部分,前一部分为head,后一部分为fast
        head = mergeSort(head);
        fast = mergeSort(fast);
        return merge(head, fast);   //merge两部分链表
    }
    
    ListNode* merge(ListNode* lhead, ListNode* rhead) {
        if( !lhead ) return rhead;
        if( !rhead ) return lhead;
        ListNode node(0);
        ListNode* tail = &node;
        while( lhead && rhead ) {
            if( lhead->val < rhead->val ) {     //左小取左边
                tail->next = lhead;
                tail = lhead;
                lhead = lhead->next;
                tail->next = NULL;
            }
            else {  //右小取右边
                tail->next = rhead;
                tail = rhead;
                rhead = rhead->next;
                tail->next = NULL;
            }
        }
        tail->next = lhead ? lhead : rhead;     //左链表不为空则取左边,否则取右边
        return node.next;
    }
};




 

 


 

posted on 2014-08-14 22:20  bug睡的略爽  阅读(196)  评论(0编辑  收藏  举报

导航