浅谈排序算法

桶排序(BucketSort)

排序过程:

假如我们现在要排序的一组数为:5,3,5,2,8. 这组数都在0-10的范围之内。这个时候,我们可以拿11个桶,标号为0,1,2,3......10。也就是定义长度为11的数组。现在我们来遍历这些数字,第一个数字为5,那么给第五号桶中插一个小红旗,第二个数字为3,给第三号桶插一个小红旗,以此类推。其中,插入一个小红旗代表的是数组元素+1(开始初始化数组元素都为0),遍历完成之后,可以查看所有桶中小红旗的数量,也就是数组中存储元素的个数。发现a[5] = 2,表示5这个数字出现了两次。从0号桶开始,a[0] = 0,表示没有0这个数字,依次遍历到 10就结束了,也就把这些数字从小到大排好了。

当然,如果需要对0-100之间的数进行排序,就需要101个桶,桶的作用就是一个标志。

把标志数组起个名字为book。

写代码思路:

1.把book数组初始化,也就是把里面都写成0

2.把需要排序的一组数放在一个数组里面。

3.循环放入的过程中,对book[i]++。

4.依次判断编号为0~10之间的桶中小红旗的个数,即book[i]的值

5.有n个小红旗(book[i] = n)就打印n次这个数。

代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
//桶排序:对于0~100之间的数排序的时候,这时候需要有101个桶(数组长度为101的数组),插个小旗(加一)用来标记每个数出现的次数。
//然后,看这些桶中(遍历这个数组)小旗的数目(多少个1),有多少只旗(多少个1)就(打印多少次这个数)表示这个桶的标号(数)出现了几次;
int main(){
	int book[11];//先拿11个桶,0~10之间的数进行排序。
	int t = 0;
	for (int i = 0; i < 11; i++)
	{
		book[i] = 0; //初始化数组(把桶清空)
	}
	int n = 0;//要对n个数排序
	printf("请输入需要对几个数进行排序:");
	scanf("%d", &n);//输入n个需要排序的数
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &t);//把数输入到t中
		book[t]++;       //进行计数,第t个桶插加一个旗
	}
	for (int i = 0; i < 11; i++)   //依此判断编号为0~10的桶,(从小到大)。
	{
		for (int j = 0; j < book[i]; j++) //出现几个就打印几次
		{
			printf("%d ", i);
		}
	}
	system("pause");
	return 0;
}

桶排序这种方法存在明显的问题就是占用了太多的空间。假如需要排列的数中有一个10000,那么最少得定义数组长度为10000的数组。

冒泡排序(BubbleSort)

冒泡排序的思想:

每次比较两个相邻的两个数,如果它们的顺序是错误的(要求是从小到大,此时的序列是前面的比后面的大)就把它们进行交换。如果有n个数进行排序,要进行n-1趟操作,而每一趟比较都要从第一个数开始,两两进行比较,将较大的数,放在后面。重复此步骤直到最后一个尚未归位的数,已经归位的数则无需比较。

排序过程:

假设我们现在对12,35,99,18,76这几个数由大到小进行排序。也就是前面的数比后面的大。

把1个位归位成为跑一趟

第一趟:

首先,比较12和35,发现12小于35,那么要交换这两个数。得到35,12,99,18,76.

然后,继续比较第二位和第三位,发现12比99小,交换得到,35,99,12,18,76.

接着,比较第三位和第四位,发现12小于18,交换得到,35,99,18,12,76.

最后,比较第四位和第五位,发现12小于76,交换得到,35,99,18,76,12.

四次比较后,发现最小的数12已经归位。然而这还只是把1个数归位了。接下来归位剩余的四个数。

第二趟:

现在归位第次小的数,跟第一趟过程差不多。

首先,比较35和99,发现小,那么交换之,得到99,35,18,76,12.

···

因为12已经归位了,所以没有必要比较第四位和第五位的大小。

...

这趟完成后,次小的数也已经归位了

第三趟:

···

第四趟:

···

直到得到最后的序列

排序的原理:

如果有n 个数进行排序,只需将n-1 个数归位,也就是说要进行n-1 趟操作。而“每一趟”都需要从第1 位开始进行相邻两个数的比较,将较小的一个数放在后面,比较完毕后向后挪一位继续比较下面两个相邻数的大小,重复此步骤,直到最后一个尚未归位的数,已经归位的数则无需再进行比较.

代码描述:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

