常用排序算法

关于排序

数据结构中的排序算法是个非常重要的内容,经常出现在各种笔试考题当中。常见排序方法有:直接插入排序、希尔排序、直接选择排序、堆排序、气泡排序、快速排序等。分开进行讲解——

  • 插入排序

  1. 直接插入排序
void InsertSort(int *arr,int n){
    int x;
    int i,j;
    for(i=1;i < n;i++){
        x=arr[i];
        for(j=i-1;j >= 0;j--)
            if(x < arr[j]) arr[j+1]=a[j];else break;
        a[j+1]=x;
    }
}

第一层循环->对数组进行遍历进行以下操作:对数组的 第0-i的子序列进行从大到小的排序。i每增加1位,假设为d。便它目前的子序列进行遍历,寻找它的位置,因为子序列之前已经是排好序了的,则若碰到比d大的数,则可以停止遍历了,若没有则将已遍历的数字后移一位,相当于将d插入它应该在的位置。

其时间复杂度为O(n^2),空间复杂度为O(1)。相等的数字顺序不会变化,所以该方法是--稳定排序

ps. 直接插入排序时间复杂度应与序列本身排序有关最小排序应为O(n),最大为O(n^2)

2. 希尔排序

void ShellSort(int *arr,int n){
  int i,j,d;
  for(d=n/2;d>=1;d/=2){
    for(i=d; i< n;i++)
      x=arr[i];
      for(j=i-d;j>=0;j-=d){
        if(x< arr[j]) a[j+d]=arr[j];
        else break;
      }
      arr[j+d]=x;
    }
  }
}

希尔排序的理论分析提出了许多困难的数学问题,特别是如何选择增量序列才能产生最快的排序效果,至今没有得到解决。希尔本身提出的步长设定为:di=n/(2)^i。
以下为排序举例:


·原序列:
a b c d e f g h i j
5 4 8 1 3 7 9 6 2 10
第一次步长:d1=10/2=5
即:
a与f :插入排序
b与g :插入排序
c与h :
...
e与j :插入排序
得到序列为:
5 4 6 1 3 7 9 8 2 10
第二次步长:d2=10/4=2
即:
a-c-e-g-i:
b-d-f-h-j:
得到序列:
2 3 5 6 9
1 4 7 8 10
组合:
2 1 3 4 5 7 6 8 9 10
第三次步长:d3=10/8=1
即:
a-b-c-d-e-f-g-h-i-j:
得到序列:
对整个序列插入排序-将d=1代入 与直接插入排序代码一致:
即可得到:
1 2 3 4 5 6 7 8 9 10

时间复杂度处于O(nlbn)和O(n^2)之间

  • 选择排序

  • 1.直接选择排序

void SelectSort(int *arr,int n){
    int i,j,k;
    for(i=1;i<=n-1;i++){
        k=i-1;
        for(j=i;j<=n-1;j++){
            if(arr[j]< arr[k]) k=j;
        }
        if(k!=i-1){
            x=arr[i-1];
            arr[i-1]=arr[k];
            a[k]=x;
        }
    }
}

直接选择排序是一种简单的排序方式,它每次从待排序的区间选出具有最小排序码的数与该区间的第一个元素进行交换。
例如:


待排序数列:
a b c d e f g h
3 9 1 7 5 2 3 4
第一次:
k=0; arr[k]=3; 进入第二级循环
第二级循环为从b-h的数中 寻找比arr[k]小的数字,第一次找到c ,这是运行k=j即此时k=2
arr[k]=1,继续寻找比1小的数字,没有 ,此时k!=i-1 意味着arr[0]不是剩下序列的最小值,进行元素位置交换
即a[0]=1; arr[2]=3 a与c进行了交换
第二次:
k=1; arr[1]=9; 进入第二级循环
该循环为从c-h中的数字寻找,寻找后序数字中比9小,且最小的数字 进行交换
...
直到i=h k=g 判断h 与g 哪个数字更大 结束循环 排序完成

在直接选择排序中,共需要进行n-1次选择和交换,每次选择需要比较 n-i次,其中1<=i<=n-1

直接选择排序时间复杂度为O(n^2),但是由于它的移动记录的总次数为O(n)数量级,所以当记录占用的字节数相对较多时通常比直接插入排序的执行速度要快一些

由于在直接选择排序中存在着不相邻元素之间的互换,因此可能会改变具有相同排序码元素的前后位置,所以该方法是不稳定的

  • 2.堆排序

    void Sift(int *arr,int n,int i){
        int j;
        j=2 * i + 1;
        int x=arr[i];
        while(j<= n-1){
            if(j< n-1 && arr[j]< arr[j+1])
                j++;
            if(x< arr[j]){
                arr[i]=arr[j];
                i=j;
                j=2 * i + 1;
            }
            else break;
        }
        arr[i]=x;
    }
    void HeapSort(int *arr,int n){
        int x,i;
        for(i=n/2-1; i>= 0;i--)
            Sift(arr,n,i);
        for(i=1;i<= n-1;i++){
            x=arr[0];
            arr[0]=arr[n-1];
            arr[n-i]=x;
            Sift(arr,n-i,0);
        }
    }
 

转载于:https://www.cnblogs.com/EffectL/p/6675859.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值