各种排序方法汇总

12 篇文章 0 订阅
12 篇文章 0 订阅

还是以前老师上课总结的

//经典排序算法: 冒泡、选择、插入、希尔、快排、归并
#include<stdio.h>
#include<stdlib.h>
void swap0(int *a, int *b){
   int temp = *a;
   *a = *b;
   *b = temp;
}

//交换数组a[]中的第i和第j个元素
void swap(int *a, int i, int j){
   int temp = a[i];
   a[i] = a[j];
   a[j] = temp;
}


//输出数组中的元素
void println(int *a, int len){
  for(int i=0;i<len-1;i++){
    printf("%d ",a[i]);
  }
  printf("%d\n",a[len-1]);
}

void swapDemo(){
  int m=-5, n=60;
  swap0(&m,&n);
  printf("%d %d\n", m,n);

  int a[5] ={1,3,5,7,9};
  println(a,5);
  //swap0( &a[0], &a[2] ); //法1
  swap(a,0,2); //法2
  println(a,5);

}

///1 冒泡/
//1.1 简单冒泡
void bubble(){
  int a[10];
  int len=10;
  printf("请输入要排序的10个整数:");
  freopen("din.txt","r",stdin);
  for(int i=0;i<len;i++){
    scanf("%d",&a[i]);
  }
  println(a,len);

  //排序
  for(int i=0;i<len-1; i++){ //趟数,所冒的泡数,总共需冒len-1个
    //每趟冒一个泡: 每次都是从j=0开始,依次让j和j+1进行比较,若逆序则交换
    for(int j=0; j<len-i-1; j++){
      if(a[j]>a[j+1]){
        swap(a,j,j+1);
      }
    }
  }
  println(a,len);
}

//1.2 优化的冒泡: 基本思想是当出现某一趟不存在逆序情况,则后面的趟数就不用进行了,因此此时序列已经有序
void bubble2(){
  int a[10];
  int len=10;
  printf("请输入要排序的10个整数:");
  freopen("din.txt","r",stdin);
  for(int i=0;i<len;i++){
    scanf("%d",&a[i]);
  }
  println(a,len);

  //排序
  for(int i=0;i<len-1; i++){
    int isOk=1;//先假定已经有序
    for(int j=0; j<len-i-1; j++){
      if(a[j]>a[j+1]){
        swap(a,j,j+1);
        isOk=0; //有交换就是非"有序"
      }
    }
    if(isOk)
        break;
  }
  println(a,len);
}

//2 选择排序/
//2.1 排手机
void select0(){
  int a[10];
  int len=10;
  printf("请输入要排序的10个整数:");
  freopen("din.txt","r",stdin);
  for(int i=0;i<len;i++){
    scanf("%d",&a[i]);
  }
  println(a,len);

  //排序

  for(int i=0; i<len-1; i++){ //趟数,让第0个到第n-1个同学,每人分别进行一趟排序
    //第i个同学排序时,从他后面那个同学开始,依次比较且发现逆序时交换
    for(int j=i+1; j<len; j++ ){
        if(a[i]>a[j]){
            swap(a,i,j);
        }
    }
  }

  println(a,len);

}

//2.2 选择排序
void select(){
  int a[10];
  int len=10;
  printf("请输入要排序的10个整数:");
  freopen("din.txt","r",stdin);
  for(int i=0;i<len;i++){
    scanf("%d",&a[i]);
  }
  println(a,len);

  //排序

  for(int i=0; i<len-1; i++){
    int k=i; //※用k记录第i趟当前子序列中最小数的位置
    for(int j=i+1; j<len; j++ ){
        if(a[k]>a[j]){
            k=j;//※
        }
    }
    //经过上面的循环,第k位置的元素一定是当前子序列中最小的元素
    if(k!=i){
        swap(a,k,i);
    }//※
  }

  println(a,len);

}

/3 插入排序
//3.1 普通插入排序
void insertSort(){
  int a[10];
  int len=10;
  printf("请输入要排序的10个整数:");
  freopen("din.txt","r",stdin);
  for(int i=0;i<len;i++){
    scanf("%d",&a[i]);
  }
  println(a,len);

  //排序
  for(int i=0; i<len-1; i++){ //趟数=len-1, 依次把每个元素拿来插入到之前的有序子序列中(从第二个元素开始,到最后就行)
    //每一趟插入第i+1个元素---待插入的元素, 此时前i个元素有序
    int temp=a[i+1]; //先把待插入的元素备份到temp中

    int j=i; //从i开始倒序(从后往前)进行遍历查找待插入位置
    while(a[j]>temp){
        //若a[j]大于temp则让a[j]往后挪一个位置
        a[j+1]=a[j];
        j--;
        if(j<0){
           break;
        }
    }

    //经过上面的循环操作,j+1位置就是temp将要放置的。
    //因为此时只有两种情况: temp>=a[j] 或 j=-1
    a[j+1]= temp;
  }

  println(a,len);
}

