• 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("
    ");
    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 }
    View Code

    桶排序(基数排序)

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

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

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

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

    实现步骤如下:

    (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】桶排序分析

    桶排序是稳定排序算法。

    桶排序使用范围比较窄。

  • 相关阅读:
    ARCproject中加入非ARC文件,或者非ARC环境中加入ARC文件
    【mybatis】mybatis 查询mysql 长编码的查询使用 正向查询和反向查询,避免数据库关系 递归查询的 解决方案
    【spring data jpa】jpa中使用in查询或删除 在@Query中怎么写 ,报错:org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'goodsConfigUid' cannot be found on null 怎么处理
    【mybatis】 mybatis在mysql 更新update 操作 更新时间字段按照年月日时分秒格式 更新为当前时间
    【spring data jpa】jpa实现update操作 字段有值就更新,没值就用原来的
    【mybatis】mybatis中insert 主键自增和不自增的插入情况【mysql】
    【mybatis】mybatis中update更新原来的值加1
    【mybatis】mybatis 中update 更新操作,null字段不更新,有值才更新
    【spring data jpa】jpa中使用count计数方法
    【mybatis】mybatis方法访问报错:org.apache.ibatis.builder.IncompleteElementException: Could not find result map com.pisen.cloud.luna.ms.goods.base.domain.GoodsConfigQuery
  • 原文地址:https://www.cnblogs.com/xiaochi/p/8511836.html
Copyright © 2020-2023  润新知