• C++数据结构X篇_24_归并排序(稳定的排序)


    本篇参考十大经典排序算法-归并排序算法详解进行整理和补充。

    1. 什么是归并排序

    1.1 概念

    归并排序(Merge sort) 是建立在归并操作上的一种有效的排序算法,归并排序对序列的元素进行逐层(递归)折半分组,然后从最小分组开始比较排序,合并成一个大的分组,逐层进行,最终所有的元素都是有序的。
    归并排序基本思想:将两个有序序列合并成一个有序序列。

    1.2 算法原理

    这是一个无序数列:4、5、8、1、7、2、6、3,我们要将它按从小到大排序。按照归并排序的思想,我们要把序列逐层进行拆分
    在这里插入图片描述
    序列逐层拆分如下
    在这里插入图片描述
    然后从下往上逐层合并,首先对第一层序列1(只包含元素4)和序列2(只包含元素5)进行合并

    创建一个大序列,序列长度为两个小序列长度之和,p1、p2指针分别指向两个小序列的第一个元素,p指向大序列的第一个元素
    在这里插入图片描述
    比较p1、p2指向的元素,4小于5,将4填入p指向的元素,p、p1往右移一位
    在这里插入图片描述
    此时,序列1已经没有元素,将序列2的元素依次填入大序列中
    在这里插入图片描述
    序列8和1,序列7和2,序列6和3,用同样的方式填入新的序列
    在这里插入图片描述
    接着,以4、5为序列1,1、8为序列2,继续进行合并

    创建一个序列长度为4的大序列,p1指向序列1的第一个元素4,p2指向序列2的第一个元素1,p指向大序列的第一个元素
    在这里插入图片描述
    4和1比较,4大于1,1填入p指向的元素,p、p2往右移一位

    在这里插入图片描述
    4和8比较,4小于8,4填入p指向的元素,p、p1往右移一位
    在这里插入图片描述
    5和8比较,5小于8,5填入p指向的元素,p、p1往右移一位
    在这里插入图片描述
    自此,序列1已经没有元素,将序列2的元素依次填入大序列中
    在这里插入图片描述
    序列2、7和序列3、6以同样的方式合并成新的序列
    在这里插入图片描述
    最后,将序列1、4、5、8和序列2、3、6、7以同样的方式继续合并成新的序列
    在这里插入图片描述
    至此所有的元素都是有序的

    1.3 算法实现

    #include 
    #include 
    #include 
    
    using namespace std;
    
    #define MAX 10
    
    //获取系统当前时间,ms为单位
    long getSystemTime()
    {
    	struct timeb tb;
    	ftime(&tb);
    	return tb.time * 1000 + tb.millitm;
    }
    
    
    //打印数组
    void printArr(int arr[])
    {
    	for (int i = 0; i < 10; i++)
    	{
    		cout << arr[i] << " ";
    	}
    	cout << endl;
    }
    
    //初始化数组
    int* CreateArray()
    {
    	//数据放到堆区
    	int* arr = (int*)malloc(sizeof(int)*MAX);
    	//生成随机数
    	srand((unsigned int)time(NULL));
    	for (int i = 0; i < MAX; i++)
    	{
    		arr[i] = rand() % MAX;
    	}
    
    	return arr;
    }
    
    //合并算法,从小到大
    void Merge(int arr[], int start, int end, int mid, int* tmp)
    {
    	int i_start = start;
    	int i_end = mid;
    
    	int j_start = mid + 1;
    	int j_end = end;
    
    	//表示辅助空间有多少元素
    	int length = 0;
    
    	//合并两个有序序列
    	while (i_start <= i_end && j_start <= j_end)
    	{
    		if (arr[i_start] < arr[j_start])
    		{
    			tmp[length] = arr[i_start];
    			length++;
    			i_start++;
    		}
    		else
    		{
    			tmp[length] = arr[j_start];
    			length++;
    			j_start++;
    		}
    	}
    
    	//有一个序列会有剩下的元素,无法知道是哪个,进行遍历将剩余元素拷贝到辅助空间
    	//i这个序列
    	while (i_start <= i_end)
    	{
    		tmp[length] = arr[i_start];
    		i_start++;
    		length++;
    	}
    
    	//j这个序列
    	while (j_start <= j_end)
    	{
    		tmp[length] = arr[j_start];
    		j_start++;
    		length++;
    	}
    
    	//辅助空间数据覆盖原空间
    	for (int i = 0; i < length; i++)
    	{
    		arr[start + i] = tmp[i];
    	}
    }
    
    //归并排序,tmp是辅助空间,排序完的结果放到其中
    void MergeSort(int arr[], int start, int end, int* tmp)
    {
    	//递归结束条件
    	if (start >= end)
    	{
    		return;
    	}
    
    	int mid = (start + end) / 2;
    	//递归 分组
    	//左半边
    	MergeSort(arr, start, mid, tmp);
    	//右半边
    	MergeSort(arr, mid + 1, end, tmp);
    
    	//合并
    	Merge(arr, start, end, mid, tmp);
    }
    
    
    
    int main()
    {
    	int* myArr = CreateArray();
    
    	//辅助空间
    	int* tmp = (int*)malloc(sizeof(int)*MAX);
    
    	printArr(myArr);
    	MergeSort(myArr, 0, MAX - 1, tmp);
    	printArr(myArr);
    
    	//释放空间
    	free(tmp);
    	free(myArr);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134

    2. 归并排序算法特点

    2.1 时间复杂度

    归并排序算法每次将序列折半分组,共需要logn轮,因此归并排序算法的时间复杂度是O(nlogn)

    2.2 空间复杂度

    归并排序算法排序过程中需要额外的一个序列去存储排序后的结果,所占空间是n,因此空间复杂度为O(n)

    2.3 稳定性

    归并排序算法在排序过程中,相同元素的前后顺序并没有改变,所以归并排序是一种稳定排序算法

    1. 视频:归并排序1
  • 相关阅读:
    数字与中文大写数字互转(5千万亿亿亿亿以上的数字也支持转换)
    商业合作保密协议
    MySQL——进阶
    网络-华为、思科交换机配置TFTP自动备份、NTP时间同步、SYSLOG日志同步功能
    通用汽车在华加速推出智能电动车型
    OpenCV从入门到入坟
    ffmpeg之 一张/多张图片合成视频
    C++:类和对象(上)
    2023年【陕西省安全员C证】免费试题及陕西省安全员C证考试试卷
    C++ vector
  • 原文地址:https://blog.csdn.net/Dasis/article/details/134044579