数据结构之排序

八、排序

  • 排序概述

  1. 排序的分类:内部排序和外部排序(若待排序记录都在内存中,称为内部排序;若待排序记录一部分在内存,一部分在外存,则称为外部排序)。稳定排序和不稳定排序。                                                                                            

  2. 内部排序的算法:插入排序(希尔排序)、交换排序(快速排序)、选择排序(堆排序)、归并排序、基数排序。

  • 插入排序

  1. 思想:每次将一个待排序的对象,按其关键码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。
  2. 具体实现算法:直接插入排序、折半插入排序、希尔排序
  3. 直接插入排序:                                                                                        


          
          
    1. void InsertSort(int a[]){
    2. int i,j;
    3. //按照有小到大的顺序排序
    4. for(i=2;i<a.length;i++){
    5. //找到无序表的第一个位置
    6. if(a[i]<a[i-1]){
    7. a[0]=a[i];
    8. //将无序表依次向后移动
    9. for(j=i-1;a[0]<a[j];j--){
    10. a[j+1]=a[j];
    11. }
    12. //将数据插入相应位置
    13. a[j+1]=a[0];
    14. }
    15. }
    16. }
    该算法的时间复杂度是:O(n2)

  4. 折半插入排序:                                                                                           

          
          
    1. void BInsertSort(int a[]){
    2. int i,j,high,low;
    3. for(i=2;i<a.length;i++){
    4. a[0]=a[i];
    5. low=1;
    6. high=i-1;
    7. int min;
    8. while(low<=high){ //使用折半查找到插入的位置
    9. min=(high+low)/2;
    10. if(a[0]<a[min])
    11. high=min-1;
    12. else
    13. low=min+1;
    14. }
    15. for(j=i-1;j=>high+1;j++) //插入的位置是在high位置之后
    16. a[j+1]=a[j];
    17. a[high+1]=a[0];
    18. }
    19. }


  5. 希尔排序:                                                                                                


                                                    从排序过程可以看出,希尔排序的一个特点是:子序列的构成不是简单地“逐段分割”,而是将相隔某个“增量”的记录组成一个子序列。
          
          
    1. void SheelSort(int a[],int dx){
    2. //这是对直接插入排序的修改
    3. //dx表示增量
    4. //当j<=0时,插入位置已经找到
    5. int i,j;
    6. for(i=dx+1;i<a.length;i++){
    7. if(a[i]<a[i-dx]){
    8. a[0]=a[i];
    9. for(j=i-dx;j>0&&a[0]<a[j];j-=dx)
    10. a[j+dx]=a[j];
    11. a[j+dx]=a[0];
    12. }
    13. }
    14. }


  • 交换排序

  1. 两两比较待排序记录的关键码,如果发生逆序(即排列顺序与排序后次序正好相反),则交换之,直到所有记录都排好序为止。
  2. 冒泡排序:                                                                                                     
          
          
    1. void bubbleSort(int a[]){
    2. int i,j;
    3. for(i=1;i<a.length-1;i++){
    4. for(j=1;j<a.length-i;j++){
    5. if(a[j]>a[j+1]){
    6. a[0]=a[j];
    7. a[j]=a[j+1];
    8. a[j+1]=a[0];
    9. }
    10. }
    11. }
    12. }


  3. 快速排序:                                                                                                  




          
          
    1. void Partition(int a[],int low,int high){
    2. //这只是一趟快速排序的算法
    3. a[0]=a[low];
    4. while(low<high){
    5. //从高位往低位扫描,找到数值小于关键字的位置,与low位置交换
    6. while(low<high&&a[0]<=a[high])
    7. high--;
    8. a[low]=a[high];
    9. //从低位往高位扫描,找到数值大于关键字的位置,与high位置交换
    10. while(low<high&&a[low]<=a[0])
    11. low++;
    12. a[high]=a[low];
    13. }
    14. //最后将关键字放入数组中
    15. a[low]=a[0];
    16. }
    快速排序平均时间复杂度和最好时间复杂度为:O(log2n),最坏时间复杂度为O(n2)。

  • 选择排序

  1. 不断从待排记录序列中选出关键字最小的记录插入已排序记录序列的后面,直到n个记录全部插入已排序记录序列中。
  2. 简单选择排序:                                                                                                



  3. 堆排序:借助于完全二叉树结构进行的排序,是一种树形选择排序。其特点是——在排序过程中,将R[1...N]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树双亲结点和孩子结点之间的内在关系,在当前无序区中选择关键字最大(或最小)的记录。                                                                           


                             堆的根节点是堆中元素值最小(或最大)的结点,称为堆顶顶点;从根节点到每个叶节点的路径上,元素的排序序列都是递减(或递增)有序的。

  4. 建立一个堆排序的方法:                                                                               



  5. 堆排序的过程:                                                                                       


  6. 堆排序算法实现:
          
          
    1. void HeapAdjust(int *a,int i,int size) //调整堆
    2. {
    3. int lchild=2*i; //i的左孩子节点序号
    4. int rchild=2*i+1; //i的右孩子节点序号
    5. int max=i; //临时变量
    6. if(i<=size/2) //如果i不是叶节点就不用进行调整
    7. {
    8. if(lchild<=size&&a[lchild]>a[max])
    9. {
    10. max=lchild;
    11. }
    12. if(rchild<=size&&a[rchild]>a[max])
    13. {
    14. max=rchild;
    15. }
    16. if(max!=i)
    17. {
    18. swap(a[i],a[max]);
    19. }
    20. }
    21. }
    22. void BuildHeap(int *a,int size) //建立堆
    23. {
    24. int i;
    25. for(i=size/2;i>=1;i--) //非叶节点最大序号值为size/2
    26. {
    27. HeapAdjust(a,i,size);
    28. }
    29. }
    30. void HeapSort(int *a,int size) //堆排序
    31. {
    32. int i;
    33. BuildHeap(a,size);
    34. for(i=size;i>=1;i--)
    35. {
    36. //cout<<a[1]<<" ";
    37. swap(a[1],a[i]); //交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面
    38. //BuildHeap(a,i-1); //将余下元素重新建立为大顶堆
    39. HeapAdjust(a,1,i-1); //重新调整堆顶节点成为大顶堆
    40. }
    41. }


  • 归并排序

  1. “归并”的含义是将两个或两个以上的有序表合并成一个新的有序表。



  2. 两个有序表的合并算法Merge():                                                        



  3. 算法分析:                                                                                                 

  • 基数排序

  1. 基数排序是一种借助多关键字排序的思想对单逻辑关键字进行排序的方法,即先将关键字分解成若干部分,然后通过对各部分关键字的分别排序,最终完成对全部记录的排序。
  2. 多关键字的排序:                                                                                       


  3. 链式基数排序:                                                               



  • 排序算法总结                                                                                     


九、时间复杂度



  1. 该时间复杂度表达作用于递归过程。
  2. n/b表示下一回递归的数据量为n/b,a表示递归的次数为a,除了递归之外的时间复杂度为O(nd)。


作者:龙猫小爷
链接:http://www.jianshu.com/p/2469a4d9708e
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值