2024年C C++最新八大排序——归并排序和计数排序(1),【一步教学,一步到位】

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

磁盘中的外排序问题是指需要对大量数据进行排序,但内存无法一次性容纳所有数据的情况。这时,需要将数据分为多个部分,每次读取一部分数据到内存中进行排序,最后将所有有序的部分进行合并,从而得到排序后的完整数据。

外排序通常包括以下步骤:

  1. 将原始数据分为多个部分(通常称为“文件”),每个文件大小不超过内存容量。
  2. 对每个文件分别进行内部排序,通常采用快速排序、归并排序等算法。
  3. 将所有有序的文件进行归并排序,得到最终的有序数据。

在具体实现时,需要考虑数据的访问方式以及磁盘I/O的效率。通常采用多路归并和分区排序等技术来优化磁盘I/O的效率,并尽可能减少归并阶段的文件数量,以提高效率。

外排序问题通常出现在大数据处理、数据库系统等领域中,是处理大规模数据时不可避免的问题。

归并排序递归实现

在这里插入图片描述

具体过程如下:

  1. 将待排序序列二分为左右两个子序列,递归地对左右子序列进行归并排序;
  2. 将排好序的左右子序列合并成一个有序序列,具体步骤是将左右两个子序列的首元素进行比较,取较小的元素放入临时数组中,直到其中一个子序列的元素全部被取完,然后将剩余的元素依次放入临时数组中;
  3. 重复步骤2,直到左右两个子序列都放完,此时临时数组中就是排好序的序列。

先分解再合并
在这里插入图片描述
代码实现

void \_MergeSortPart(int\* a, int\* tmp, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int midi = (begin + end) / 2;
	\_MergeSortPart(a, tmp, begin, midi);
	\_MergeSortPart(a, tmp, midi+1, end);
	int begin1 = begin, end1 = midi;
	int begin2 = midi+1, end2 = end;
	int index = begin;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] > a[begin2])
		{
			tmp[index++] = a[begin2++];
		}
		else
		{
			tmp[index++] = a[begin1++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[index++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[index++] = a[begin2++];
	}
	memcpy(a+begin,tmp+begin,sizeof(int)\*(end-begin+1));
}
void MergeSort(int\* a, int n)
{
	int\* tmp = (int\*)malloc(sizeof(int) \* n);
	if (tmp == NULL)
	{
		perror("malloc fail");
	}
	\_MergeSortPart(a, tmp, 0, n - 1);
	free(tmp);
	tmp = NULL;
}

代码解释

归并排序使用递归实现,可以在递归函数开头设置一个条件 begin >= end,当这个条件不满足时,说明递归的每组只有一个数据了,返回后这两个只有一个数的区间进行归并后,拷贝回原数组,再次返回。这时候,就进入了右边的含有两个数的区间,再进行递归,不满足继续递归的条件时,就说明这个偏右的区间也都只有一个数据了,再返回,返回后偏右的区间中的这两个数进行归并,归并后再拷贝回原数组…如此往复,直到将所有的数据全部归并结束并拷贝回原数组。

这个过程比较复杂,大家就可以尝试使用 递归展开图 去理解。

归并排序非递归实现

非递归实现的思路就是直接在数组内部实现归并,定义一个变量 gap,表示每组要归并的元素个数,用 for 循环来控制归并的组数和位置,i 每次跳过 2*gap 个长度,相当于跳过了一组,即开始下一组的递归。这个层次所有组完成递归后,将 gap 变为原来的2倍,开始下一层次的递归,这一次层次每组的数据个数是原来的 2 倍…一直循环,直到 gap 大于数据个数。
但这里有个易错点:end1、begin2、end2可能出现的越界问题。首先,begin1 不可能越界,因为begin1等于i ,越界了就进不了循环;end1和begin2 都有越界的可能,因此判断 begin2 之后,如果越界,就直接停止这层循环(因为这一操作是对本组和一下组进行归并,end2 越界,说明绝对没有第二组,那也就不用进行递归); end2 如果越界的话,说明是有第二组,但第二组数据没有第一组多的情况,直接将end2 赋值为 end 即可解决问题!

void \_MergeSortNonr(int\* a, int\* tmp, int begin, int end)
{
	int gap = 1;//归并每组的元素个数
	while (gap <= end)
	{
		for (int i = 0; i <= end; i += 2 \* gap)
		{
			int index = 0;
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 \* gap - 1;
			if (begin2 > end)
			{
				break;
			}
			if (end2 > end)
			{
				end2 = end;
			}
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] > a[begin2])
				{
					tmp[index++] = a[begin2++];
				}
				else
				{
					tmp[index++] = a[begin1++];
				}
			}
			while (begin1 <= end1)
			{
				tmp[index++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[index++] = a[begin2++];
			}
			memcpy(a+i, tmp+i, sizeof(int) \* (end2 - i - 1));
		}
		gap \*= 2;
	} 
}


计数排序

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值