24.C语言最全排序方法小结(不断更新)

希尔排序:

该方法的基本思想是:先将整个待排元素序列切割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。

由于直接插入排序在元素基本有序的情况下(接近最好情况),效率是非常高的,因此希尔排序在时间效率上比前两种方法有较大提高。

以n=10的一个数组49, 38, 65, 97, 26, 13, 27, 49, 55, 4为例

第一次 gap = 10 / 2 = 5

49   38   65   97   26   13   27   49   55   4

1A                                        1B

2A                                         2B

3A                                         3B

4A                                          4B

5A                                         5B

1A,1B,2A,2B等为分组标记,数字同样的表示在同一组,大写字母表示是该组的第几个元素, 每次对同一组的数据进行直接插入排序。

即分成了五组(49, 13) (38, 27) (65, 49)  (97, 55)  (26, 4)这样每组排序后就变成了(13, 49)  (27, 38)  (49, 65)  (55, 97)  (4, 26),下同。

第二次 gap = 5 / 2 = 2

排序后

13   27   49   55   4    49   38   65   97   26

1A             1B             1C              1D            1E

2A               2B             2C             2D              2E

第三次 gap = 2 / 2 = 1

4   26   13   27   38    49   49   55   97   65

1A   1B     1C    1D    1E      1F     1G    1H     1I     1J

第四次 gap = 1 / 2 = 0 排序完毕得到数组:

4   13   26   27   38    49   49   55   65   97

以下给出严格依照定义来写的希尔排序:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3
 4 void show(int *p, int length)
 5 {
 6     for (int i = 0; i < length; i++)
 7     {
 8         printf("%4d", p[i]);
 9     }
10     printf("\n");
11 }
12
13 void shellsort(int *p, int length)
14 {
15     int d = length / 2;//增量
16     while (d >= 1)
17     {
18         //从后往前推
19         for (int i = d;d<length && i<length; i++)
20         {
21             int x = p[i];//备份当前数据
22             int j = i - d;//前面一个元素
23
24             //在数组范围内,找到插入的位置,如果大则把大的赋给后面,j一直是前一个位置
25             while (j >= 0 && p[j] > x)
26             {
27                 p[j + d] = p[j];
28                 j = j - d;
29             }
30             //所以这里要加d
31             p[j + d] = x;
32         }
33         d /= 2;//增量变化
34     }
35 }
36
37 void main()
38 {
39     int a[10] = { 49 ,  38  , 65   ,97   ,26  , 13,   27  , 49  , 55 ,  4 };
40     show(a, 10);
41     shellsort(a, 10);
42     show(a, 10);
43     system("pause");
44 }



桶排序(基数排序)

桶排序(也称箱排序),据坊间演绎,其实现方式有很多。

在此我们仅仅阐述一下本文的实现思想,以便于更好的理解下面的内容,同时加深对桶排序的认识。

首先,说明一点,我们是使用数组模拟桶(最好应该是使用链表模拟)。

所谓数组模拟桶实现排序的过程到底是怎么进行的呢?呵呵!其实还真有点抽象。

实现步骤如下:

(1)定义映射函数

<1>求得欲排数据序列中的最大数据。

<2>通过遍历欲排数据对每个数据乘以10再与最大数据取余,求得每个数据对应桶的索引(或称关键字)。

(2)求得每个桶中盛放的数据个数(为了保证随后准确分配数据)

(3)求得每个桶盛放数据个数的右边界索引(所谓的桶逻辑控制)

(4)从右向左(确保稳定性)扫描欲排数据序列,依次分配到对应桶中

(5)对各桶中所盛数据进行收集

(6)利用插入排序再对各个桶中所盛数据进行排序

(7)直至排序结束,即为已排序数据序列

其实,整个过程再讲通俗一点,可以如下描述:

建立一个数组作为我们的所谓的桶(逻辑桶)