//3.2 二分优化后的插入排序
void binaryInsertSort(){
  int a[10];
  int len=10;
  printf("请输入要排序的10个整数:");
  freopen("din.txt","r",stdin);
  for(int i=0;i<len;i++){
    scanf("%d",&a[i]);
  }
  println(a,len);

  //排序
  for(int i=0; i<len-1; i++){
    int temp=a[i+1];

    //1)用二分查找出temp将要放置的位置"high+1" 中的 high
    int low = 0;
    int high = i;
    int mid;
    while(low<=high){
        mid = (low+high)>>1;
        if(a[mid]>temp){ //左半区
            high = mid-1;
        }else{//右半区
           low = mid+1;
        }
    }
    //经过上面循环的操作,找到temp将要放置的位置是:high+1

    //2)把从high+1到i区间内的元素依次往后挪一个位置
    for(int j=i; j>high; j--){
        a[j+1]=a[j];
    }

    //3)让temp放置在high+1
    a[high+1]= temp;
  }

  println(a,len);
}

4 希尔排序//
void shellSort(){
  int a[10];
  int len=10;
  printf("请输入要排序的10个整数:");
  //freopen("din.txt","r",stdin);
  for(int i=0;i<len;i++){
    scanf("%d",&a[i]);
  }
  println(a,len);

  /*希尔排序: 是一种优化算法,用于优化越有序越有利的排序算法。
    基本思想: 当序列非常无序时,gap很大(组内元素很少),此时排序比较快
    (即使是n*n但n很少)。当gap越来越小时(组内元素越来越多),此时排序也比较快,因为越来越有序了。
    */
  for(int gap=(len+1)/2; ; ){//分组

     //组内排序(使用越有序越有利的排序算法如插入排序法,此处为方便大家理解shell算法,我们用冒泡排序
     for(int i=0; i<len-gap; i++){
         for(int j=i; j<len-gap; j+=gap ){
            if(a[j]>a[j+gap]){
                swap(a,j,j+gap);
            }
         }
     }

    if(gap>1){
        gap = (gap+1)/2;
    }else{
      break;
    }
  }
  println(a,len);

}

//5 快速排序
/*
划分: 把a[p....r]范围内的元素进行划分,返回j,实现的功能:
      j为枢轴的位置,a[p...j-1]为左半区(小区),a[j+1...r]为右半区(大区)
*/
int partition(int a[], int p, int r){
  int i=p; //用于左侧遍历的游标-->找一个大于枢轴的数
  int j=r+1; //用于右侧遍历的游标-->找一个小于枢轴的数
  int x=a[p]; //把枢轴备份到x中

  while(1){
    //用i遍历,在左侧找一个大于枢轴的数
    while(a[++i]<x && i<r);

    //用j遍历,在右侧找一个小于枢轴的数
    while(a[--j]>x);

    if(i>=j){
        break;
    }

    //把i和j位置的元素交换一下
    swap(a,i,j);
  }

  //把枢轴(目前是p位置)交换到中间位置(j)
  swap(a,p,j);

  return j;//枢轴的位置
}

//把划分方法partition()优化一下,随机选择一个元素做为枢轴, 注意要导头文件:#include<stdlib.h>
int partition2(int a[], int p, int r){
  /只是这几行是优化代码
  srand( time(0) ); //用当前时间做种子,
  int rnd = rand()%(r-p);
  swap(a,p,p+rnd);


  以下是原partition()中的代码///
  int i=p; //用于左侧遍历的游标-->找一个大于枢轴的数
  int j=r+1; //用于右侧遍历的游标-->找一个小于枢轴的数
  int x=a[p]; //把枢轴备份到x中

  while(1){
    //用i遍历,在左侧找一个大于枢轴的数
    while(a[++i]<x && i<r);

    //用j遍历,在右侧找一个小于枢轴的数
    while(a[--j]>x);

    if(i>=j){
        break;
    }

    //把i和j位置的元素交换一下
    swap(a,i,j);
  }

  //把枢轴(目前是p位置)交换到中间位置(j)
  swap(a,p,j);

  return j;//枢轴的位置
}

