zoukankan      html  css  js  c++  java
  • 七种排序算法总结(冒泡、插入、选择、希尔、归并、堆、快速)

    首先声明一下,本文只对七种排序算法做简单总结,并参照一些资料给出自己的代码实现,并没有对某种算法理论讲解,更详细的

    解可以参考以下资料(本人参考):

    1、《data structure and algorithm analysis in c 》

    2、《大话数据结构》

    3、http://blog.csdn.net/morewindows/article/details/7961256


    一、冒泡排序

    基本思想是:两两比较相邻记录的关键字,如果反序则交换

    冒泡排序时间复杂度最好的情况为O(n),最坏的情况是O(n^2) 

    改进思路1:设置标志位,明显如果有一趟没有发生交换(flag = false),说明排序已经完成

    改进思路2:记录一轮下来标记的最后位置,下次从头部遍历到这个位置就Ok


    二、直接插入排序

    将一个记录插入到已经排好序的有序表中, 从而得到一个新的,记录数增1的有序表 

    时间复杂度也为O(n^2), 比冒泡法和选择排序的性能要更好一些


    三、简单选择排序

    通过n-i次关键字之间的比较,从n-i+1 个记录中选择关键字最小的记录,并和第i(1<=i<=n)个记录交换之

     尽管与冒泡排序同为O(n^2),但简单选择排序的性能要略优于冒泡排序


    四、希尔排序

    先将整个待排元素序列分割成若干子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排

    序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。其时间复杂度为O(n^3/2),要好于直接

    插入排序的O(n^2)


    五、归并排序

    假设初始序列含有n个记录,则可以看成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到(不小于n/2的最小整数)个长度为2

    或1的有序子序列,再两两归并,...如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序。 时间复杂度为

    O(nlogn),空间复杂度为O(n+logn),如果非递归实现归并,则避免了递归时深度为logn的栈空间 空间复杂度为O(n)


    六、堆排序

    堆是具有下列性质的完全二叉树:每个节点的值都大于或等于其左右孩子节点的值,称为大顶堆;或者每个节点的值都小于或等于其左

    右孩子节点的值,称为小顶堆。


    堆排序就是利用堆进行排序的方法.基本思想是:将待排序的序列构造成一个大顶堆.此时,整个序列的最大值就是堆顶 的根结点.将它移

    走(其实就是将其与堆数组的末尾元素交换, 此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元

    素的次大值.如此反复执行,便能得到一个有序序列了。 时间复杂度为 O(nlogn),好于冒泡,简单选择,直接插入的O(n^2)


    七、快速排序

    通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。时间复杂度为O(nlogn)

    下文没有给出快速排序的实现,参考以前的文章




    代码实现:(含3种swap交换函数,6个排序算法,不含快速排序)

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
     
    #include<iostream>
    using  namespace std;

    void swap1( int *left,  int *right)
    {
         int temp = *left;
        *left = *right;
        *right = temp;
    }

    void swap2( int &left,  int &right)
    {
         int temp = left;
        left = right;
        right = left;
    }

    void swap3( int &left,  int &right)
    {
         if (left != right)  //如果相同按下面方法会被置0
        {
            left ^= right;
            right ^= left;
            left ^= right;
        }
    }

    /*****************************************************************/
    /* 冒泡排序时间复杂度最好的情况为O(n),最坏的情况是O(n^2)
    * 基本思想是:两两比较相邻记录的关键字,如果反序则交换 */


    void BubbleSort1( int arr[],  int num)
    {
         int i, j;
         for (i =  0; i < num; i++)
        {
             for (j =  1; j < num - i; j++)
            {
                 if (arr[j -  1] > arr[j])
                    swap1(&arr[j -  1], &arr[j]);
            }
        }
    }

    // 改进思路:设置标志位,明显如果有一趟没有发生交换(flag = flase),说明排序已经完成.
    void BubbleSort2( int arr[],  int num)
    {
         int k = num;
         int j;
         bool flag =  true;
         while (flag)
        {
            flag =  false;
             for (j =  1; j < k; j++)
            {
                 if (arr[j -  1] > arr[j])
                {
                    swap1(&arr[j -  1], &arr[j]);
                    flag =  true;
                }
            }
            k--;
        }
    }
    //改进思路:记录一轮下来标记的最后位置,下次从头部遍历到这个位置就Ok
    void BubbleSort3( int arr[],  int num)
    {
         int k, j;
         int flag = num;
         while (flag >  0)
        {
            k = flag;
            flag =  0;
             for (j =  1; j < k; j++)
            {
                 if (arr[j -  1] > arr[j])
                {
                    swap1(&arr[j -  1], &arr[j]);
                    flag = j;
                }
            }
        }
    }
    /*************************************************************************/

    /**************************************************************************/
    /*插入排序: 将一个记录插入到已经排好序的有序表中, 从而得到一个新的,记录数增1的有序表
    * 时间复杂度也为O(n^2), 比冒泡法和选择排序的性能要更好一些 */


    void InsertionSort( int arr[],  int num)
    {
         int temp;
         int i, j;
         for (i =  1; i < num; i++)
        {
            temp = arr[i];
             for (j = i; j >  0 && arr[j -  1] > temp; j--)
                arr[j] = arr[j -  1];
            arr[j] = temp;
        }
    }

    /****************************************************************************/

    /*希尔排序:先将整个待排元素序列分割成若干子序列(由相隔某个“增量”的元素组成的)分别进行
    直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,
    再对全体元素进行一次直接插入排序。其时间复杂度为O(n^3/2),要好于直接插入排序的O(n^2) */


    void ShellSort( int arr[],  int num)
    {
         int i, j, gap, temp;
         for (gap = num /  2; gap >  0; gap /=  2//gap 的取值方法不一
        {
             for (i = gap; i < num; i++)
            {
                temp = arr[i];
                 for (j = i - gap; j >=  0 && arr[j] > temp; j -= gap)
                    arr[j + gap] = arr[j];
                arr[j + gap] = temp;
            }
        }
    }

    /**************************************************************************/

    /* 简单选择排序(simple selection sort) 就是通过n-i次关键字之间的比较,从n-i+1
    * 个记录中选择关键字最小的记录,并和第i(1<=i<=n)个记录交换之
    * 尽管与冒泡排序同为O(n^2),但简单选择排序的性能要略优于冒泡排序 */


    void SelectSort( int arr[],  int num)
    {
         int i, j, Mindex;
         for (i =  0; i < num; i++)
        {
            Mindex = i;
             for (j = i +  1; j < num; j++)
            {
                 if (arr[j] < arr[Mindex])
                    Mindex = j;
            }

            swap1(&arr[i], &arr[Mindex]);
        }
    }

    /********************************************************************************/
    /*假设初始序列含有n个记录,则可以看成n个有序的子序列,每个子序列的长度为1,然后
    * 两两归并,得到(不小于n/2的最小整数)个长度为2或1的有序子序列,再两两归并,...
    * 如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序
    * 时间复杂度为O(nlogn),空间复杂度为O(n+logn),如果非递归实现归并,则避免了递归时深度为logn的栈空间
    * 空间复杂度为O(n) */



    /*lpos is the start of left half, rpos is the start of right half*/
    void merge( int a[],  int tmp_array[],  int lpos,  int rpos,  int rightn)
    {
         int i, leftn, num_elements, tmpos;

        leftn = rpos -  1;
        tmpos = lpos;
        num_elements = rightn - lpos +  1;

         /*main loop*/
         while (lpos <= leftn && rpos <= rightn)
             if (a[lpos] <= a[rpos])
                tmp_array[tmpos++] = a[lpos++];
             else
                tmp_array[tmpos++] = a[rpos++];

         while (lpos <= leftn)  /*copy rest of the first part*/
            tmp_array[tmpos++] = a[lpos++];
         while (rpos <= rightn)  /*copy rest of the second part*/
            tmp_array[tmpos++] = a[rpos++];

         /*copy array back*/
         for (i =  0; i < num_elements; i++, rightn--)
            a[rightn] = tmp_array[rightn];
    }


    void msort( int a[],  int tmp_array[],  int left,  int right)
    {
         int center;

         if (left < right)
        {
            center = (right + left) /  2;
            msort(a, tmp_array, left, center);
            msort(a, tmp_array, center +  1, right);
            merge(a, tmp_array, left, center +  1, right);
        }
    }



    void merge_sort( int a[],  int n)
    {
         int *tmp_array;
        tmp_array = ( int *)malloc(n *  sizeof( int));

         if (tmp_array !=  NULL)
        {
            msort(a, tmp_array,  0, n -  1);
            free(tmp_array);
        }

         else
            printf( "No space for tmp array! ");
    }

    /************************************************************************************/
    /* 堆是具有下列性质的完全二叉树:每个节点的值都大于或等于其左右孩子节点的值,称为大顶堆;
    * 或者每个节点的值都小于或等于其左右孩子节点的值,称为小顶堆*/


    /*堆排序就是利用堆进行排序的方法.基本思想是:将待排序的序列构造成一个大顶堆.此时,整个序列的最大值就是堆顶
    * 的根结点.将它移走(其实就是将其与堆数组的末尾元素交换, 此时末尾元素就是最大值),然后将剩余的n-1个序列重新
    * 构造成一个堆,这样就会得到n个元素的次大值.如此反复执行,便能得到一个有序序列了
    */

    /* 时间复杂度为 O(nlogn),好于冒泡,简单选择,直接插入的O(n^2) */

    // 构造大顶堆
    void HeapAdjust( int arr[],  int i,  int num)
    {
         int j, temp;
        temp = arr[i];
         for (j =  2 * i +  1; j < num; j =  2 * j +  1)
        {
             if (j +  1 < num && arr[j +  1] > arr[j])
                j++;  //如果右孩子比左孩子大,记录位置
             if (arr[j] <= temp)
                 break//如果父节点大,没必要交换,直接退出循环
            arr[i] = arr[j];  //否则交换
            i = j;
        }
        arr[i] = temp;
    }

    void HeapSort( int arr[],  int num)
    {
         int i;
         for (i = num /  2 -  1; i >=  0; i--)
            HeapAdjust(arr, i, num);  //构造大顶堆

         for (i = num -  1; i >=  1; i--)
        {
            swap1(&arr[i], &arr[ 0]);  //将堆顶放置最后
            HeapAdjust(arr,  0, i);  //重新构造大顶堆
        }
    }


    int main( void)
    {
         int arr[] = {  92583471610};
        HeapSort(arr,  10);
         for ( int i =  0; i <  10; i++)
            cout << arr[i] <<  ' ';
        cout << endl;

         return  0;
    }


  • 相关阅读:
    【转】JSP三种页面跳转方式
    我要从头做起
    转载:用 Tomcat 和 Eclipse 开发 Web 应用程序
    html的style属性
    Java连接oracle数据库
    tomcat遇到的问题(总结)
    ceshi
    今天要小结一下
    argument.callee.caller.arguments[0]与window.event
    JavaScript事件冒泡简介及应用
  • 原文地址:https://www.cnblogs.com/riskyer/p/3231032.html
Copyright © 2011-2022 走看看