十种排序算法(C语言实现)(冒泡、基数、归并、快排、希尔、桶排序,基数/基数、选择、插入)的代码实现及其原理

1 篇文章 0 订阅
1 篇文章 0 订阅
                **一次性实现所有排序的思想**

冒泡排序、插入排序、选择排序、快速排序、
希尔排序,归并排序、计数排序、基数排序、
桶排序、堆排序
升序排序******
一次全部解决,代码中的注释非常清楚,主函数中释放对应排序方式的 // 就执行对应排序,所有被调函数都不释放就是原本的顺序,使用的软件是VS2019。

放几张图片先。
在这里插入图片描述
在这里插入图片描述

//冒泡排序、快排、插入排序、选择排序、希尔排序、归并排序、堆排序、基数排序、桶排序、计数排序
//以下排序均为升序排序
//时间复杂度的对比
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 10    //数组中数字个数,暂定10
#define M 50   //数组最大范围的定义
#define GREAT 10000    //Great 代表N个数字当中的最大值比Great小
int main();
int bubbling(int*);//冒泡排序  o(n^n)
int insert(int*);//插入排序     o(n^n)
int select(int*);//选择排序      o(n^n)
int fast(int*,int ,int);//快排    o(nlog^n)
int shell(int*);   //希尔排序     o(nlog^2n)
int merge_sort(int* ,int, int);   //归并排序   o(nlog^n)
int base(int*);  //基数排序          o(n)
int bucket(int*);  //桶排序(计数排序)   o(n)
int heap(int*, int,int); void build_sortheapify(int *);  //堆排序         o(nlog^n)

int main()
{                                                       //数组中元素数值大小不得大于10000
	int arrary[] = { 134,54,342,99,88,45,200,87,99,165 };//数字数组大小必须与N一致
	int newarrary[M];
	int i;
	printf("原数组为:\t      ");
	for (i = 0; i < 10; i++)
		printf("%4d", arrary[i]);
	printf("\n\n");
//***************函数调用区******************************
	//bubbling(arrary);
	//insert(arrary); 
	//select(arrary);
	//fast(arrary, 0, N-1);  
	//shell(arrary);
	//merge_sort(arrary,0,N);   
	//base(arrary);
	//bucket(arrary);
	//build_sortheapify(arrary);
//*******************************************************
	for (i = 0; i < N; i++)
		newarrary[i] = arrary[i];
		printf("指定方式排序之后为:  ");
		for (i = 0; i < N; i++)
		{
			printf("%4d", newarrary[i]);
		}
	return 0;
}

int bubbling(int* arrary)//冒泡排序
{
	int i, j, change = 0;
	for(i=1;i<N;i++)   //i从第二个元素开始进行n-1次循环
		//i也可以从0开始循环,但是后面的查找就要变为j-1和j,j从i开始
		for (j = 0; j < N-i; j++)//遍历循环
			//第一次排序外层i为1,内层循环9次依次比较相邻两个元素的大小,依次将较大者放在最后
			//最后放在了j+1==8+1==9,即是数组最后一个元素,当走完这次内层循环之后
			//最后一个元素已经是当前最大,那么,下一次排序将不再考虑他,
			//如何实现呢?这就是外层循环(从1开始自加的作用,因为j+1的原因),
			//下一次开始10就-2了,最后一个元素放在第八个位置,依次类推,
			//直到i=9;10-i==1,内层就不会再循环,跳出for()for(),排序成功!
		{
			if (arrary[j] > arrary[j + 1])//如果不满足要求的较小的值在前面,就执行以下操作实现change
			{
				change = arrary[j]; arrary[j] = arrary[j + 1]; arrary[j + 1] = change;
			}
			//先把较大的arrary[j]的值暂时放在change中,将较小的arrary[j+1]赋值给arrary[j]
			//再把change中存放的较大的值赋值给arrary[j+1]
		}
	return arrary[M];
}

int insert(int* arrary)//插入排序
//思路如下:从第二个元素开始,将他和前一个对比,排序,然后,后面2和3、3和4
//比如第三个开始插入排序,若是比第二个大,就不懂,若是小,往前挪动一个位置,然乎前一个后移一个位置
//循环条件是i>0,知道插入的元素比前一个大,就结束本轮插入
{
	int i, j;
	int temp;//临时放置数据的变量
	for(i=1;i<N;i++)
		if (arrary[i] < arrary[i - 1])
			//这里注意,if是用来做判断的,while是用来做循环的
			//if不会回过头来执行当前if结构体,while会回过头来执行当前结构体,直到条件不成立
		{
			temp = arrary[i];  //temp就是要插入的元素值
			j = i;      //记录当前最后一个元素的位置
			while (j > 0 &&temp<arrary[j-1])
			{
				arrary[j] = arrary[j - 1];
				j--;
			}
			arrary[j] = temp;    //在插入循环停下来的位置,把temp的值给当前位置的数组
		}
	return arrary[M];
}

