LeetCode—Sort List解题报告

转载请注明:http://blog.csdn.net/ict2014/article/details/17416115

原题如下:


题目解析:

       题目要求是对单链表进行从小到大排序,要求的时间复杂度为O(nlogn)。

       从时间复杂度上分析此题,可以排除插入排序等O(n^2)的算法。

       剩余两种排序算法,快速排序和合并排序。这两种算法究竟使用哪一个呢?此时我们要结合题目的数据结构——单链表进行分析,看哪一个更加方便快捷。快速排序的思想是选定一个pivot点,在该点之前的都小于此点,在该点之后的都大于此点,然后前半部分和后半部分分别递归排序,繁杂的操作就是调整指针。对于合并排序而言,从中间将链表拆分成两个链表,两个链表单独进行排序,排序后的两个链表进行合并操作即可。相比较而言,个人感觉合并排序比较简单一些,拆分成两个链表的时候,从链表的中间进行切分即可,合并两个有序的单链表也是很简单的操作。


题目代码:

       我们实现合并排序,算法的时间复杂度为O(nlogn)。代码在leetcode上Accept.

/**
 * 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) {
        //List is empty or only one node
        if(head == NULL || head->next == NULL){
            return head;
        }
        //List size
        int size = GetSize(head);
        //Combination Sort
        return CombinationSort(head, size);
    }
    
    //Combination Sort
    ListNode* CombinationSort(ListNode* head, 
                              const int& size){
        if(size <= 1){
            return head;
        }
        
        ListNode* head2 = ForwardNSteps(head, size>>1);
        ListNode* newHead1 = CombinationSort(head, size>>1);
        ListNode* newHead2 = CombinationSort(head2,size-(size>>1));
        
        return CombineTwoList(newHead1, newHead2);
    }
    
    //Combine two sorted lists
    ListNode* CombineTwoList(ListNode* head1,
                             ListNode* head2){
        ListNode* newhead;
        ListNode* current1 = head1;
        ListNode* current2 = head2;
        
        if(head1->val < head2->val){
            newhead = head1;
            current1 = current1->next;
        }else{
            newhead = head2;
            current2 = current2->next;
        }
        
        ListNode* pre = newhead;
        while(current1 != NULL && current2 != NULL){
            if(current1->val < current2->val){
                pre->next = current1;
                pre = current1;
                current1 = current1->next;
            }else{
                pre->next = current2;
                pre = current2;
                current2 = current2->next;
            }
        }
        
        if(current1 != NULL){
            pre->next = current1;
        }
        
        if(current2 != NULL){
            pre->next = current2;
        }
        
        return newhead;
    }
    
    //move forward N steps
    ListNode* ForwardNSteps(ListNode* head,
                            const int& nsteps){
        for(int i = 1; i < nsteps; ++i){
            head = head->next;
        }
        ListNode* head2 = head->next;
        head->next = NULL;
        return head2;
    }
    
    //calculate the length of list
    int GetSize(ListNode* head){
        int length = 0;
        while(head != NULL){
            head = head->next;
            ++length;
        }
        return length;
    }
};

注意程序的第31行,左移右移运算符的优先级小于加减乘除,第一次总是wrong answer,调试之后,才发现

“size-size>>1”的结果始终为0,因此,必须用括号将size>>1括起来。这是一点需要注意的小事项。

程序总体是合并排序的思想,22-34是合并排序的核心代码段。完成拆分、合并操作。75-84完成拆分操作,36-73完成合并两个有序单链表操作。代码只是用英文进行了简单的注释,如有疑问,可以互相讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值