数据结构-排序算法代码

本文详细介绍了多种排序算法,包括插入排序(直接插入、折半插入)、希尔排序、交换排序(快速排序)、冒泡排序、双冒泡排序、选择排序、堆排序、二路归并排序以及基数排序,分析了它们的时间复杂度、空间复杂度和稳定性特点。
摘要由CSDN通过智能技术生成

目录

插入排序

直接插入排序

希尔排序

折半插入

交换排序

快速排序

 冒泡排序

双冒泡

选择排序

简单选择排序

堆排序

二路归并排序

基数排序


插入排序

直接插入排序

//直接插入排序,时间O(n²),空间O(1),稳定
void InsertSort(ElemType A[],int n){
    int i,j;
    for(i=2;i<=n;i++) //将第一个元素视为一个有序表,从第二个元素开始依次将后续元素插入有序表
        if(A[i-1]>A[i]){ //判断当前A[i]关键码在有序表后是否已经满足
            A[0]=A[i];   //A[0]位置本身不存储元素,用来放置排序时的待插入元素
            for(j=i-1;A[0]<A[j];--j)    //从后往前只要满足待调整元素小于当前元素就后挪,直到找到带插入位置
                A[j+1]=A[j];  //往后挪置
            A[j+1]=A[0];      //待插入元素插入有序表中相应的位置
        }
}

希尔排序

//希尔排序,最坏O(n²),空间O(1),不稳定(当相同关键字被划分到不同子表时,会改变他们的相对次序)
void ShellSort(ElemType A[],int n){  
    int dk,i,j;
    for(dk=n/2;dk>=1;dk=dk/2){ //dk是比较元素时的"增量"
        //此处和直接插入排序一样,就是把1换成了dk,记忆时可以同直接插入一起比较记忆
        for(i=dk+1;i<=n;++i){  //从1+dk的位置开始,遍历后面每一个元素
            if(A[i-dk]>A[i]){
                A[0]=A[i];
                for(j=i-dk; j>0 && A[0]<A[j];j=j-dk)
                    A[j+dk]=A[j];
                A[j+dk]=A[0];
            }
        }
    }      
}

折半插入

//折半插入排序,减少了比较次数,元素移动次数未变,时间复杂度仍为O(n²),稳定
void BinaryInsertSort(ElemType A[],int n){
    int i,j,low,high,mid;
    for(i=2;i<=n;i++){
        A[0]=A[i];

        low=1;high=i-1;
        while(low<=high){//在有序表中通过折半比较找到待插入位置
            mid=(low+high)/2;
            if(A[0]<A[mid]) high=mid-1;//待插入元素比中间位置小,则在有序表左半部分继续查找
            else low=mid+1;
        }
        for(j=i-1;j>=high+1;--j) //与直接插入排序相比,终止条件变了,因为已经知道待插入位置了,为high+1处
            A[j+1]=A[j];
        A[j+1]=A[0];
    }
}

交换排序

快速排序

//快速排序 时间O(nlogn),空间O(logn),不稳定(若右端有两个相同关键字,且都比枢纽小,则相对位置发生变化)
int Partition(ElemType A[],int low,int high){
    ElemType pivot=A[low];  //A[low]挖一个空,右边的比枢纽小的放到左边low处,左边的比枢纽大的放右边high处,交替进行
    while(low<high){
        while(low<high && pivot<=A[high]) --high;  //默写代码时注意,这里low<high又重复了一次
        A[low]=A[high];
        while(low<high && A[low]<=pivot) ++low;
        A[high]=A[low];
    }
    A[low]=pivot;
    return low;
}
void QuickSort(ElemType A[],int low,int high){
    if(low<high){
        int pivotpos=Partition(A,low,high);//排序一次,并返回枢纽最终位置,将表分为两部分,对左右分别再排序
        QuickSort(A,low,pivotpos-1);//对左边的表进行排序
        QuickSort(A,pivotpos+1,high);//对右边的表进行排序
    }
}

Partition函数:(对表按照某个枢纽进行一次排序,并返回枢纽位置)

将A[low]作为枢纽,最终将他插到表中间的某个位置,使得枢纽左边的元素比枢纽小,右边的元素比枢纽大。故high位置的元素若已经满足就high--,直到一个元素不符合,即比枢纽小,那它就要放到枢纽左边去,放到low的位置。若low位置的元素已经满足条件就low++,直到一个元素不符合,即比枢纽大,那它就要放到枢纽右边去,放到high的位置。最终high=low跳出while循环,并将保存的枢纽元素放到A[low]位置,返回枢纽的位置low

QuickSort函数:递归函数,每次递归对表进行一次排序,并利用返回的枢纽位置对左右表再排序

 冒泡排序