int select(int* arrary)//选择排序
{
	int i, j;
	int min,temp;
	//思路是将当前最小元素放在最后,然后和当前第一个元素交换
	for (i = 0; i < N - 1; i++)
	{
		min = i;     //从第一个元素至倒数第二个元素,每次记录当前位置为min找到当前min后change
		for (j = i + 1; j < N; j++)  //从i的下一个元素开始
		{
			if (arrary[min] > arrary[j])  min = j; //又发现比min小的,就重置min的数据与位置
			//发现有比min还小的就把他的位置给min,方便后面找最小元素
			//此循环的目的发现比min所在位置小的元素就让当前位置位置元素是min所在位置元素
			//依次找出当前最小元素
		}
		if (i != min)
		{
			temp = arrary[i];
			arrary[i] = arrary[min];
			arrary[min] = temp;
		}   //如果i比之后的元素都小,就不执行交换,因为他就是当前最小元素
		//该过程是将拍好的当前min所在位置的最小元素放在当前i所在位置,i从左往右走
	}
	
	return arrary[M];
}

int fast(int* arrary, int begin, int end)//快速排序
//思路就是将第一个元素放置在他该放的位置,左边全是比他小的元素,右边全是比他大的元素,然后用递推放置其他元素
{
	if (begin > end)
		return 0;
	int t;
	int temp = arrary[begin];   //将基数begin暂时存在temp中
	int i = begin;
	int j = end;
	while (j > i)
	{
		while (arrary[j] >= temp)  //这里是必须等于,不然数组中出现相同元素时候就会出错
			j--;  
		if (arrary[j] < temp&&i<j)
		{

			t = arrary[j];
			arrary[j] = arrary[i];
			arrary[i] = t;
		}


		while (arrary[i] <= temp&&i<j)  //这里是必须等于,不然数组中出现相同元素时候就会出错
			i++;       
		if (arrary[i] > temp)
		{

			t = arrary[i];
			arrary[i] = arrary[j];
			arrary[j] = t;
		}
	}
		fast(arrary, begin, i-1);  //递归排序左半边
		fast(arrary, i+1, end);   //递归排序右半边   
}

int shell(int* arrary)//希尔排序
{              //随着分组越来越细,数组越来越趋近于正确排序
	int i,j,temp,k,gap;   //定义分组最大间隔gap
	for (gap = 3; gap > 0; gap--)  //每组分组间隔逐渐缩小
	{
		for (i = 0; i < gap; i++)      //这里遍历第一个点和第一个间隔点之间的元素,之后+gap就是每组对应元素
		{
			for (j = i + gap; j < N; j += gap)     //这个for当中的每个j对应元素为一组
			{
				if (arrary[j] < arrary[j - gap])        //对每组元素进行插入排序
				{
					temp = arrary[j];      //temp就是要插入的元素
					k = j - gap;         //k是每组中j前一个元素
					while (k > 0 && arrary[k] > temp)
					{
						arrary[k + gap] = arrary[k]; //arrary[k]较大的话,将其在组中后移一个单位
						k=k-gap;     //继续在该组中前移比较能否插入
					}//结束时候停下来,不满足了,不会继续循环,但是k已经-了gap,就该+上gap才是该插入的位置
					arrary[k + gap] = temp;     //将temp插入当前轮次属于他的位置
				}
			}
		}
	}          //第170到179行代码实则就是插入排序
	return arrary[M];
}

