• [数据结构]快速排序


    一、问题描述

    内部排序是一件具有重大意义的问题,许多项目的实现中都需要用到排序。

    我们知道,排序的算法有许多种,每种排序算法的时间复杂度和空间复杂度不尽相同。在解决实际问题时,往往需要根据实际需要选择排序算法。

    上次实验已经讨论了希尔排序的实现及其原理,本实验重点介绍另一种排序算法——快速排序。实验中将讨论快速排序的实现及其原理。

    二、数据结构——顺序结构

    本实验重点在算法实现上,数据结构的思想被弱化了。在排序过程中,由于维护序关系的需要,要有交换的操作,这就破坏了ADT的物理位置的相邻反映逻辑的依次的性质,可以说这里的顺序结构只是一个二次结构。因此,本实验不对此作过多说明。

    三、算法的设计和实现

    1、算法描述

    快速排序是一种基于比较的排序算法,算法是不稳定的。有一种形象的叫法是“挖坑+分治”排序来形容快速排序。以下简要说明其操作。

    以不降序排序为例。选择序列中一个元素作为基准元素,本实验中选择的是序列区间的第一个元素。定义两个指针(这里的指针只是一个意指,不一定用c++语言中真正的指针来实现,可以是一个整型数)i和j,初始时分别指向待排序列区间的首、尾。

    每一轮排序时,选择第一个元素作为基准元素,相当于在序列区间的第一个位置挖了一个坑,现在要填坑。移动j,直到Elem[j]比基准元素小,将Elem[j]挖出来填到第一个位置,这时坑就是j这个位置了;移动i,知道Elem[i]比基准元素大,将Elem[i]挖出来填到j位置,这时坑就是i这个位置了。重复上述挖坑、填坑的操作,直到i == j,结束循环。此时,将基准元素填入当前的坑里,于是在该基准元素的左侧的元素都比它小,右侧的都比它大。这时就出现了一个自相似的子结构,于是很自然地选择递归,将当前的待排序序列区间以基准元素的位置一分为二,分别重复上述过程。递归的边界是当前区间只有一个元素,*凡有序。

    所谓“挖坑”上面已经提到了,所谓“分治”就是指的区间一分为二的递归过程。

    2、算法复杂度分析

    快速排序的时间主要耗费在划分操作上,设当前待排序区间长度为k,则共需要k-1次关键字的比较。

    最坏情况是每次划分选取的基准元素都是当前区间的最小(或者最大)元素,那么划分的结果将是左边的子区间(或者右边的子区间)为空,而右边的子区间(或者左边的子区间)长度为k-1,仅比之前少一个元素。此时的时间复杂度为O(n^2)。

    最好情况是每次划分选取的基准元素都正好是当前区间的中位数,划分的结果是左、右子区间元素个数大致相等,总的复杂度为O(n lgn)。

    尽管快速排序的最坏情况复杂度逼**方级别,但就*均性能而言,它是基于关键字比较的内部排序算法中速度最快的(这个网上有许多算法的时间测试,这里不再赘述),它的*均时间复杂度为O(n lgn)。

    3、例子

    (1)第一轮

    基准元素下标 1 2 3 4 5 6 7 8 9 10
    72 72 6 57 88 60 42 83 73 48 85
      48 6 57 88 60 42 83 73 48 85
      48 6 57 88 60 42 83 73 88 85
      48 6 57 42 60 42 83 73 88 85
      48 6 57 42 60 72 83 73 88 85

    (2)第二轮

    a)区间[1,5]

    基准元素下标 1 2 3 4 5
    48 48 6 57 42 60
      42 6 57 42 60
      42 6 57 57 60
      42 6 48 57 60

    b)区间[7,10]

    基准元素下标 7 8 9 10
    83 83 73 88 85
      73 73 88 85
      73 83 88 85

    c)总的序列

    42 6 48 57 60 72 73 83 88 85

    (3)第三轮

    a)区间[1,2]

    基准元素下标 1 2
    42 42 6
      6 6
      6 42

    b)区间[4,5]

    基准元素下标 4 5
    57 57 60
      57 60

    c)区间[7,7],直接返回

    d)区间[9,10]

    基准元素下标 9 10
    88 88 85
      85 85
      85 88

    e)总的序列

    6 42 48 57 60 72 73 83 85 88

    排序完成

    四、预期结果和实验中的问题

    1、预期结果

    程序能够正确地将一个序列按照不递减的顺序排序。下图为一个例子。

    2、实验中的问题及思考

    快速排序还有一些改进的版本,当然比较常见的是在选择基准元素的时候采用随机选择的方式。据研究表明,选择黄金分割点处的数作为基准元素的期望速度最快,这个我还没有仔细学习过。

    附:c++源代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 
     5 using namespace std;
     6 #define MaxN 120
     7 
     8 int gap[200]; //步长 2^k+1 第一项改为1
     9 int n;
    10 
    11 template <class T> class My_list
    12 {
    13 private:
    14     T Elem[MaxN]; //待排序的元素
    15     int Len; //元素个数
    16 public:
    17     void Init()
    18     {
    19         memset(Elem, 0, sizeof(Elem));
    20         Len = 0;
    21     }
    22     void Insert_back(T x)
    23     {
    24         Elem[++Len] = x;
    25     }
    26     void Print()
    27     {
    28         int i;
    29         for(i = 1; i < Len; i++)
    30             printf("%d ", Elem[i]);
    31         printf("%d
    ", Elem[i]);
    32     }
    33     int GetLen()
    34     {
    35         return Len;
    36     }
    37     void QuickSort(int st, int ed)
    38     {
    39         if(st < ed)
    40         {
    41             int i = st, j = ed, x = Elem[st];
    42             while(i < j)
    43             {
    44                 while(i < j && Elem[j] > x) //找右侧比x大的元素 
    45                     j--;
    46                 if(i < j)
    47                     Elem[i++] = Elem[j];
    48                 while(i < j && Elem[i] < x) //找左侧比x小的元素 
    49                     i++;
    50                 if(i < j)
    51                     Elem[j--] = Elem[i];
    52             }
    53             Elem[i] = x;
    54             QuickSort(st, i - 1); //分治左侧区间 
    55             QuickSort(i + 1, ed); //分治右侧区间 
    56         } //if
    57     }
    58 };
    59 
    60 void Read(My_list <int> &L)
    61 {
    62     int i, x;
    63     L.Init();
    64     printf("请输入需要排序的数的个数。
    ");
    65     scanf("%d", &n);
    66     printf("请输入需要排序的数列。
    ");
    67     for(i = 1; i <= n; i++)
    68     {
    69         scanf("%d", &x);
    70         L.Insert_back(x); //把x插入到最后
    71     }
    72 }
    73 
    74 int main()
    75 {
    76     int GapNum;
    77     My_list <int> L;
    78     Read(L);
    79     L.QuickSort(1, n);
    80     printf("升序排序后的数列:
    ");
    81     L.Print();
    82     return 0;
    83 }
    View Code
  • 相关阅读:
    strspn实现 查找第一个不在指定字符串中出现的字符
    strstr 的实现 即 字符串中查找子字符串第一次出现的位置
    strcspn
    将字符串中的大写字母变成小写字母
    strrchr 字符在字符串中最后一次出现的位置
    strchr 字符c在字符串中出现的位置 实现
    qsort库函数 排序
    strncmp实现
    strcmp实现
    ACM/ICPC题目输入情形及其处理方法
  • 原文地址:https://www.cnblogs.com/CQBZOIer-zyy/p/5185409.html
Copyright © 2020-2023  润新知