zoukankan      html  css  js  c++  java
  • 浅谈排序算法

    桶排序(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;
    }
    

    参考书

    《啊哈!算法》

  • 相关阅读:
    Java实现 LeetCode 211 添加与搜索单词
    跨平台Unicode与UTF8互转代码
    C++转换unicode utf-8 gb2312编码
    c++ ANSI、UNICODE、UTF8互转
    Visual C++ unicode and utf8 转换
    Unicode和UTF-8的关系
    boost uuid 学习笔记
    boost uuid
    Darwin Streaming server 的 Task 类
    VS2010下编译安装DarwinStreamingServer5.5.5
  • 原文地址:https://www.cnblogs.com/tfper/p/9831419.html
Copyright © 2011-2022 走看看