【数据结构】:排序(二)——归并与计数排序详解

🌈个人主页@ꪔ小林Y

个人专栏《C++小白闯关日记》《C语言小白闯关日记》,《数据结构入门------从原理到实战》

🍀代码信条 :每一行代码都是成长的脚印👣,每一次调试成功都是对坚持的回应

目录

接上节,这节内容继续围绕排序展开

排序

归并排序

归并排序的算法思想:归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序的核心步骤:

  • 代码实现:
c 复制代码
void _MergeSort(int* arr ,int left, int right, int* tmp)
{
	//分解
	if (left >= right)
	{
		return;
	}
	int mid = (left + right) / 2;
	//根据mid将[left,right]划分成左右两个序列:[left,mid],[mid+1,right]
	_MergeSort(arr, left, mid,tmp);
	_MergeSort(arr, mid + 1, right,tmp);
	//合并两个序列:[left,mid][mid+1,right]
	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;
	int index = left;
	while (begin1<=end1 && begin2<=end2)
	{
		if (arr[begin1] < arr[begin2])
		{
			tmp[index++] = arr[begin1++];
		}
		else {
			tmp[index++] = arr[begin2++];
		}
	}
	//要么begin1序列中数据没有放完
	//要么begin2序列中数据没有放完
	while (begin1 <= end1)
	{
		tmp[index++] = arr[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[index++] = arr[begin2++];
	}
	//tmp-->arr
	for (int i = left;i <=right;i++)
	{
		arr[i] = tmp[i];
	}
}
//归并排序
void MergeSort(int* arr, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);//为后续合并做准备
	_MergeSort(arr, 0, n - 1,tmp);
	free(tmp);
}
  • 测试:
c 复制代码
void printArr(int* arr, int n)
{
	for (int i = 0;i < n;i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
void test01()
{
	int a[] = {6,1,2,7,9,3};
	int n= sizeof(a) / sizeof(a[0]);
	printf("排序之前");
	printArr(a, n);
	//归并排序
	MergeSort(a, n);
	printf("排序之后");
	printArr(a, n);

}
int main()
{
	test01();
	return 0;
}
  • 运行结果:

时间复杂度:单次递归时间复杂度*总的递归次数

归并排序时间复杂度:n * logn

归并排序空间复杂度:n

非比较排序

计数排序

计数排序是对哈希直接定址法的变形应用:

(1)统计相同元素出现次数

(2)根据统计的结果将序列回收到原来的序列中

例:一个数组:{6,1,2,9,4,2,4,1,4}

数据及重复次数:1(2),2(2),4(3),6(1),9(1)

建立数组:

但是如果遇到数组{100,101,102,101,108,109,108},这种如果用上述排序会造成空间的浪费。所以我们采用映射 的方法将数组中的值全部保存在count数组中:

  • 代码实现:
c 复制代码
#include<memory.h>
//非比较排序------计数排序
void CountSort(int* arr, int n)
{
	//找min,max
	int min = arr[0], max = arr[0];
	for (int i = 1;i < n;i++)
	{
		if (arr[i] < min)
		{
			min = arr[i];
		}
		if (arr[i] > max)
		{
			max = arr[i];
		}
	}
	//确定count数组的大小------max-min+1
	int range = max - min + 1;
	int* count = (int*)malloc(sizeof(int) * (range));
	if (count == NULL)
	{
		perror("malloc fail");
		exit(1);
	}
	//对count初始化:calloc
	memset(count,0, sizeof(int)*(range));
	for (int i = 0;i < n;i++)
	{
		count[arr[i] - min]++;
	}
	//将count数组中的数据还原到原数组中
	int index = 0;
	for (int i = 0;i < range;i++)
	{
		while (count[i]--)
		{
			arr[index++] = i + min;
		}
	}
}
  • 测试运行:
c 复制代码
void printArr(int* arr, int n)
{
	for (int i = 0;i < n;i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
void test01()
{
	int a[] = { 6,1,2,7,9,3 };
	int n= sizeof(a) / sizeof(a[0]);
	printf("排序之前");
	printArr(a, n);
	//计数排序
	CountSort(a, n);
	printf("排序之后");
	printArr(a, n);
}
int main()
{
	test01();
	return 0;
}
  • 运行结果:

计数排序时间复杂度:O(n+range)

空间复杂度:O(range)

各排序方法的比较

稳定性 :假定待排序的序列中,存在多个相同的数据,若经过排序,这些相同数据的相对次序保持不变,则称这种算法是稳定的;否则不稳定。

例:

归并排序:{1,3,3,2}

二分之后为{1,3}和{2,3}

再次排序之后为{1,2,3,3}

这样两个3的相对位置并未发生改变,所以说这个排序是稳定的。

🎊本期数据结构------排序(二)的内容就结束了。如果文中有表述不准的地方,或是你有更清晰的理解思路,强烈欢迎在评论区留言交流------ 技术路上多碰撞,才能更快进步

觉得内容对你有帮助的话,别忘了点赞❤️➕收藏🌟,方便后续回顾复习;想跟着一起系统学习数据结构的朋友,也可以点击关注,下一期我们会聚焦更进一步的学习。不见不散✌️

相关推荐
武帝为此8 小时前
【数据结构之树状数组】
数据结构·算法
失败才是人生常态8 小时前
算法题归类学习
学习·算法
天赐学c语言8 小时前
12.6 - K个一组翻转链表 && C 编译到执行的4个阶段
数据结构·c++·链表·c编译
leoufung8 小时前
用 DFS 拓扑排序吃透 LeetCode 210:Course Schedule II
算法·leetcode·深度优先
chao1898448 小时前
电容层析成像Tikhonov算法
算法
会挠头但不秃8 小时前
2.逻辑回归模型
算法·机器学习·逻辑回归
✎ ﹏梦醒͜ღ҉繁华落℘9 小时前
菜鸟的算法基础
java·数据结构·算法
爪哇部落算法小助手9 小时前
每日两题day65
数据结构·c++·算法
麒qiqi9 小时前
【数据结构核心篇】树与哈希(Hash)的原理、特性及实战应用
数据结构·算法·哈希算法