int merge_sort(int* arrary, int start, int end)//归并排序
{                    //传进来的end是字符串长度
	if (end == start+1)       //当只有两个元素,再次二分之后退出递推
	{
		return 0;
	}
	int mid = start+(end - start) / 2;
	merge_sort(arrary, start, mid);
	merge_sort(arrary, mid , end);  //每一次都二分
	int i = start;
	int j = mid;
	int k = 0;
	int temp[N];           //以下为合并
	for (; i < mid && j < end;)
	{
		if (arrary[i] < arrary[j])
		{
			temp[k++] = arrary[i++];
		}   //找到下的就先放然后挪动位置,然后两个二分区域各自位置比较,小的放到temp,
		   //直到二分中的一个归置完  
		else
		{
			temp[k++] = arrary[j++];
		}
	}   //然后将未排完的半区直接放在temp剩余位置,都满了,就不执行后面的两个while
	   //在每个分区拍好后合并,所以每次的分区其实都是排好了顺序的
	if (i < mid)   //做判断
	{                 //说明右边赋值完毕,左边有剩余
		while (i < mid) //做循环
		{
			temp[k++] = arrary[i++];
		}
	}
	if (j < end)   //做判断
	{                 //说明左边边赋值完毕,右边边有剩余
		while (j < end) //做循环
		{
			temp[k++] = arrary[j++];
		}
	}
	//两个while最多只会执行一个
	for (i = 0; i < end-start; i++)
	{
		arrary[i+start] = temp[i];
	}
}

int base(int* arrary)//基数排序
{   //思想是从个位开始,按照个位大小排序,然后十位---直到当前最大位
	//数组长度是N,最大数字是max,max的位数是bit
	int i, max = 0,base=1;
	for (i = 0; i < N; i++)
	{
		if (arrary[i] > max)
			max = arrary[i];
	}            //找到了最大数max
	int* t = (int*)malloc(sizeof(int) * N);
	while (max / base > 0)
	{
		int bucket[N] = { 0 };
		for (i = 0; i < N; i++)
		{                  //计算每个桶里面数字的个数
			bucket[arrary[i] / base % 10]++; //依次从个位开始得到每一位的数字,每次之后桶往后挪动      
			//对应位的数字是多少就放在几号桶,找到当前位数对应桶,当前桶++;最后得到当前桶数字个数
		}
		for (i = 1; i < N; i++)
		{
			bucket[i] += bucket[i - 1];  //累加,计算i个桶及其之前桶内数字个数的总和
		}
		for (i = N - 1; i >= 0; i--)
		{                                              //这里用开辟了空间的t[]来存放
			int position = arrary[i] / base % 10;     //position是几号桶
			t[bucket[position] - 1] = arrary[i];     //bucket[position]就是他的当前位数数字大小排在第几位,
			bucket[position]--;
		}                                           //对应数组下标就是bucket[position]-1
		for (i = 0; i < N; i++)
		{
			arrary[i] = t[i];
		}
		base *= 10;
	}
	return arrary[M];
}

int bucket(int* arrary)//桶排序
{
	int i, k;
	int b[GREAT];    //b的下标就是arrary元素大小,所以数组大小可以尽量大
	memset(b, 0, sizeof(b));     //使用b数组之前清空他
	for (i = 0; i < N; i++)
	{
		k = arrary[i]; //依次把数组元素给k
		b[k]++;   //然后arrary数组元素的大小就是b的下标,++的作用是记录当前下标数组元素个数
	}                 //也就是相同的数字的个数,至少有一个,后面方便判断;
	//实际上,就把数值转换为了下表,就已经排好了序
	int j = 0;
	for (i = 0; i < GREAT; i++)
		while (b[i] > 0)      //后面有b[i]--会while循环b[i]次重复输出相同的数字
		{
			arrary[j++] = i;       //返回给arrary
			b[i]--;
		}
	return arrary[M];
}

int heap(int* arrary,int n, int i)//堆排序,n是当前数组元素个数
{                            //就是建立子树节点
	//父节点是(i-1)/2
	if (i >= n)
	{
		return 0;
	}

	int c1 = 2 * i + 1;
	int c2 = 2 * i + 2;
	//这两个是子节点
	int max = i;
	if (c1<n && arrary[c1]>arrary[max])
	{
		max = c1;
	}
	if (c2<n && arrary[c2]>arrary[max])
	{
		max = c2;
	}
	if (max != i)
	{
		int t;
		t = arrary[max];
		arrary[max] = arrary[i];
		arrary[i] = t;
		heap(arrary,n, max);
	}
}
void build_sortheapify(int *arrary)
{
	int last = N-1;
	int parent = (last - 1) / 2;  //last,parent都是指的下标
	int j;
	for (j = parent; j >= 0; j--)
	{
		heap(arrary,N, j);
	}   //至此构建好了子树结点
	int k;
	for (k = N - 1; k >= 0; k--)
	{
		int m;
		m = arrary[k];
		arrary[k] = arrary[0];
		arrary[0] = m;
		heap(arrary, k, 0);  
		//每次将最后一个结点和arrary[0]change,应为arrary[0]heap之后就是当前最大值
		//然后砍掉最后一个元素,所以数组要变短所以数组长度要是k
	}
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值