Sort List @leetcode

本文介绍了一种使用归并排序对链表进行排序的方法,详细解释了两种不同的实现思路及其对应的代码实现,旨在帮助读者理解如何在O(n log n)的时间复杂度内完成排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:https://oj.leetcode.com/problems/sort-list/

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

思路:

对链表进行排序,并且要求是O(n log n)的时间复杂度,同事要求使用常量排序空间,可行的方法包括归并排序、快速排序。进行快速排序的时候,需要不断地调整链表之间的指针顺序,最好是采用新版算法导论里面的partition方法;如果是归并排序的话,那么有两种方式来实现。

第一种是传统的归并排序,进行排序的时候,由于需要对链表进行2分,因此可以采用快慢链表的方式,具体代码如下:

/**
 * 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) {
       lmerge_sort(head);
    }
      ListNode* lmerge_sort(ListNode*start)
   {
       if(start == NULL || start->next == NULL)
       {
           return start;
       }
       ListNode *p = start;
       ListNode *q = start;
       ListNode *pre = NULL;
       while (q != NULL && q->next != NULL)
       {
           q = q->next->next;//采用的快慢指针,实现对链表的二分
           pre = p;
           p = p->next;
       }
       pre->next = NULL;
       ListNode*head1 = lmerge_sort(start);
       ListNode *head2 = lmerge_sort(p);
       return lmerge(head1,head2);
   }
   ListNode* lmerge(ListNode*head1,ListNode*head2)
   {
       ListNode *head;
       ListNode *p;

       if(head1 == NULL)
       {
           return head2;
       }
       if(head2 == NULL)
       {
           return head1;
       }

       if(head1->val < head2->val)
       {
           head = head1;
           head1 = head1->next;
       }
       else
       {
           head = head2;
           head2 = head2->next;
       }
       p = head;
       while (head1 != NULL &&head2 != NULL)
       {
           if(head1->val < head2->val)
           {
               p->next = head1;
               head1= head1->next;
           }
           else
           {
               p->next = head2;
               head2= head2->next;
           }
           p = p->next;
       }
       if(head1 != NULL)
       {
           p->next = head1;
       }
       if(head2 != NULL)
       {
           p->next = head2;
       }
       return head;
   }
};

第二种归并排序的思路来自于STL里面对list进行排序的方法,采用缓冲列表的方式,采用一个大小为64的数组,就可以对至多2^64-1的链表进行排序,这个数据的范围基本上可以满足所有的排序需求。具体代码如下:

class Solution {
public:
    ListNode *sortList(ListNode *head) {
        int feet= 0;
        const int MAX = 64;
        ListNode *mlist[MAX]= {NULL};//链表缓冲区
        ListNode *carry = NULL;
        while (head != NULL)
        {
            int itp = 0;
          //  cout << head->val <<" ";
            carry = slice(head);
            while (itp < feet&& mlist[itp] != NULL)
            {
                //cout << "asd"<<endl;
               // print(mlist[itp]);
                mergelist(carry,mlist[itp]);
               // cout << "asd"<<endl;
                itp ++;
            }
            mergelist(carry,mlist[itp]);
            myswap(carry,mlist[itp]);
            if(itp == feet)
            {
                feet ++;
            }
        }
       // cout << "rnd;"<<endl;
        carry = NULL;
        for(int i = 0;i < feet;i ++)
        {
            mergelist(carry,mlist[i]);
        }
        return carry;
    }
    ListNode * slice(ListNode *&head)
    {
        ListNode * tmp = head;
        head = head->next;
        tmp->next = NULL;
        return tmp;
    }
    void mergelist(ListNode*&qhead,ListNode *&phead)
    {
        ListNode *thead = new ListNode(0);
        ListNode *head1 = qhead;
        ListNode *head2 = phead;
        ListNode *p = thead;
        while(head1 != NULL && head2 != NULL)
        {
            if(head1->val < head2->val)
            {
                p->next = head1;
                head1 = head1->next;
                p = p->next;
            }
            else
            {
                p->next = head2;
                head2 = head2->next;
                p = p->next;
            }
        }
        while(head1 != NULL)
        {
            p->next = head1;
            p = p->next;
            head1 = head1->next;
        }
        while(head2 != NULL)
        {
            p->next = head2;
            p = p->next;
            head2 = head2->next;
        }
        p->next = NULL;
        qhead = thead->next;
        phead = NULL;
        delete thead;
    }
    void myswap(ListNode * &a,ListNode *&b)
    {
        ListNode * tmp = a;
        a = b;
        b = tmp;
    }
};

第二种思路很巧妙,理解的时候有一定困难,尽可能的多在纸上画画。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值