然后,申请开辟与欲排数据所占空间相同的内存,作为真正的盛放数据的桶(物理桶)

数组的索引默认为桶号

对数组的每一次赋值都有着不同的意义(请参考代码分析)

最后再用插入排序对各桶中所收集数据分别进行排序。即完成桶排序。

总而言之:先分类,后收集,再排序。

【2】示例代码及其分析过程

(1)代码如下:

  1 #include<iostream>
  2 #include<malloc.h>
  3 using namespace std;
  4
  5
  6 void  PrintArr(int ar[],int n)
  7 {
  8     for(int i = 0; i < n; ++i)
  9         cout<<ar[i]<<" ";
 10     cout<<endl;
 11 }
 12
 13 int MapToIndex(int x,int max)
 14 {
 15     return (10 * x) / max;
 16 }
 17
 18 void insertion_sort(int arr[],int begin,int end)
 19 {
 20     for(int i = begin+1; i <= end; ++i)
 21     {
 22         int v = arr[i];
 23         int j = i;
 24         while(j-1 >= begin && v<arr[j-1])
 25         {
 26             arr[j--] = arr[j-1];
 27         }
 28         arr[j] = v;
 29     }
 30 }
 31
 32 void bucket_sort(int ar[], int begin, int end)
 33 {
 34
 35     const int radix = 11 ;  //注意:为什么是11?
 36     int count[radix], i, j;
 37     int size = end-begin+1;
 38
 39     //计数值置空
 40     for(i = 0; i < radix; ++i)
 41     {
 42         count[i] = 0;    //置空
 43     }
 44
 45     //end-begin+1 = 9 - 0 + 1 = 10
 46     int *Temp = (int *) malloc((size) * sizeof(int));     //分配临时空间
 47
 48     //取得当前待排序数据中的最大数据
 49     int max = 0;
 50     for(i = begin; i < size; ++i)
 51     {
 52         if(ar[i] > max)
 53             max = ar[i];
 54     }
 55
 56     //统计各桶需要装的元素的个数
 57     for(i = begin; i < size; ++i)
 58     {
 59         count[MapToIndex(ar[i], max)]++;
 60     }
 61
 62     //输出计数结果:
 63     PrintArr(count, radix);
 64
 65     //求出桶的边界索引,count[i]为第i个桶的右边界索引+1
 66     for(i = 1; i < radix; ++i)
 67     {
 68         count[i] = count[i] + count[i-1];
 69     }
 70
 71     //输出桶边界索引
 72     PrintArr(count, radix);
 73
 74     //从右向左扫描,保证排序稳定性
 75     for(i = end; i >= begin; --i)
 76     {
 77         j = MapToIndex(ar[i], max);
 78         Temp[count[j]-1] = ar[i];  //放入对应的空间中,count[j]-1是第j个桶的右边界索引
 79         --count[j];       //准备放置下一个元素的位置索引
 80     }
 81
 82     for(int i = 0; i < size; ++i)
 83     {
 84         cout<<Temp[i]<<"  ";
 85     }
 86     cout<<endl;
 87
 88     PrintArr(count, radix);
 89
 90     //从各个桶中收集数据
 91     for(i = begin, j = 0; i < size; i++, j++)
 92     {
 93         ar[i] = Temp[j];
 94     }
 95
 96     PrintArr(ar, end+1);
 97
 98      //释放空间
 99     free(Temp);
100
101     for(i = 0; i < size; i++)
102     {
103         int index1 = begin + count[i];             //得到第i个桶的左边界
104         int index2 = begin + count[i+1] - 1;       //得到第i个桶的右边界
105         if(index1 < index2)
106             insertion_sort(ar, index1, index2);
107     }
108 }
109
110 void  main()
111 {
112     int  ar[] = {12, 14, 54, 5, 6, 3, 9, 8, 47, 89};
113     int len = sizeof(ar)/sizeof(int);
114     bucket_sort(ar, 0, len-1);
115     PrintArr(ar, len);
116 }
117 /*
118 4 3 0 0 0 1 1 0 0 0 1
119 4 7 7 7 7 8 9 9 9 9 10
120 5  6  3  8  12  14  9  47  54  89
121 0 4 7 7 7 7 8 9 9 9 9
122 5 6 3 8 12 14 9 47 54 89
123 3 5 6 8 9 12 14 47 54 89
124 */