int main()
{
	int arr[100];
	int n = 0;//需要对n个数进行排序(从小到大)
	int temp = 0;
	printf("请输入需要对几个数进行排序:");
	scanf("%d", &n);
	for (int i = 0; i < n; i++){
		scanf("%d", &arr[i]);
	}

	//冒泡排序:

	//先分开写:
	////第一趟:
	//for (int i = 0; i < n -1; i++)
	//{
	//	if (arr[i]>arr[i + 1]){
	//		temp = arr[i];
	//		arr[i] = arr[i + 1];
	//		arr[i + 1] = temp;
	//	}
	//}
	////第二趟:
	//for (int i = 0; i < n - 2; i++)
	//{
	//	if (arr[i]>arr[i + 1]){
	//		temp = arr[i];
	//		arr[i] = arr[i + 1];
	//		arr[i + 1] = temp;
	//	}
	//}
	////需要 n-1 趟
	////...
	
	
	//合并起来:
	for (int times = 1; times <= n - 1; times++){
		for (int i = 0; i < n - times; i++){
			if (arr[i]>arr[i + 1]){
				temp = arr[i]; //交换的过程
				arr[i] = arr[i+1];
				arr[i+1] = temp;
			}
		}
	}

	//打印排好序的数组
	for (int i = 0; i < n; i++)
	{
		printf("%d ", arr[i]);
	}
	system("pause");
	return 0;
}

快速排序(QuickSort)

快速排序的过程:

我们对需要排序的序列6 1 2 7 9 3 4 5 10 8 ,首先在这组数中找一个基准数,我们就把第一个数6作为基准数,接下来,需要将这个序列中所有比基准数大的数放在6 的右边,比基准数小的数放在6 的左边。

分别从初始序列“6 1 2 7 9 3 4 5 10 8”两端开始“探测”。先从右往左找一个小于6 的数,再从左往右找一个大于6 的数,然后交换它们。这里可以用两个 变量i 和j,分别指向序列最左边和最右边。

其实哨兵j 的使命就是要找小于基准数的数,而哨兵i 的使命就是要找大于基准数的数,直到i 和j 碰头为止。



此时,基准数6已经归位,左边的序列是3 1 2 5 4 右边的是 9 7 10 8 ,接下来分别处理这两个序列。处理方法跟上述类似。

其实快速排序的每一轮处理都是将这一轮的基准数归位,直到所有的数归位为止。

代码流程:

1.将需要排序的序列放在一个数组中调用排序算法

2.设置哨兵i和j和基准数。

3.哨兵j先走,哨兵j找出小于基准数的值,哨兵i找出大于基准数的数。

4.若i和j没要到则交换这两个数。反之,将基准数归位,即交换arr[i]和基准数。

5.一轮完成后,剩下的就是将左边后右边的序列进行递归调用快速排序方法,直到将所有子序列排列完成为止。

6.输出排好序的数组

代码实现:

#include <stdio.h>
#include <stdlib.h>
//分别从初始序列“6 1 2 7 9 3 4 5 10 8”两端开始“探测”。先从右往左找一个小于6 的数,再从左往右找一个大于6 的数,然后交换它们。这里可以用两个
//变量i 和j,分别指向序列最左边和最右边。

//其实哨兵j 的使命就是要找小于基准数的数,而哨兵i 的使命就是要找大于基准数的数,直到i 和j 碰头为止。

/*快速排序的每一轮处理其实就是将这
一轮的基准数归位,直到所有的数都归位为止,排序就结束了。
*/
void qSort(int left, int right,int arr[])
{
	int i, j, temp, basic;
	if (left > right)
		return;
	i = left;    //哨兵i和j分别指向left和right
	j = right;
	basic = arr[left];//基准数
	while (i != j){
		//哨兵j先走,要有顺序,因为此处设置的基准数是最左边的数
		while (arr[j] >= basic && i < j){//哨兵j的使命就是找出小于基准数的数
			j--;
		}
		while (arr[i] <= basic && i < j){//哨兵i的使命就是找出大于基准数的数
			i++;
		}
		//i和j没遇到,交换着两个值
		if (i < j){
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
	}
	//i和j相遇,将基准值归位.
	//上面有了代码 basic = arr[left]  ,basic这时候就是一个临时变量
	arr[left] = arr[i];
	arr[i] = basic;

	//把基准值归位后就进行 基准值左边和基准值右边部分 的 递归排序
	qSort(left, i - 1, arr);
	qSort(i + 1, right, arr);
}
int main(){
	int arr[] = {6,1,2,7,9,3,4,5,10,8};
	qSort(0,9,arr);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	system("pause");
	return 0;
}

参考书

《啊哈!算法》

原文地址:https://www.cnblogs.com/tfper/p/9831419.html