经典排序算法代码

来源:互联网 发布:最好看的网络官场小说 编辑:程序博客网 时间:2024/05/29 13:34

1、插入排序

//插入排序void InsertSort(int Nums[],int Length){  for(int i=0;i<Length;i++)  {    int j,temp=Nums[i];  //将第i个数保存起来    for(j=i-1;Nums[j]>temp&&j>=0;j--)  //依次将第i个数与前面的数比较    {      Nums[j+1]=Nums[j]; //如果前面的数比第i个数大,则往后移动    }    Nums[j+1]=temp;  //最后将空出的位置装入上面保存的第i个数  }}

2、希尔排序

//希尔排序void ShellSort(int nums[],int Length){  for(int gap=Length/2;gap>0;gap/=2)  {    //根据增量gap 进行插入排序    for(int i=gap;i<Length;i+=gap)    {      if(temp<Nums[j-gap)         Nums[j]=Nums[j-gap];      else         break;    }    Nums[j]=temp;  }}

上面代码中的gap增量叫做希尔增量,增量的使用对于算法性能有影响,当使用希尔增量时,最坏情形下的运行时间为O(N^2),Hibbard提出一个稍微不同的增量序列1,3,7….,使用Hibbard增量的希尔排序的最坏情形下的运行时间为O(N^(3/2))。
3、堆排序

#include <stdio.h>//这个函数调整对数组中第n个元素的位置void HeapAdjust(int array[],int n,int length){  int Child;  for(int i=n;i*2<=length;i=Child)  {    Child=i*2;    if(Child+1<=length&&array[Child]<array[Child+1])       Child++;    //如果较大的子节点大于父节点则交换位置    if(array[i]<array[Child])    {       int Temp=array[i];       array[i]=array[Child];       array[Child]=Temp;    }    else    {       break;    }  }}void HeapSort(int array[],int length){  //调整前半部分,保证了最大的值都在前半部分  for(int i=length/2;i>0;i--)  {    HeapAdjust(array,i,length);  }  for(int i=length-1;i>0;i--)  {    //将最大的书移动到尾部    int Temp=array[1];    array[1]=array[i+1];    array[i+1]=Temp;    //除去尾部后,调整第一个元素位置    HeapAdjust(array,1,i);  }}void HeapAdjustLittle(int array[],int num,int length){  //如果输入的数小于这些数,直接返回  if(num<array[1])  {    return;  }  //如果输入的数大于数组中最小的数,则赋值,然后调整堆数组  array[1]=num;  intt Child;  for(int i=1;i*2<=length;i=Child)  {    Child=i*2;    if(Child+1<=length&&array[Child]>array[Child+1])      Child++;    //如果较小的子节点大于父节点则交换位置      if(array[i]>array[Child])    {      int Temp=array[i];      array[i]=array[Child];      array[Child]=Temp;    }    else    {      break;    }  }}//打印输出数组内容void PrintArray(int array[],int size){  printf("最大的前%d个数:\n",size);  for(int i=0;i<size;i++)  {    printf("%3d",array[i]);  }  printf("\n");}int myarray[]={0, 1, 9, 2, 8, 3, 7, 4, 6, 5 , 10};int main(){  //将前十个数进行一次堆排序,并输出结果  HeapSort(myarray,sizeof(myarray)/4-1);  PrintArray(myarray+1,sizeof(myarray)/4-1);  //输入数字,打印出前十个最大的数  while(1)  {    int num=0;    scanf("%d",&num);    HeapAdjustLittle(myarray,num,sizeof(myarray)/4-1);    PrintArray(myarray+1,sizeof(myarray)/4-1);  }  return 0;}

4、归并排序

#include<stdio.h>//合并两个有序数组void Merge(int Array[],int tmpArray[],int left,int mid,int right){  int i=left;  int tmpleft=left;  int tmpright=mid+1;  //比较左右数组元素大小,放入第三个数组中  while(tmpleft<=mid&&tmpright<=right)  {    if(Array[tmpleft]<Array[tmpright]       tmpArray[i++]=Array[tmpleft++];    else       tmpArray[i++]=Array[tmpright++];  }  //右边数组用完了进入此循环拷贝左边数组到第三个数组  for(;tmpleft<=mid;tmpleft++)  {    tmpArray[i++]=Array[tmpleft];  }  //左边数组用完了进入此循环拷贝右边数组到第三个数组  for(;tmpright<mid;tmpright++)  {    tmpArray[i++]=Array[tmpright];  }  //合并后的数组拷贝回原数组  for(i=left;i<=right;i++)  {    Array[i]=tmpArray[i];  }}//归并排序void MergeSort(int Array[],int tmpArray[],int left,int right){  //基准条件,如果只有一个元素即为有序数组,直接返回  if(left>=right)     return;  //递归数组排序左右两边数组  int mid=(left+right)/2;  MergeSort(Array,tmpArray,left,mid);  MergeSort(Array,tmpArray,mid+1,right);  //排序完成后进入合并数组  Merge(Array,tmpArray,left,mid,right);}int main(){  int a[]={1,0,2,9,3,8,4,7,5,6};  int tempa[10];  MergeSort(a,tempa,0,9);  for(int i=0;i<10;i++)  {     printf("%d\n",tempa[i]);  }  return 0;}