(2)分析过程如下:

学过数据结构的估计都可以想象得到:桶排序中所谓的桶应该是用一个单链表实现

因为,我们一直觉得,计算机世界就是对现实世界的模拟。那么,既然是山寨,当然越逼真越好

但是,假如我们没有学习过单链表,脑子里面根本没有单链表的概念。而且,我们要实现桶排序。

好吧!我唯一可以借助的就是数组。

不过数组模拟桶实现桶排序的确不是很好理解,有几分抽象

上面这就是一个用数组模拟桶实现的桶排序示例代码,现在做一下具体分析,希望可以更深刻理解桶排序。

分析过程如下:

(1)待排序数据序列为:

(2)count数组本质上是逻辑的桶,为什么说是逻辑上的桶?因为,它控制着桶的所有数据逻辑

但是申请的内存Temp才是每个桶的真正储存空间,所以只能说是逻辑上的桶。

而当数据被分配到各个桶中又从桶(即就是从申请空间)被收集之后,就对申请空间进行释放(因为留着再没有必要)。

如何理解以上内容?请结合一下图示理解具体分析:

第一行:所建桶的索引(可以看到总共为11个桶)

为什么是11个桶?由我们在对待排数据求输入桶对应的索引时匹配函数(MapToIndex)决定。

由于最大数据输入匹配函数后所得桶对应索引为10。所以,在此必须如此设计。

第二行:所有桶置空

第三行:每个桶中待盛的数据个数

第四行:每个桶的右边界索引

如何理解右边界索引?

比如0号桶,第三行已经得出其待盛四个数据,那么将来数据就会存入Temp[0],Temp[1],Temp[2],Temp[3]

比如1号桶,第三行已经得出其待盛三个数据,那么将来数据就会存入Temp[4],Temp[5],Temp[6]

第五行:待排数据全部放入各个桶中后,桶的左边界索引(这个是为了下面插入排序使用)。

(3)对每一个桶(即就是申请空间)中所盛的数据再利用插入排序进行排序

(4)数组中的数据即为已排序序列

【3】桶排序分析

桶排序是稳定排序算法。

桶排序使用范围比较窄。

原文地址:https://www.cnblogs.com/xiaochi/p/8511836.html

时间: 2024-10-13 20:23:17

24.C语言最全排序方法小结(不断更新)的相关文章

C语言常见的排序方法——冒泡法、选择法、插入法

当我们要对C中一组数据进行排序是常见的排序方法有冒泡法.选择法.插入法 冒泡排序法(升序):假设一组数据a[0].a[1].a[2].a[3]...a[n],第一轮:先比较a[0]与a[1].a[1]与a[2]...a[i]与a[i+1]...a[n-1]与a[n]的大小,如果a[i]与a[i+1]不是升序(即a[i] > a[i+1]),那么就将a[i]与a[i+1]的值互换,第一轮过后,a[n]就是最大值:第二轮:运用第一轮同样的方法,比较a[0]与a[1].a[1]与a[2]...a[i]

Linux中查看磁盘大小、文件大小、排序方法小结

一,查看磁盘空间大小的命令:dfdf命令用于查看磁盘分区上的磁盘空间,包括使用了多少,还剩多少,默认单位是KB 比如以下命令: df -hl执行结果如下: 执行的结果每列的含义: 第一列Filesystem,磁盘分区 第二列Size,磁盘分区的大小 第三列Used,已使用的空间 第四列Avail,可用的空间 第五列Use%,已使用的百分比 第六列Mounted on,挂载点 解释一下后面的h和l参数,h是把显示的单位改成容易辨认的单位,不再是默认的KB了,而l参数表示只显示本地磁盘分区,不包含的

