• 保研复习数据结构记(8)--排序


    一.内部排序

    1.概念

    • 什么是排序?是将一个任意排列的记录或者是数据元素,排列成按关键字有序的序列
    • 什么是排序方法是稳定的?按照关键字排序的ki=kj,在排序之后,两个关键字相等的记录的顺序与排序之前相同,若相反,则称为关键字是不稳定的。
    • 什么是内部排序?指的是待排序记录序列存放在计算机内存随机存储器序列中
    • 什么是外部排序?指的是待排序记录数量太多,一部分存放在外存中,在排序时需要进行存取磁盘操作。

    2.插入排序

    插入排序算法简单,适合记录数量少进行排序,不适合数量大的元素进行排序。

    (1)直接插入排序Straight Insertion Sort
    • 什么是直接插入排序?将一个记录插入到已排好序的有序序列中,如果采用顺序表存储方式存储的话,插入后需要后移元素,如果改进效率可以使用折半插入。
    • 直接插入排序的时间复杂度是多少?O(n^{2})
    • 代码?

    首先给出数据元素的定义

    1. typedef int keytype;//为了方便定义整型
    2. #define maxsize 10
    3. typedef struct{
    4. keytype key;//关键字数据项
    5. keytype otherinfor;//其他数据项
    6. }elemtype;
    7. typedef struct{
    8. elemtype r[maxsize+1];//第一个元素用作临时存储
    9. int length=0;
    10. }Sqlist;
    1. void straightSort(Sqlist L)
    2. {
    3. for(int i=2;i<=L.length;++i)
    4. {
    5. if(L.r[i-1].key>L.r[i].key)
    6. {
    7. L.r[0].key=L.r[i].key;//存放待插元素
    8. L.r[i].key=L.r[i-1].key;//先后移一位元素,这也是后移向前插的开始
    9. int j;
    10. for(j=i-2;L.r[0].key
    11. {
    12. L.r[j+1].key=L.r[j].key;
    13. }
    14. L.r[j+1]=L.r[0];//插入到正确位置,因为r[j]不小于r[0]所以,0存在j的后面j+1
    15. }
    16. }
    17. OutPut(L);
    18. }
     (2)希尔排序Shell's Sort
    • 什么是希尔排序?基本思想是先将整个记录序列分割成若干子序列分别对若干子序列进行插入排序,逐渐缩小分割增量,待整个序列“基本有序”时,再整体进行一次插入排序。
    1. void shellInsert(Sqlist L,int dk)
    2. {
    3. //前后记录增量位置为dk
    4. for(int i=dk+1;i<=L.length;++i)
    5. {
    6. if(L.r[i].key
    7. {
    8. L.r[0].key=L.r[i].key;//存放要插入的元素
    9. int j;
    10. for(j=i-dk;j>0&&L.r[0].key
    11. {
    12. L.r[j+dk]=L.r[j];//向后移动
    13. }
    14. L.r[j+dk]=L.r[0];//后移之后把元素赋值
    15. }
    16. }
    17. }
    18. void shellSort(Sqlist L,int delta[],int t)
    19. {
    20. //按增量delta[]对顺序表L进行排序
    21. for(int k=0;k
    22. {
    23. shellInsert(L,delta[k])//一趟增量为delta的插入排序
    24. }
    25. }

    关于增量序列delta[],尚未有人得出较好的结论。有人指出当delta[k] = 2^{t-k+1} - 1时,希尔排序的时间复杂度是O(n^{3/2}),其中t是排序趟数,k<=t

    3.快速排序Quick Sort

    (1)冒泡排序Bubble Sort
    • 冒泡排序的思想是什么?首先将第一个记录与第二个记录进行比较,如果逆序就swap,一直比较到最后一个记录的位置上;每一趟会比较出一个剩余最大的元素 放在后面,第i趟冒泡排序是从第1个到第n-i+1个依次比较。
    (2)快速排序Quick Sort
    • 快速排序如何选择枢轴Pivot?由于如果记录序列最初是基本有序,然后快排序列的Pivot选择第一个元素的话,那么整个流程类似于冒泡排序,所以Pivot通常采用“三者取中”,即比较L.r[s].key和L.r[t].key和L.r[(s+t)/2],取三者中其关键字的中值作为枢轴。
    • 快速排序的思想?首先按照“三者取中”的原则选取一个Pivot,然后进行一趟排序,排序的结果是,将所有小于Pivot的元素移动到Pivot左侧,所有大于Pivot的元素移动到Pivot右侧,继续对Pivot左右两侧分别快排。And每一趟排序选取left和right,假设枢轴值是pivotkey,如果pivotkey大于high那么交换pivotkey和high,high--。
    1. int Partition(Sqlist& L,int low,int high)
    2. {
    3. //交换顺序表中子表r[low..high]
    4. L.r[0].key=L.r[low].key;
    5. int pivotkey=L.r[low].key;//将最小值赋值给枢轴
    6. while(low
    7. {
    8. while(low=pivotkey)--high;
    9. L.r[low]=L.r[high];//将比枢轴小的记录移动到低端
    10. while(low
    11. L.r[high]=L.r[low];//将比枢轴大的记录移动到高端
    12. }
    13. L.r[low]=L.r[0];//将枢轴记录到位
    14. return low;//返回枢轴位置
    15. }
    16. void quickSort(Sqlist& L,int low,int high)
    17. {
    18. if(low
    19. {
    20. int pivotloc=Partition(L,low,high);//将L一分为二
    21. quickSort(L,low,pivotloc);//对低表进行递归排序
    22. quickSort(L,pivotloc+1,high);//对高表进行递归排序
    23. }
    24. }

    快速排序被认为在所有同数量级O(nlogn)的排序中,其性能最好。

    4.选择排序Selection Sort

    (1)简单选择排序Simple Selection Sort
    • 简单选择排序的基本思想?在第i趟选择的过程中,从剩下n-i+1个元素中找到关键字最小的元素,与第i个元素进行交换,作为有序序列中的第i个元素。
    • 时间复杂度为O(n^{2})
    (2)堆排序Heap Sort
    • 什么是堆?n个元素的序列{k1,k2,...,kn},当且仅当满足如下关系时,称之为堆:

    k_i\leq k_{2i} And k_i\leq k_{2i+1}  或者  k_i \geq k_{2i} And k_i \geq k_{2i+1}其中i=1,2,3,..,n/2

    • 若将此序列对应的一维数组看成是一个完全二叉树,堆表明什么含义?完全二叉树所有非终端结点的值不大于(或不小于)其左右孩子结点的值。那么堆顶元素必为序列中n个元素的最小值或者最大值。
    • 使用堆排序应该解决哪两个问题?如何由一个无序序列建成一个堆;如何在输出堆顶元素之后,调整剩余元素称为一个新的堆。
    • 堆排序的代码?
    1. void HeapAdjust(HeapType& H,int s,int m)
    2. {
    3. elemtype rc=H.r[s];
    4. for(int j=2*s;j<=m;j*=2)//沿key较大的孩子结点向下筛选
    5. {
    6. if(j1].key)
    7. ++j;//j为key
    8. if(rc.key>=H.r[j].key)break;
    9. H.r[s]=H.r[j];
    10. s=j;
    11. }
    12. H.r[s]=rc;//插入
    13. }
    14. void HeapSort(HeapType& H)
    15. {
    16. //对顺序表H进行堆排序
    17. for(int i=H.length/2;i>0;i--)
    18. {
    19. HeapAdjust(H,i,H.length);
    20. }
    21. for(int i=H.length;i>1;--i)
    22. {
    23. swap(H.r[1],H.r[i]);//将堆顶记录,最后一个记录相互交换
    24. HeapAdjust(H,1,i-1);//将H.r[1..i-1]重新调整为大顶堆
    25. }
    26. }

    5.归并排序Merging Sort

    • 什么是归并排序(什么是2-路归并排序)?假设有n个记录,将每一个记录看作n个有序的记录,两两归并,得到(n/2)向上取整 长度为2或者1的有序序列,再继续两两归并,如此重复得到n个有序的序列为止。
    • 代码是什么
    1. void merge(int R[], int low, int mid, int high)
    2. {
    3. int len = high - low + 1;
    4. int* temp = new int[len];
    5. int i = low, j = mid + 1;
    6. int k = 0;
    7. while (i <= mid && j <= high) {
    8. if (R[i] <= R[j]) {
    9. temp[k] = R[i];
    10. k++;
    11. i++;
    12. }
    13. else {
    14. temp[k] = R[j];
    15. k++;
    16. j++;
    17. }
    18. }
    19. while (i <= mid) {
    20. temp[k] = R[i];
    21. k++;
    22. i++;
    23. }
    24. while (j <= high) {
    25. temp[k] = R[j];
    26. k++;
    27. j++;
    28. }
    29. for (k = 0; k < len; k++)
    30. R[low + k] = temp[k];
    31. }
    32. void mergeSort(int R[], int low, int high){//主排序函数
    33. if (low < high) {
    34. int mid = (low + high) / 2;
    35. mergeSort(R, low, mid);//左侧继续排序
    36. mergeSort(R, mid+1, high);//右侧继续排序
    37. merge(R, low, mid, high);//合并
    38. }
    39. }

    6.基数排序Radix Sorting

  • 相关阅读:
    齐次坐标得到非齐次坐标
    数据库-索引
    2023-2028年中国六方氮化硼市场投资分析及前景预测报告
    Java进阶(再论线程)——线程的4种创建方式 & 线程的生命周期 & 线程的3大特性 & 集合中的线程安全问题
    form-serialize插件,快速收集表单元素的值
    RocketMQ详细配置与使用
    【MySQL数据库和JDBC编程】第三章-第二节:MySQL的增删查改进阶篇
    【计算机视觉 | 语义分割】语义分割常用数据集及其介绍(六)
    python -m SimpleHTTPServer 使用详解
    java-php-python-ssm基于的燕理快递中转站系统的设计与实现计算机毕业设计
  • 原文地址:https://blog.csdn.net/qq_61219640/article/details/136597308