c语言数据结构-排序(快速+归并+计数+桶)

 (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)

目录

快速排序:

归并排序:

计数排序:

桶排序: 


快速排序:

原理:快速排序的核心思想是设立一个轴,然后其他数据都和这个轴作比较,最后把轴放在序列的中间,执行完一遍快速排序后左边的数据都比轴小,右边的数据都比轴大。然后递归下去,当递归结束的时候就拍好序了。快速排序的排序很快,但是当数据形成一边倒的情况的时候就发挥不出快速排序的优势。

代码思路:先选第一个元素作为中心轴,此时有两个下标right和left,分别指向最后一个元素位置和第一个元素位置(如图所示),首先将最后一个元素48与44比较,因为48大于44,所以将right--,使right前移指向50,因为50大于44,所以right指向19,因为19小于44,所以将19放到left对应的位置中,然后left后移指向3,因为3小于44,所以将left继续后移,到47时,因为47大于44,所以将47放到原来19的位置(那里有一个空缺),然后right前移,以此类推,最终left会和right重合,且他们重合的位置有空缺,再将中心轴44插入到空缺中

void quicksort(int *arr,int n)
{
	if (n < 2)//数组元素小于2个就不用排序
		return ;
	int tmp = arr[0];//选取最左边的数为中心轴
	int left = 0;//左下标
	int right = n - 1;//右下标
	int moving = 2;//当前应该移动的下标,1-左下标,2-右下标
	while (left < right)
	{
		if (moving == 2)//移动右下标
		{
			//如果右下标位置元素的值大于等于中心轴,继续移动右下标。
			if (arr[right] >= tmp)
			{
				right--;
				continue;
			}
			//如果右下标位置元素的值小于中心轴,吧它填到左下标的坑中。
			arr[left] = arr[right];
			left++;//左下标向右移动
			moving = 1;//下次循环将移动左下标
			continue;
		}
		if (moving == 1)//移动左下标
		{
			//如果左下标位置的元素值小于等于中心轴,继续移动左下标
			if (arr[left] <= tmp)
			{
				left++;
				continue;
			}
			//如果左下标位置元素的值大于中心轴,把他填到右下标的坑中
			arr[right] = arr[left];
			right--;//右下标向左移动
			moving = 2;//下次循环移动右下标
			continue;
		}
	}
	//如果循环结束,左右下标重合,把中心轴的值填进去
	arr[left] = tmp;
	quicksort(arr, left);//对中心轴左边的序列进行排序
	quicksort(arr + left + 1, n - left - 1);//对中心轴右边的序列进行排序
}
int main()
{
	int arr[15] = { 44,3,38,5,47,15,36,26,24,2,46,4,19,50,48 };
	quicksort(arr, 15);
	for (int i = 0; i < 15; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

归并排序:

原理:把要排序的序列拆分成多个含有一个数据的序列,然后按照从小到大(从大到小)进行合并,这样就自然的将无序的序列排好序。归是归并的归,不是递归的归,归并排序就是合并排序。

代码思路:首先将待排序数列拆分,使一个元素单独成一组,得到7个有序子数列,然后每两个一组单独排序,得到4个有序子数列,再将4个子数列每两个一组排序,得到两个子数列,最后将两个子数列排序,得到有序子数列

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int min(int x, int y)//取x和y中的较小值
{
	return x < y ? x : y;
}
void mergesort(int* arr, int n)
{
	if (n < 2)//数组元素小于2个就不用排序
		return;
	int* a = arr;//a指向待排序的数组
	int* b = (int*)malloc(n * sizeof(int));//b指向已排序的数组
	int seg;//区间分段的计数器
	int start;//区间起始位置的计数器
	//排序的次数的循环
	for (seg = 1; seg < n; seg = seg * 2)
	{
		//每次排序选取区间的循环
		for (start = 0; start < n; start = start + seg * 2)
		{
			//把每个区间分成两部分,low是起始位置,mid是中间位置,max是结束位置

			int low = start;
			int mid = min(start + seg, n);
			int max = min(start + seg * 2, n);
			int i = low;//已排序数组的计数器
			int start1 = low, end1 = mid;//待排序左边数列的起始和结束位置
			int start2 = mid, end2 = max;//待排序右边数列的起始和结束位置
			//把待排序左右两边数列合并到已排序数组
			while ((start1 < end1) && (start2 < end2))
			{
				b[i++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
			}
			//把左边数列其他元素追加到已排序数组
			while (start1 < end1)
			{
				b[i++] = a[start1++];
			}
			//把右边数列其他的元素追加到已排序数组
			while ((start2 < end2))
			{
				b[i++] = a[start2++];
			}		
		}
		//交换一下两个数组的指针,准备下一次排序
		int* tmp = a;
		a = b;
		b = tmp;	
	}
	//如果a指向的不是原始数组的指针,把a中的内容复制到arr中
	if (a != arr)
	{
		memcpy(arr, a, n * sizeof(int));
	}
	free(b);
}
int main()
{
	int arr[15] = { 44,3,38,5,47,15,36,26,24,2,46,4,19,50,48 };
	mergesort(arr, 15);
	for (int i = 0; i < 15; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

 运行结果为:

计数排序:

前面的算法都是基于比较的排序,计数排序是利用了数组的下标天然有序原理进行排序,所以计数排序是基于统计而排序的排序算法。算法的核心思想是遍历一个无序数组,将遍历到的数据按它的数值找到统计数组的对应下标将其放入统计数组中,依次类推,直到无序的数组的每一个数据都被遍历完之后统计数组也已经初始化完毕,接下来就是遍历统计数组如果遍历到的空间是大于零的就将其下标存入原来的数组中,直到统计数组被遍历完,最终可以排好序。

 

代码思路:创建一个临时数组用来存放待排序的数组,如下图所示。创建的数组大小就为待排序的数组的最大值,这样就可以确保将所有数据存入临时数组中,然后开始计数,记录临时数组中每一数字对应的个数(例如1有两个,2有五个)。最后再将其按照大小一一排出形成有序数列 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int Max(int* arr, unsigned int n)
{
	int i = 0;
	int max = 0;
	for (i = 0; i < n; i++)
	{
		if (max < arr[i])
		{
			max = arr[i];
		}
	}
	return max;
}
void counsort(int* arr, unsigned int n)
{
	if (n < 2)
		return;
	int max = Max(arr, n);//获取待排序数组的最大元素的值
	int tmp[max];//临时数组的大小为max
	memset(tmp, 0, sizeof(tmp));//初始化临时数组
	int i, j, k;
	//临时数组计数
	for (i = 0; i < n; i++)
	{
		tmp[arr[i]]++;
	}
	//临时数组计数的内容填到arr中
	i = 0;
	for (j = 0; j < max + 1; j++)
	{
		for (k = 0; k < tmp[j]; k++)
		{
			arr[i++] = j;
		}
	}
}
int main()
{
	int arr[15] = { 44,3,38,5,47,15,36,26,24,2,46,4,19,50,48 };
	counsort(arr, 15);
	for (int i = 0; i < 15; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

桶排序: 

原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,然后再对每个桶分别排序,最后把全部桶的数据合并

代码思路:创建几个桶用来存放数据(10以内为一个桶,10~20为一个桶,以此类推)分别将每个桶用冒泡(其他排序方法也行)进行排序,最后将所有桶排序

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void bucketsort(int *arr,int n)
{
	int bucket[5][5];//分配5个桶
	int bucketsize[5];//每个桶中元素个数的计数器
	//初始化桶和计数器
	memset(bucket, 0, sizeof(bucket));
	memset(bucketsize, 0, sizeof(bucketsize));
	//把数组arr的数据放入桶中
	for (int i = 0; i < n; i++)
	{
		bucket[arr[i] / 10][bucketsize[arr[i] / 10]++] = arr[i];
	}
	//对每个桶进行冒泡排序
	for (int i = 0; i < 5; i++)
	{
		bubblesort(bucket[i], bucketsize[i]);
	}
	//把每个桶的数据填充到数组中
	int k = 0;
	for (int i = 0; i < 5; i++)
	{
		for (int j = 0; j < bucketsize[i]; j++)
		{
			arr[k++] = bucket[i][j];
		}
	}
}
int main()
{
	int arr[15] = { 44,3,38,5,47,15,36,26,24,2,46,4,19,49,48 };
	bucketsort(arr, 15);
	for (int i = 0; i < 15; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小周不摆烂

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

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

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

打赏作者

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

抵扣说明:

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

余额充值