C语言中常见的排序方法

在C语言中,常见的排序方法有冒泡法,排序法,插入法等等.所谓的冒泡法,就是对一组数字进行从大到小或者从小到大的一种排序方法.主要就是相邻的数值相互交换.从第一个数值开始,如果这相邻的两个数值排序与我们希望的排序位置不同时,那么就将两个数的位置进行交换.如果一致,就不用交换.一直重复这个过程,直到没有数值需要交换为止,则排序完成.下面是将10个学生的成绩用冒泡法按顺序排列的做法: 1 #include<stdio.h> 2 int main() 3 { 4 int i; 5 int arr[10

三种排序方法(c语言)

1 #include "stdio.h" 2 void main() 3 {void read_data(int a[],int n); 4 void write_data(int a[],int n); 5 void comp(int a[],int n); 6 void insert(int a[],int n); 7 void bubble(int a[],int n); 8 int i,n=0,a[200]; 9 printf("请输入元素个数:"); 10

经典排序方法及细节小结(1)

在数据结构的学习中,排序是我们要重点学习的一部分:在掌握几种经典排序算法的同时,我们还要能够根据实际中遇到的情况,结合它们的时间复杂度.空间复杂度.稳定性这几个方面选择最合适的算法.现针对常用的几种经典排序算法和容易出错的细节总结一下: 1.插入排序 (1)直接插入排序 直接插入排序是一种最简单的排序方法,其基本思路是: ①将一条记录插入到已排好的有序表中,从而得到一个大小加1的新有序表. ②每一步将一个待排序的数据元素,按其排序码的大小,插入到前面已经排好序的一组元素的合适位置上去 ③循环①②

Sql server2005 优化查询速度50个方法小结

Sql server2005 优化查询速度50个方法小结 Sql server2005优化查询速度51法查询速度慢的原因很多,常见如下几种,大家可以参考下. I/O吞吐量小,形成了瓶颈效应.  没有创建计算列导致查询不优化.  内存不足.  网络速度慢.  查询出的数据量过大(可以采用多次查询,其他的方法降低数据量).  锁或者死锁(这也是查询慢最常见的问题,是程序设计的缺陷).  sp_lock,sp_who,活动的用户查看,原因是读写竞争资源.  返回了不必要的行和列.  查询语句不好,没有

常用排序算法小结

1 #include <stdio.h> 2 #include <stdlib.h> 3 4 5 //the basic bubble sort 6 void maopao1(int *num,int len) 7 { 8 int i,j; 9 int temp; 10 for (i = 0; i < len-1; ++i) 11 { 12 for (j = i+1; j<len; ++j) 13 { 14 if (num[i]>num[j]) 15 { 16 t

深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)

最近看了一下java 8的一些新特性,其中最重要的莫过于Lambda表达式了,通过一阵子的学习,原本准备自己写一篇博客的,后来阅读了一位学长翻译过来的博客(原文是Brain Goetz的State of Lambda,下面会给出原文链接),觉得写的十分完美,把我想要写的和我没想到的都罗列了出来,就把这个分享给大家了. 注:原译文见  http://lucida.me/blog/java-8-lambdas-insideout-language-features/ 英语原版见:http://cr.

全排序的两种想法

字典序全排序: 1 import java.util.Arrays; 2 import java.util.Scanner; 3 public class Cao41 { 4 /** 5 * @param 第一行输入个数N,第二行输入序列1-9, 6 * 输出字典序排列 具体做法如下: 首先要将数组a从小到大排序,输出第一个排序,然后进入循环 先用getindex方法找到最靠后的,后面有比啊a[index]大的index,当index不存在设index=-1,结束循环. 然后从 index到en