写给自己看的单链表(5):归并排序

搬运自我的CSDN https://blog.csdn.net/u013213111/article/details/88670270

!!!Attention:以下操作中的单链表均带有头结点!!!
参考怎样实现链表的归并排序

由于待处理的单链表带有头结点,因此把程序分为MergeSort和MergeSortCore两部分,其中MergeSort只是用来处理头结点的,这与写给自己看的单链表(2):进阶操作中的合并程序类似。

从MergeSortCore的伪代码可以一窥归并排序的思路:

1 Lnode *MergeSortCore(Lnode *head)
2 {
3     if 元素只有一个(已经有序)return;
4         划分为左右两段
5     对左段进行MergeSortCore
6     对右段进行MergeSortCore
7     //此时左段和右端已经有序
8     对左段和右段进行合并(MergeListCore)
9 }

要解决的是两个问题,一是如何分段,二是如何合并左段和右段。合并左段和右段可以用写给自己看的单链表(2):进阶操作中已经写好的MergeListCore,那么剩下的问题就是如何分段了。

分段用的是追及的思路:

使用一个slow指针和一个fast指针,让fast指针相对slow指针的移动速度是单位1。这样fast走到尽头时,slow就在“中间”位置了。

这样可以把链表分为两段:[left, slow->next) 和 [right, fast),这里的left和right均不包含头结点。right即为slow->next,在对right进行了赋值后,要注意把slow->next赋值为NULL,否则在递归MergeListCore时找不到终止点。fast其实就是NULL,所以分段的循环条件为fast != NULL。

代码如下:

 1 void MergeSort(Lnode *head)
 2 {
 3     if (head->next == NULL)
 4         return;
 5     head->next = MergeSortCore(head->next);
 6 }
 7
 8 Lnode *MergeSortCore(Lnode *head)
 9 {
10     if (head->next == NULL)
11         return head;
12
13     Lnode *slow, *fast;
14     slow = head;
15     fast = slow->next;
16     while (fast != NULL) {
17         fast = fast->next;
18         if (fast != NULL) {
19             slow = slow->next;
20             fast = fast->next;
21         }
22     }
23
24     Lnode *righthead;
25     righthead = slow->next;
26     slow->next = NULL;
27     head = MergeSortCore(head);
28     righthead = MergeSortCore(righthead);
29     return MergeListCore(head, righthead);
30 }

原文地址:https://www.cnblogs.com/lyrich/p/10586633.html

时间: 2024-10-17 00:23:44

写给自己看的单链表(5):归并排序的相关文章

写给自己看的单链表(4):快速排序

搬运自我的CSDN https://blog.csdn.net/u013213111/article/details/88670136 !!!Attention:以下操作中的单链表均带有头结点!!!参考了这三篇文章:单链表快速排序算法的实现单链表的快速排序单链表的快排实现快速排序的思路是:首先,选取一个pivot:然后以pivot作为基准,对待排序的数据进行分区,得到两个部分,一个部分的数据均小于pivot,另一个部分的数据均大于pivot,然后对这两个部分再进行之前的操作,直至排序完成.对数组

看数据结构写代码(4)单链表

单链表比较简单,中间倒也没出什么大问题,只是 在写 插入 和 删除的 算法的 时候 ,时间复杂度 是正常 算法的2倍.后来 改正了. 下面奉上代码.如有 bug,欢迎指出. // SingleList.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <cstdlib> enum E_State { E_State_Error = 0, E_State_OK = 1, }; typedef int ElementTyp

【LeetCode】 sort list 单链表的归并排序

题目:Sort a linked list in O(n log n) time using constant space complexity. 思路:要求时间复杂度O(nlogn) 知识点:归并排序,链表找到中点的方法 存在的缺点:边界条件多考虑!!! /** * LeetCode Sort List Sort a linked list in O(n log n) time using constant space complexity. * 题目:将一个单链表进行排序,时间复杂度要求为o

单链表的归并排序

#include<iostream> #include<time.h> using namespace std; //链表的归并排序 struct listnode{ int value; listnode* next; listnode(int value):value(value),next(NULL){} }; listnode* find_mid(listnode* head){ if(head==NULL)return NULL; listnode* fast=head;

单链表排序--归并排序

#include <iostream> #include <cstdlib> using namespace std; struct ListNode //默认为public { int data; ListNode* next; ListNode(int x, ListNode* nextNode):data(x), next(nextNode){} }; ListNode* mergeData(ListNode* first, ListNode* second) { if(fi

数据结构与算法系列四(单链表)

1.引子 1.1.为什么要学习数据结构与算法? 有人说,数据结构与算法,计算机网络,与操作系统都一样,脱离日常开发,除了面试这辈子可能都用不到呀! 有人说,我是做业务开发的,只要熟练API,熟练框架,熟练各种中间件,写的代码不也能“飞”起来吗? 于是问题来了:为什么还要学习数据结构与算法呢? #理由一: 面试的时候,千万不要被数据结构与算法拖了后腿 #理由二: 你真的愿意做一辈子CRUD Boy吗 #理由三: 不想写出开源框架,中间件的工程师,不是好厨子 1.2.如何系统化学习数据结构与算法?

单链表排序(插入与归并)

struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; /* * 单链表的插入排序, 插入排序是一种稳定排序 */ class Solution7 { public: ListNode* insertionSortList(ListNode* head) { if(head == NULL || head->next == NULL) return head; ListNode *

快速排序,归并排序,堆排序的数组和单链表实现

原文链接:https://www.cnblogs.com/DarrenChan/p/8807112.html 这三个排序的时间复杂度都是O(nlogn),所以这里放到一起说. 回到顶部 1. 快速排序# 快速排序(英语:Quicksort),又称划分交换排序(partition-exchange sort),通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成

链表的归并排序

当我们需要对链表进行排序时,由于不能对它的元素进行随机访问,所以更适合使用归并排序,大名鼎鼎的快速排序用到链表上,效率也很低,原因还是在于不能对链表中的元素进行随机访问,同理,采用堆排序更是不可能的事情. 对单链表进行归并排序,单链表与数组相比只能顺序访问每个元素,因此在使用二路归并排序时关键在于找到链表的中间结点将链表一分为二:可以利用一个步长为2的指针和一个步长为1的指针同时遍历单链表,当步长为2的指针指向链表最后一个结点或者最后一个结点的下一个结点时,步长为1的指针即指向链表的中间结点.然