void testPartition(){
  int a[10];
  int len=10;
  printf("请输入要排序的10个整数:");
  freopen("din.txt","r",stdin);
  for(int i=0;i<len;i++){
    scanf("%d",&a[i]);
  }
  partition(a,0,len-1);
  println(a,len);
}
/*启发一下
void quickSort(){
   int a[13] = {21,3,2,0,25,  49,25,16,8,23,  45,-3,4};
   //划分一次
   int q = partition(a,0,len-1);

   int q2=partition(a,0,q-1);
   int q3=partition(a,q+1,len-1);

   int q21 = partition(a,0,q2-1);
   int q22 = partition(a,q2+1,q-1);

   int q31 = partition(a,0,q3-1);
   int q32 = partition(a,q3+1,len-1);

   //依此类推...
}
*/

void quickSort(int a[], int p, int r){

   if(p<r){ //至少要有两个元素才划分

      //划分, 结果: 左半区a[0,q-1],  枢轴a[q],  右半区a[q+1,r]
      //int q = partition(a,p,r);
      int q = partition2(a,p,r);

      quickSort(a,p,q-1);
      quickSort(a,q+1,r);
   }

}

void testQuickSort(){
  int a[50];
  int len=50;
  printf("请输入要排序的50个整数:");
  freopen("din.txt","r",stdin);
  for(int i=0;i<len;i++){
    scanf("%d",&a[i]);
  }
  quickSort(a,0,len-1);
  println(a,len);
}

6 归并排序///
//归并方法:把两个有序子序列合并成一个有序序列
void merge(int a[], int b[], int left, int mid, int right){
    //该方法的具体功能: 把左子序列a[left,mid] 和 右子序列a[mid+1,right]归并到b[left,right]
    int p=left; //遍历左子序列的游标
    int r=mid+1; //遍历右子序列的游标

    int k=left; //归并结果序列的游标---当前归并元素在结果集中的放置位置

    while( p<=mid && r<=right){
        if(a[p]<a[r]){
           b[k++] = a[p++];
        }else{
           b[k++] = a[r++];
        }
    }
    //经过上面的循环,一定有一个子序列已经归并完成。只时只要把没归并完的那个子序列剩下的元素直接照搬到结果集中
    if(p>mid){//左子序列归并完,照搬右子序列
        for(int i=r;i<=right;i++){
            b[k++] = a[i];
        }
    }else{//右子序列归并完,照搬左子序列
        for(int i=p;i<=mid;i++){
            b[k++] = a[i];
        }
    }
}
void mergeSort(int a[], int left, int right){

   if(left<right){//至少2个元素
      //先分解
      int mid = (left+right)/2;
      mergeSort(a,left,mid);
      mergeSort(a,mid+1,right);

      //再归并
      int b[100];
      merge(a,b,left,mid,right);
      //把辅助序列b中的数据拷回到a中
      for(int i=left;i<=right;i++){
         a[i]=b[i];
      }
   }
}

void testMergeSort(){
  int a[10];
  int len=10;
  printf("请输入要排序的10个整数:");
  freopen("din.txt","r",stdin);
  for(int i=0;i<len;i++){
    scanf("%d",&a[i]);
  }
  println(a,len);
  mergeSort(a,0,len-1);
  println(a,len);
}

int main(){
  //swapDemo();

   //bubble();
   //bubble2();

   //select0();
   //select();


   //insertSort();
   //binaryInsertSort();


   //shellSort();

   //testPartition();
   testQuickSort();

   //testMergeSort();

  return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
排序算法中,时间复杂度是评估算法性能的重要指标。根据引用和引用的内容,下面是一些常见排序算法的时间复杂度汇总: 1. 冒泡排序:冒泡排序是一种简单但效率较低的排序算法。最坏情况下,冒泡排序的时间复杂度是O(n^2),其中n是待排序元素的数量。最好情况下,当数据已经有序时,冒泡排序的时间复杂度是O(n)。 2. 插入排序插入排序算法根据待排序序列中的元素逐个插入已排序序列的合适位置。最坏情况下,插入排序的时间复杂度也是O(n^2)。最好情况下,当数据已经有序时,插入排序的时间复杂度是O(n)。 3. 选择排序:选择排序是一种简单的排序算法,每次从未排序的部分选择最小(或最大)的元素,然后放到已排序部分的末尾。选择排序的时间复杂度始终为O(n^2),无论数据是否有序。 4. 快速排序快速排序是一种高效的排序算法,基于分治的思想。最坏情况下,快速排序的时间复杂度是O(n^2),但通常情况下,快速排序的平均时间复杂度是O(nlogn)。 5. 归并排序:归并排序是一种稳定且高效的排序算法,基于分治和合并的思想。归并排序的时间复杂度始终为O(nlogn),无论数据是否有序。 综上所述,不同的排序算法其时间复杂度不同。冒泡排序插入排序的时间复杂度是O(n^2),选择排序的时间复杂度也是O(n^2),而快速排序和归并排序的时间复杂度是O(nlogn)。请注意,这些时间复杂度都是在最坏情况下估计的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值