八种常用排序算法

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define LEN 10
// 1 冒泡:将序列每轮找出的最大值从下标n到0依次存放
void Bubble(int * data,int len){
int i,j; 
for (i=0;i<len;i++){ /*1从第一个元素开始,将相邻元素进行比较,如果前面元素大于后面元素则交换
  2从第一对到最后一对,做步骤1的操作,这样遍历一次最后的元素就为数组最大的元素
  3对除了最后一个元素的其他元素进行以上步骤
  4因为每次都会找出一个最大元素并放在最后,那么每次比较的元素下标值都会-1,直到没有元素比较*/
for(j=0;j<len-i-1;j++){//每次比较次数-1
if(data[j]>data[j+1]){
int temp=data[j];
data[j]=data[j+1];
data[j+1]=temp;
}
}
}
}
//2 直插
void Insert(int array[],int n){
int i,j,temp;//从第二个位置开始比较
for(i=1;i<n;i++){//i=1 因为j要指向前一个元素
if(array[i]<array[i-1]){//1从第二个元素开始与其左边的数进行比较,比前小则插入在左边元素的前面,左边的元素后移
temp = array[i];
for(j = i-1/*从左边元素开始*/;j>=0&&array[j]>temp;j--){//2大的元素后移且把要找到一个小于temp的值为止执行操作3
array[j+1] = array[j];//较小值移动到较大值的位置
}
array[j+1] = temp;//3 将array[i]放到正确位置上 这里的原来等于j = i-1;
}//4 依次遍历第二个以后的元素,重复上述操作
}
}//基本有序 记录数少  比较快  n^2  分个小组就可以形成这样的条件了
//3 希尔
void Shell(int array[],int n)//希尔排序是插入排序的优化版
{ int i,j,temp;
int d = n;
do{
d = d/3+1;//增量,它的值在排序过程中从大到小,直到最后一趟排序减为1 最好为奇数,且相邻的值避免互为倍数
for(i=d;i<n;i++){//i=d 因为j=i-d要指向前一个元素
if(array[i]<array[i-d]){
temp = array[i];
for(j = i-d;j>=0&&array[j]>temp;j-=d){
array[j+d] = array[j];
}
array[j+d] = temp;
}
}
}while(d>1);
}
//4 选择:依次找出最小值从下标0开始存放
void Selection(int *data,int len){ 
//1 从第一个元素开始 假定取出的数为最小值 记录下标 如后比最小还小记录下标
//2 比较到最后元素完毕交换 data[min]与当前(第一个)元素
//3 再从下一个元素 假定它为最小值 依次类推重复步骤1   //                                 2直到最后第二个元素
int i,j;
for (i=0;i<len;i++){
int min=i;
for (j=i+1;j<len;j++){
if(data[min]>data[j])
min=j;
}
if(data[min]!=data[i]){
int temp=data[i];
data[i]=data[min];
data[min]=temp;
}
}
}
//5 快排
void Quick(int *data,int left,int right){/*思路:1通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有
        数据都要小,
       2然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
   1 找到一个基准,用i,j两个指针分别从两边进行扫描,左边元素如果小于基准 i后移继续比较*/
int i=0,j=0;
int p=(left+right)/2;//此指针会一直移动,指向被交换的元素位置
int pivot=data[p];
for(i=left,j=right;i<j;){
while(i<p&&data[i]<pivot) 
i++;//在条件为基准值左边,移动扫描,遇到大于基准值时停止
if(i<p){
data[p]=data[i];//如果i在p的左边,且比当前元素大于pivot 则把当前元素移动到基准位置并且把p指向当前元素的位置
p=i;
}
while(p<j&&data[j]>=pivot)
j--;
if(p<j){
data[p]=data[j];//如果比基准值小则把此元素放在当前p指向的位置(这个位置的值要把基准值小)
p=j;
}
data[p]=pivot;//还原基准值 
if(p-left>1)//p在基值右边
Quick(data,left,p-1);
if(right-p>1)
Quick(data,p+1,right);
}
}
//将有二个有序数列a[first...mid]和a[mid...last]合并。  
//6.1归并  该算法是采用分治法
void MergeArray(int a[], int first, int mid, int last, int temp[]){  
    int i = first, j = mid + 1;  
    int m = mid,   n = last;  
    int k = 0;  
      
    while (i <= m && j <= n){  
        if (a[i] <= a[j])  
            temp[k++] = a[i++];  
        else  
            temp[k++] = a[j++];  
    }        
    while (i <= m)  //其他已有序的元素插入到之前有序数列
        temp[k++] = a[i++];       
    while (j <= n)  
       temp[k++] = a[j++];       
    for (i = 0; i < k; i++)  //处理完毕的临时数组进行复制到原数组
       a[first + i] = temp[i];  
}
//6.2 递归排序 
void MergeSort(int a[], int first, int last, int temp[]){  
    if (first < last){  //只有一个元素
        int mid = (first + last) / 2;  
        MergeSort(a, first, mid, temp);    //左边有序  
        MergeSort(a, mid + 1, last, temp); //右边有序  
        MergeArray(a, first, mid, last, temp); //再将二个有序数列合并  
    }  
//7堆排序
// 堆 是一个完全二叉树
//堆排序树形选择排序在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系(Rn<=R2n;Rn<=k(2n+1);或者Rn>=R2n;Rn>=k(2n+1);),
//(由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件)
/* 
1  将待排序的序列构造成堆结构(若想排序后为升序,则构造成大顶堆,否则构造成小顶堆结构)
2  建堆完成,堆顶为整个序列的最大值,将堆顶元素与堆尾元素交换,则堆尾为最大值,再将其移走
3  将剩余n-1个序列重新建堆,则可以依次得到每次新序列中的最大值
  
*/
//array是待调整的堆数组,i是待调整的数组元素的位置,nlength是数组的长度
//7.1 
swap(int k[],int i,int j){
int temp = k[i];
k[i] =k[j];
k[j] =temp;
}
//7.2
void HeapAdjust(int array[],int i,int nLength){//建堆(大根)
    int nChild;
    for(;2*i+1<nLength/*处理位置要小于数组长度*/;i=nChild){//不仅是找一次,要循环往下再找交换
        nChild=2*i+1;//子结点位置
        //指向当前处理的最大子结点
        if(nChild<nLength-1&&array[nChild+1]>array[nChild])
++nChild;
        //如果较大的子结点大于父结点那么把较大的子结点往上移动,替换它的父结点
        if(array[i]/*根结点*/<array[nChild])
swap(array,i,nChild);
        else 
break; //否则退出循环
    }
}
// 7.3 排序堆
void HeapSort(int array[],int length){
    int i;
    //从下往上,从右往左//从下面的根节点
    for(i=length/2-1;i>=0;--i)
HeapAdjust(array,i,length);
    //从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
    for(i=length-1;i>0;--i){
//把第一个元素和当前的最后一个元素交换保证当前的最后一个位置的元素都是在现在的这个序列之中最大
swap(array,0,i);
        //不断缩小调整heap的范围,每一次调整完毕保证第一个元素是当前序列的最大值
        HeapAdjust(array,0,i);//重新建堆
    }
}
// 8 基数排序 基数排序的方式可以采用LSD(Least significant digital)或MSD(Most significant digital),LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。LSD的基数排序适用于位数少的数列,如果位数多的话,使用MSD的效率会比较好 缺点:空间利用率低,需于链表结合进行优化
/* LSD:
73, 22, 93, 43, 55, 14, 28, 65, 39, 81
1 首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中
2 接下来将这些桶子中的数值重新串接起来,成为以下的数列
  81, 22, 73, 93, 43, 14, 55, 65, 28, 39
  接着再进行一次分配,这次是根据十位数来分配
3 接下来将这些桶子中的数值重新串接起来,成为以下的数列
  14, 22, 28, 39, 43, 55, 65, 73, 81, 93
4 持续上述操作直到最高位*/
//8.1 LSD
 int MaxBit(int data[], int n){//辅助函数,求数据的最大位数
    int d = 1; //保存最大的位数
    int p = 10;
int i;
    for(i = 0; i < n; ++i){
        while(data[i] >= p){
            p *= 10;
            ++d;
        }
    }
    return d;
}
//8.2
void RadixSort(int data[], int n){
    int d = MaxBit(data, n);
    int *tmp = malloc(n*sizeof(int));
    int *count = malloc(n*sizeof(int)); //计数器
    int i, j, k;
    int radix = 1;
    for(i = 1; i <= d; i++){//进行d次排序
        for(j = 0; j < LEN; j++)
            count[j] = 0; //每次分配前清空计数器
        for(j = 0; j < LEN; j++){
            k = (data[j] / radix) % 10; //统计每个桶中的记录数便于在tmp中找到它的位置
            count[k]++;
        }
        for(j = 1; j < 10; j++)
            count[j] += count[j - 1]/*前面所有的记录数*/; //调整桶号
        for(j = n - 1; j >= 0; j--){//计算桶号在tmp中对应的位置
            k = (data[j] / radix) % 10;//桶编号
            tmp[count[k] - 1] = data[j];//找到对应位置存放
            count[k]--;//处理下一个桶号
        }
        for(j = 0; j < n; j++) //根据低位到高位的调整(原数组)
            data[j] = tmp[j];
        radix = radix * 10;
    }
}
void Print(int *data,int DataLength){
int i;
printf("sorted: ");
for(i=0;i<DataLength;i++){
printf("%d ",data[i]);
}
}
void GetRandomNumber(int *data,int n){
int i;
for(i=0;i<LEN;i++){
data[i]=rand()%(LEN*2);
}
}
int main(void){
srand(time(0));
int data[LEN],i;
GetRandomNumber(data,LEN);
printf("before sorting:");
for(i=0;i<LEN;i++){
printf("%d ",data[i]);
}
printf("\n");
// Bubble(data,sizeof(data)/sizeof(int));
// Insert(data,sizeof(data)/sizeof(int));
// Selection(data,sizeof(data)/sizeof(int));
// Quick(data,0,sizeof(data)/sizeof(int)-1);
// Shell(data,sizeof(data)/sizeof(int));
// int temp[LEN];
// MergeSort(data,0,sizeof(data)/sizeof(int)-1,temp);
// HeapSort(data,sizeof(data)/sizeof(int));
RadixSort(data,LEN);
Print(data,sizeof(data)/sizeof(int));//下标为1开始 为堆顶
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值