使用插入排序、归并排序对链表进行排序

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

插入排序

插入排序的时间复杂度是 O(n^2)
在这里插入图片描述
插入排序算法:

  1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  3. 重复直到所有输入数据插入完为止。
ListNode* sortList(ListNode* head) {
        //使用插入排序
        if(head == NULL || head->next == NULL) return head;
        //一个哑结点,方便在head之前插入节点
        ListNode * dummyHead = new ListNode(0);
        //哑结点的指向head
        dummyHead->next = head;
        //需要排序插入的节点,从第二个节点开始
        ListNode * curr = head->next;
        //排好序的最后一个节点,从第一个节点开始
        ListNode * lastSorted = head;
        ListNode * prev;
        while(curr != NULL){
            //如果需要排序的节点的值大于已经排好序的最后一个值,就指向下一个
            if(curr->val > lastSorted->val){
                lastSorted = lastSorted->next;
                curr = lastSorted->next;
            }else{
                //否则就表明当前需要排序的节点需要插入到已经排好序的节点中
                //需要从头开始,找地方插入
                prev = dummyHead;
                //先找到需要插入的地方,需要满足大于等于前一个,小于后一个
                while(prev->next->val < curr->val){
                    prev = prev->next;
                }
                //经过上面的循环,已经找到了一个prev,它满足prev小于curr,并且prev->next大于等于curr,所以curr要插入在prev之后
                //插入之前要先将curr之后的节点保存起来,存在lastSorted->next
                lastSorted->next = curr->next;
                curr->next = prev->next;
                prev->next = curr;
                //lastSorted的下一个节点就是待插入的节点
                curr = lastSorted->next;
            }       
        }
        return dummyHead->next;
    }

归并排序

时间复杂度是O(nlogn) 的排序算法包括归并排序堆排序快速排序(快速排序的最差时间复杂度是 O(n^2),其中最适合链表的排序算法是归并排序
归并排序基于分治算法。最容易想到的实现方式是自顶向下的递归实现,考虑到递归调用的栈空间,自顶向下归并排序的空间复杂度是O(logn)。如果要达到O(1) 的空间复杂度,则需要使用自底向上的实现方式。
对链表自顶向下归并排序的过程如下。

  1. 找到链表的中点,以中点为分界,将链表拆分成两个子链表。寻找链表的中点可以使用快慢指针的做法,快指针每次移动 22 步,慢指针每次移动 11 步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点。
  2. 对两个子链表分别排序。
  3. 将两个排序后的子链表合并,得到完整的排序后的链表。
    上述过程可以通过递归实现。递归的终止条件是链表的节点个数小于或等于 1,即当链表为空或者链表只包含 1个节点时,不需要对链表进行拆分和排序。
    在这里插入图片描述
ListNode* sortList(ListNode* head) {
        return sortList(head, nullptr);
    }

    ListNode* sortList(ListNode* head, ListNode* tail) {
        //如果链表为空,直接返回
        if (head == nullptr) {
            return head;
        }
        //如果链表只有一个元素,返回该节点,开始融合
        if (head->next == tail) {
            head->next = nullptr;
            return head;
        }
        //利用快慢指针找链表的中点,快指针一次跑两步,慢指针一次走一步,当快指针走到尾部时,此时慢指针的位置就是中点
        ListNode* slow = head, *fast = head;
        while (fast != tail) {
            slow = slow->next;
            fast = fast->next;
            if (fast != tail) {
                fast = fast->next;
            }
        }
        ListNode* mid = slow;
        return merge(sortList(head, mid), sortList(mid, tail));
    }
    //合并两个有序链表
    ListNode* merge(ListNode* head1, ListNode* head2) {
        ListNode* dummyHead = new ListNode(0);
        ListNode* temp = dummyHead, *temp1 = head1, *temp2 = head2;
        //将两个链表中较小的节点接在哑结点之后
        while (temp1 != nullptr && temp2 != nullptr) {
            if (temp1->val <= temp2->val) {
                temp->next = temp1;
                temp1 = temp1->next;
            } else {
                temp->next = temp2;
                temp2 = temp2->next;
            }
            temp = temp->next;
        }
        //接完了较短的链表,较长的链表还有剩余,将剩余的全部接上
        if (temp1 != nullptr) {
            temp->next = temp1;
        } else if (temp2 != nullptr) {
            temp->next = temp2;
        }
        return dummyHead->next;
    }

使用自底向上的方法实现归并排序,则可以达到 O(1) 的空间复杂度。
首先求得链表的长度}length,然后将链表拆分成子链表进行合并。
具体做法如下。

  1. 用subLength 表示每次需要排序的子链表的长度,初始时subLength=1。
  2. 每次将链表拆分成若干个长度为subLength 的子链表(最后一个子链表的长度可以小于
  3. subLength),按照每两个子链表一组进行合并,合并后即可得到若干个长度为 subLength×2 的有序子链表(最后一个子链表的长度可以小于 subLength×2)。
  4. 将subLength 的值加倍,重复第 2 步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于length,整个链表排序完毕。
    在这里插入图片描述
ListNode* sortList(ListNode* head) {
        if (head == nullptr) {
            return head;
        }
        int length = 0;
        ListNode* node = head;
        //先求出链表有多长
        while (node != nullptr) {
            length++;
            node = node->next;
        }
        ListNode* dummyHead = new ListNode(0, head);
        for (int subLength = 1; subLength < length; subLength <<= 1) {
            ListNode* prev = dummyHead, *curr = dummyHead->next;
            while (curr != nullptr) {
                ListNode* head1 = curr;
                for (int i = 1; i < subLength && curr->next != nullptr; i++) {
                    curr = curr->next;
                }
                ListNode* head2 = curr->next;
                curr->next = nullptr;
                curr = head2;
                for (int i = 1; i < subLength && curr != nullptr && curr->next != nullptr; i++) {
                    curr = curr->next;
                }
                ListNode* next = nullptr;
                if (curr != nullptr) {
                    next = curr->next;
                    curr->next = nullptr;
                }
                ListNode* merged = merge(head1, head2);
                prev->next = merged;
                while (prev->next != nullptr) {
                    prev = prev->next;
                }
                curr = next;
            }
        }
        return dummyHead->next;
    }

    ListNode* merge(ListNode* head1, ListNode* head2) {
        ListNode* dummyHead = new ListNode(0);
        ListNode* temp = dummyHead, *temp1 = head1, *temp2 = head2;
        while (temp1 != nullptr && temp2 != nullptr) {
            if (temp1->val <= temp2->val) {
                temp->next = temp1;
                temp1 = temp1->next;
            } else {
                temp->next = temp2;
                temp2 = temp2->next;
            }
            temp = temp->next;
        }
        if (temp1 != nullptr) {
            temp->next = temp1;
        } else if (temp2 != nullptr) {
            temp->next = temp2;
        }
        return dummyHead->next;
    }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SOC罗三炮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值