归并排序以最坏情形的运行时间O(NlogN)运行,而所使用的比较次数几乎是最优的。
5、快速排序
快速排序(quicksort)是在实践中最快的一直排序算法,它的平均运行时间是O(NlogN)。该算法之所以特别快,主要是由于非常精炼和高度优化的内部循环。它的最坏情形的性能为O(N^2),但稍加努力就可避免这种情形。通过将堆排序与快速排序结合起来,就可以在堆排序的最坏运行时间下,得到对几乎所有输入的最快运行时间。

#include<stdio.h>//分为两个区,左边的数都比右边的数小//返回值为中间数所在的位置int Partition9int nums[],int left,int right){  int midNum=Nums[right]; //定数组左后一个数为中间数  int j=left;  for(int i=left;i<right;i++) //循环比较第i个数和中间数  {      if(Nums[i]<midNum)      //如果小于中间数,j指针向后移,j指针之前的数都小于中间数      {        if(i!=j)        {           int temp=Nums[i];           Nums[i]=Nums[j];           Nums[j]=temp;        }        j++;      }  }  //收尾工作,将中间数和j指向的中间位置的数调换  int temp=Nums[j];  Nums[j]=midNum;  Nums[right]=temp;  return j; //返回中间数的下标}void QuickSort(int Nums[],int left,int right){   if(left<right)   {      int mid=Partition(Nums,left,right);  //分区      QuickSort(Nums,left,mid-1);   //左边递归排序      QuickSort(Nums,mid+1,right);  //右边递归排序   }}int main(){    int a[]={1,0,2,9,3,8,4,7,5,6};    QuickSort(a,0,9);    for(int i=0;i<10;i++)    {      printf("%d\n",a[i]);    }    return 0;}

6、计数排序
计数排序的特单是时间复杂度,与其他的排序算法不同,它的时间复杂度为O(N+K),这个时间复杂度表明了当K相对比较大时,不适合使用,比如对集合{1, 0, 100},但是对于N远大于K的情况下,是相当适合的。

#include<stdio.h>#include<stdlib.h>#include<string.h>int data[]={1,2,1,0,4,5};//计数排序参数列表//int d[]为待排序数据列表//int n为待排序数据个数//int min,max为待排序数据中最大和最小值,用来计算待排数据跨度kvoid sort_counter(int d[],int n,int k){  int i,j=0;  k++;  //实际申请空间比k大1  //申请辅助空间  int* counter=malloc(sizeof(int)*k);  memset(counter,0,sizeof(int)*k);  //计数  for(i=0;i<n;++i)  {     ++counter[d[i]];  }  //将计数结果保存到待排序数据空间  for(i=0;i<k;++i)  {     while(counter[i]-->0)     {        d[j++]=i;     }  }  //释放辅助空间  free(counter);}int main(void){    sort_counter(data,6,5);    int i;    for(i=0;i<6;++i)    {        printf("%d\n",data[i]);    }    return 0;}

7、基数排序

#include<stdio.h>//int data[]={1,100,321,121,333,586,1100};//该函数计算data中最大位数,本例中,最大位数是1100,所以结果是4int maxbit(int data[],int n){    int d=1;  //保存最大的位数    int p=10;    for(int i=0;i<n;++i)    {        while(data[i]>=p)        {           p*=10;           ++d;        }    }    return d;}//基数排序void sort_radix(int data[],int n){    int d=maxbit(data,n);  //计算位数    int *tmp=new int[n];   //中间变量,用来存储中间排序结果    int *count=new int[10];//计数排序中的计数器    int i,j,k;    int radix=1;    //根据最大位数进行循环,对每一位进行基数排序    for(i=1;i<=d;i++)    {        //初始化计数器        for(j=0;j<10;j++)            count[j]=0;        //对位数进行计数排序        for(j=0;j<n;j++)        {            k=(data[j]/radix)%10;  //注意这里进行取模            count[k]++;        }        for(j=1;j<10;j++)            count[j]=count[j-1]+count[j];        //将排序中间结果保存到tmp        for(j=0;j<n;j++)        {            k=(data[j]/radix)%10;            tmp[count[k]-1=data[j];            count[k]--;        }        //将中间结果保存到data        for(j=0;j<n;j++)            data[j]=tmp[j];        //取模时的被除数,需要提高一位        radix=radix*10;    }    delete []tmp;    delete []count;}int main(){    int data[]={1,100,321,121,333,586,1100};    sort_radix(data,7);    for(int i=0;i<7;i++)    {        printf("%d\n",data[i]);    }    return 0;}

基数排序比较适合对取值很大的数进行排序,也可用来对字符串进行排序。但基数排序的缺点是不呈现时空局部性,因为在按位对每个数进行排序的过程中,一个数的位置可能发生巨大的变化,所以不能充分利用现代机器缓存提供的优势。同时计数排序作为中间稳定排序的话,不具有原地排序的特点,当内存容量比较宝贵的时候,还是有待商榷。

0 0
原创粉丝点击