//冒泡排序,时间O(n²),空间O(1),稳定
void swap(ElemType &a,ElemType &b){
    ElemType temp;
    temp=a;a=b;b=temp;
}
//此处为获得升序有序序列,每次将最小的元素冒到开头
void BubbleSort(ElemType A[],int n){  
    for(int i=0;i<n-1;i++){    //冒泡的最终位置
        bool flag=false;       //是否发生交换的标志
        for(int j=n-1;j>i;j--) //j从最后一个元素开始,到冒泡最终位置的后一位
            if(A[j-1]>A[j]){   //若构成逆序,即后一个元素小于前一个元素,则交换位置
                swap(A[j-1],A[j]);
                flag=true;
            }
        if(flag==false)     //未发生交换,则说明序列已经有序
            return;
    }
}

双冒泡

//双冒泡
void DoubleBubbleSort(ElemType A[],int n){
    for(int i=0;i<(n-1)/2;i++){
        bool flag=false;
        //最小元素冒到表头
        for(int j=n-1;j>i;j--)
            if(A[j-1]>A[j]){
                swap(A[j-1],A[j]);
                flag=true;
            }
        //最大元素冒到表尾
        for(int j=0;j<n-1-i;j++) //注意此处终止条件
            if(A[j]>A[j+1]){
                swap(A[j],A[j+1]);
                flag=true;
            }
        if(flag==false)
            return;
    }
}

选择排序

简单选择排序

//简单选择排序  时间O(n²),空间O(1),不稳定(涉及交换的四个算法除了冒泡都不稳定)
void SelectSort(ElemType A[],int n){
    for(int i=0;i<n-1;i++){ //对前n-1个位置进行变换,每次选择后序元素中最小的元素进行交换
        int min=i,j;
        for(j=i+1;j<n;j++)
            if(A[j]<A[min]) min=j;
        if(min!=j) swap(A[i],A[min]);
    }
}

堆排序

/**
 * 堆排序(大根堆)  时间O(nlogn),空间O(1),不稳定
 * 堆可视为完全二叉树,最后一个非叶节点存储在|_n/2_|中
*/
void HeapAdjust(ElemType A[],int k,int len){  //调整堆
    A[0]=A[k];      //取出A[k]暂存,将k位置空出来
    /*从待调整位置开始往下寻找,*2看其左孩子,与右孩子比大小,
      记录较大者位置,判断此时与父节点相比是否需要调整*/
    for(int i=2*k; i<=len; i*=2){  
        if(i<len && A[i]<A[i+1]) //i要<len,因为要判断A[i+1]
            i++;
        if(A[0]>=A[i]) break; //不需要调整,此时已经是大根堆了
        else{
            A[k]=A[i];
            k=i;        //k要后移到较大的子孩子的位置
        }
    }
    A[k]=A[0];   
}
void BuildMaxHeap(ElemType A[],int len){ //建立初始堆
    for(int i=len/2;i>0;i--)
        HeapAdjust(A,i,len);
}
void HeapSort(ElemType A[],int len){  //堆排序
    BuildMaxHeap(A,len);
    for(int i=len; i>1; i--){   //len-1趟排序,每次挑出一个最大的元素,即堆顶,放到最后,然后将剩下的元素调整
        swap(A[i],A[1]);        //输出堆顶元素,和堆底元素交换,换到堆的最后(相当于将最大元素输出了),len--,再对剩余元素排序
        HeapAdjust(A,1,i-1);    //从堆顶开始调整
    }
}

二路归并排序

//归并排序  时间O(nlogn)[共需logn趟,每趟n],空间O(n),稳定(merge不改变相对次序)
int n=4;
ElemType *B=(ElemType *)malloc((n+1)*sizeof(ElemType));  //辅助数组
void Merge(ElemType A[],int low,int mid,int high){       //需要mid将A划分为两个子表进行归并
    int i,j,k;
    for(k=low;k<=high;k++)                               //将A中元素复制到B中,再从B中比较挑选元素放到A中,A为最后结果
        B[k]=A[k];
    for(i=low,j=mid+1,k=i; i<=mid && j<=high; k++)
    {
        if(B[i]<=B[j])
            A[k]=B[i++];
        else
            A[k]=B[j++];
    }
    while(i<=mid)  A[k++]=B[i++];       //子表1中有剩余,则将剩余元素加入到A中
    while(j<=high) A[k++]=B[j++];
}
void MergeSort(ElemType A[],int low,int high){ //先划分后归并
    if(low<high){
        int mid=(low+high)/2;       //从中间划分为两个子序列
        MergeSort(A,low,mid);       //对左边子序列继续划分
        MergeSort(A,mid+1,high);    //对右边子序列继续划分
        Merge(A,low,mid,high);      //归并
    }
}

基数排序

/**
 * 时间O(d(n+r))[d趟,一趟分配O(n),收集O(r)]
 * 空间O(r)[r个队列]
 * 稳定(不改变相对顺序)
 */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不科学的爆炸短发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值