算法学习小结 排序(1)

1.桶排序

 桶排序从字面上来理解就与桶子有关,而桶子的作用就是装东西,用个题目来理解。

  例1:将0到1000中的n个数按从小到大排列(要求多组输入)。

第一行输入n,表示n个数

10

 第二行输入要排列的数字

45 556 12 2 548 0 74 56 956  20

 思路:桶排序就是将数字放入特定的桶子里面,按照桶子的顺序输出。

像这一道题要排列n个数,而且数字要1000以内。定义一个数组当作桶子,数组可得下标要可以到1000,数组要初始为0。当输入一个数字时,以这个数字为下标的数组就加1,就像念到一个数字就往贴有这个数字标签的桶子中放入一个小球。

输出时,就从小到大将装有小球的桶子上的标签输出,即将不为0的数组的下标输出。同时还要注意有的数字不止有一个的情况,要循环输出。

//桶排序
#include <stdio.h>
int main() {
	int n, i, j, x;
	int sz[1001] = {0};                  //定义一个数组且初始化为0;
	while (scanf("%d", &n) != EOF) {
		for (i = 1; i <= n; i++) {
			scanf("%d", &x);                 //输入n个数字
			sz[x]++;                         //将输入的数作为数组下标
		}
		for (i = 1; i <= 1000; i++) {        //从小到大找到输入的数
			for (j = 1; j <= sz[i]; j++)     //同一个数字的次数
				printf("%d ", i);
		}
	}
}

基本原理    对号入座

缺点:   浪费空间

2.快速排序

快速排序最重要的是要找一个基准数(即一个用作参考的数)

例2:对十个整型数进行排序(从小到大)

第一行输入十个整数

6 1 5 44 9 86 2 3 9 20

思路:对于快速排序,要用到二分的思想。                                                                                    像这题,找到一个基准数,这里就直接用第一个数6作为基准数了。我们需要根据基准数,将数分为两份,一份小于6,另一份大于6。把这两份数分别放于6的两侧,具体放于哪一侧需要参考我们的目的,是从小到大,还是从大到小。    这里是从小到大,比基准数6小的就放在6的左边,大的就放在基准数的右边。为了方便,就分别从最左和最右开始,将数与基准数进行比较。

先定义一个  i  放在数组最左边,一个  j  放在数组的最右边。   

   

之后,让  i  和   j  分别从最左和最右开始移动,一定要让  j  先开始移动( j - -),一直到  j  所在的数字小于基准数6停止,然后  i  再行动( i++)一直到   i  所在的数字大于6停止,交换  i 所在的数和  j  所在的数。

 

 同样的是  j  先动,i  再动,停下的条件不变。

 

 然后继续,直到  i  与  j  相遇,这时就要将  i 和  j 所在位置与基准数位置交换,第一轮排序结束。

 第二轮和第一轮一样,只是序列变成了以6为分界的左右两列,再对两个序列重复上述步骤            依旧以每个序列的第一个数为基准数,同样定义个  i  和  j  。记住一定要先从与基准数相反的方向开始。

 

 这是第二趟,之后又分成了几个序列,同样的方法,直到完全排序好。

#include <stdio.h>
int num[101];//定义一个全局变量,子函数和main函数中都可以使用

//定义函数进行快速排序(从小到大)
void quick(int left, int right) {
	int i, j;
	int base= num[left];//基准数

	if (left > right)
		return;

	i = left;
	j = right;

	while (i != j) {
		//先从右到左
		while ( num[j] >= base && i < j)
			j--;
		//再从左到右
		while (num[i] <= base && i < j)
			i++;

		//交换i和j所在位置的数,这时i和j还没相等
		if (i < j) {
			int temp = num[i];
			num[i] = num[j];
			num[j] = temp;
		}
	}

		//直到i与j相等,将其位置的数与基准数交换
		num[left] = num[i];
		num[i] = base;

		//之后又有序列,对其重复上述步骤
		//这里i和j已经相等
		quick(left, i - 1);  //对基准数左边的序列,这是递归过程
		quick(i + 1, right); //对基准数右边的序列
		return;
}


int main() {
	for (int i = 1; i <= 10; i++)
		scanf("%d", &num[i]);
		
	quick(1, 10);   //调用快速排序函数
	
	//输出
	printf("排列好的数组:");
	for (int i = 1; i <= 10; i++)
		printf("%d ", num[i]);
	return 0;
}

注意:为什么要从基准数相反的方向开始呢?                                                                                    就如上面排雷 2  1  5  3,基准数为2。如果我们先从左边开始,i  一直到5停止,而 j  也是到5停止,这样就只有交换2 和 5 的位置了,并不能达到排序的目的。

 

如果从右边开始的话,就不会有这种情况。 

                                                                                                                    

3.冒泡排序

   冒泡就是气泡在水中一样向上冒出,数字在数组中向后移动。

例3:将n个整型数按从大到小排列

第一行输入n,表示n个数                                                                                                                       第二行输入要排序的数

5

56 812 421 2 2545

 思路: 这5个数字需要一个数组储存,先将这5个数按从大到小排序,就是说数字越小,位置就越靠后。冒泡排序要我们先将最前面的两个数字进行比较,数字小的就后移。

56与812比较,56小,位置后移;56与421比较,56小,位置后移;56与2比较,2小,位置不变;

2与2545比较,2小位置后移。这样最小的2,就到了数组的最后了。

排列后的数组就是  812   421  56   2545   2。这还只是第一趟。第二趟的方法跟刚刚一样,相邻的两个数字进行比较,排列出来是  812   421  2545  56  2;一共有五个数字,所以要进行四趟比较的循环。最后结果为:2545  812  421  56  2。                                                                                

而要将数组按从小到大的顺序排列 的话,只要比较相邻两个数字谁大,将大的后移就行。

#include <stdio.h>
void big(int q, int x[10001]);

int main() {
	int a[10001];
	int n;
	scanf("%d", &n);                        //输入n,表n个数
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	big(n, a);
}

//从大到小
void big(int q, int x[10001]) {
	for (int i = 1; i <= q - 1; i++) {       //需要循环的趟数
		for (int j = 1; j <= q - i; j++) {   //每一趟要两两对比的次数
			if (x[j] < x[j + 1]) {
				int temp = x[j];
				x[j] = x[j + 1];
				x[j + 1] = temp;
			}
		}
	}
	printf("排列好的数:");
	for (int i = 1; i <= q; i++)
		printf("%d ", x[i]);
}

基本原理:双重嵌套循环,两两对比

缺点:对于较多的数,时间复杂度高

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值