【PTA】排序算法

本文详细展示了冒泡排序、优化后的冒泡排序、插入排序、希尔排序、选择排序、堆排序、归并排序(递归与非递归两种方式)和快速排序的C++实现。这些排序算法在计算机科学中有着广泛的应用,理解并掌握它们对于提升编程技能至关重要。
部署运行你感兴趣的模型镜像

 

 

在PTA例子中的体现:

一、冒泡排序

//1:没有优化的冒泡排序
#include <iostream>
#define MAXN 100001
using namespace std;

int a[MAXN];

void Bubble_Sort(int* a,int N){
    //N-1趟
    for(int k=N-1;k>0;k--){
        for(int i=0;i<k;i++){
            if(a[i]>a[i+1]){
                int tmp=a[i];
                a[i]=a[i+1];
                a[i+1]=tmp;
            }
        }
    }
}

//2:优化后的冒泡排序
#include <iostream>
#define MAXN 100001
using namespace std;

int a[MAXN];

void Bubble_Sort(int* a,int N){
    //N-1趟
    for(int k=N-1;k>0;k--){
        int flag=0;
        for(int i=0;i<k;i++){
            if(a[i]>a[i+1]){
                int tmp=a[i];
                a[i]=a[i+1];
                a[i+1]=tmp;
                flag=1;
            }
        }
        if(!flag) return;
    }
}

二、插入排序

#include <iostream>
#define MAXN 100001
using namespace std;

int a[MAXN];

void Insert_Sort(int* a,int N){
   int j;
   for(int i=1;i<N;i++){
       int tmp=a[i];
       for(j=i-1;j>=0;j--){
           if(a[j]>tmp) a[j+1]=a[j];//往后挪
           else break;
       }
       a[j+1]=tmp;//一定要一开始就存一下a[i],不然第一次挪位置a[i]就丢了
   }
}

三、希尔排序

#include <iostream>
#define MAXN 100001
using namespace std;

int a[MAXN];

void Shell_Sort(int* a,int N){
   int j,D,Si;
   int Sedgewick[] = {929, 505, 209, 109, 41, 19, 5, 1, 0};
   for(Si=0;Sedgewick[Si]>=N;Si++);
    /* 初始的增量Sedgewick[Si]不能超过待排序列长度 */

    for(D=Sedgewick[Si];D>0;D=Sedgewick[++Si]){
         for(int i=D;i<N;i++){
            //每次第0张已经在手上,从第D张开始
                int tmp=a[i];
                for(j=i-D;j>=0;j-=D){
            //第D张前面一张开始比较
                    if(a[j]>tmp){
                        a[j+D]=a[j];
                    }else break;
                }
                a[j+D]=tmp;
         }
    }
   
}

 四、选择排序

#include <iostream>
#define MAXN 100001
using namespace std;

int a[MAXN];

void Select_Sort(int* a,int N){
    for(int i=0;i<N;i++){
        //FindMin
        int min=a[N-1],minId=N-1;
        for(int j=i;j<N;j++){
            if(a[j]<min){
                min=a[j];
                minId=j;
            }
        }
        //SwapMin
        int t=a[minId];
        a[minId]=a[i];
        a[i]=t;
    }
}

五、堆排序 

#include <iostream>
#define MAXN 100001
using namespace std;

int a[MAXN];

//没有哨兵,a[i]中i是从0到N-1
void PerDown(int i,int N){
    int tmp=a[i];
    int parent,child;
    for(parent=i;(parent*2+1)<N;parent=child){
        child=parent*2+1;
        if((child!=N-1) && a[child+1]>a[child]){
            child++;
        }
        if(a[child]>tmp)    a[parent]=a[child];
        else                break;
    }
    a[parent]=tmp;
}

void Heap_Sort(int* a,int N){
//1:Build MaxHeap
    for(int i=N/2;i>=0;i--){
        PerDown(i,N);
    }
    for(int i=N-1;i>0;i--){
//2:swap Max to the end
        int t=a[i];
        a[i]=a[0];
        a[0]=t;
//3:adjust MaxHeap
//改变一个点只会改变一条路径
        PerDown(0,i);
    }
    
}

六、归并排序

Merge函数:实现两个内部有序的子序列的归并

//1:递归版
#include <iostream>
#define MAXN 100001
using namespace std;

int a[MAXN];

//两个有序子列的归并
void Merge(int* A,int* TmpA,int Left,int Right,int RightEnd){
    int LeftEnd=Right-1;
    int num=RightEnd-Left+1;
    int TmpA_p=Left;

    while ( Left<=LeftEnd && Right<=RightEnd){
        if(A[Left]<A[Right]) TmpA[TmpA_p++]=A[Left++];
        else                 TmpA[TmpA_p++]=A[Right++];
    }

    while(Left<=LeftEnd){
        TmpA[TmpA_p++]=A[Left++];
    }
    while(Right<=RightEnd){
        TmpA[TmpA_p++]=A[Right++];
    }

    for(int i=0;i<num;i++,RightEnd--){
        A[RightEnd]=TmpA[RightEnd];
    }
}

//分而治之
void MSort(int* A,int* TmpA,int Left,int RightEnd){
    int center;
    if(Left<RightEnd){
        center=(Left+RightEnd)/2;
        MSort(A,TmpA,Left,center);
        MSort(A,TmpA,center+1,RightEnd);
        Merge(A,TmpA,Left,center+1,RightEnd);
    }
}

void Merge_Sort(int* a,int N){
    int* TmpA=new int[N];
    if(TmpA){
        MSort(a,TmpA,0,N-1);
    }
    else printf("空间不足\n");  
}

//2:非递归版
#include <iostream>
#define MAXN 100001
using namespace std;

int a[MAXN];

void Merge1(int* A,int* TmpA,int Left,int Right,int RightEnd){
    int LeftEnd=Right-1;
    int num=RightEnd-Left+1;
    int TmpA_p=Left;

    while ( Left<=LeftEnd && Right<=RightEnd){
        if(A[Left]<A[Right]) TmpA[TmpA_p++]=A[Left++];
        else                 TmpA[TmpA_p++]=A[Right++];
    }

    while(Left<=LeftEnd){
        TmpA[TmpA_p++]=A[Left++];
    }
    while(Right<=RightEnd){
        TmpA[TmpA_p++]=A[Right++];
    }

//Merge1不用做Merge中将元素贴回原数组A的这一步
//归并结果存储在TmpA中

    /*for(int i=0;i<num;i++,RightEnd--){
        A[RightEnd]=TmpA[RightEnd];
    }*/
}

void Merge_pass(int* A,int* TmpA,int N,int length){
    int i;
//i是新子序列的首元素
    for(i=0;i<=N-2*length;i+=2*length){
        Merge1(A,TmpA,i,i+length,i+2*length-1);
    }
//最后是不是比一个length还多
//只要比一个length多1就是两个子列,可以归并
//第二个子列最后一个元素一定是A[N-1]
//不然的话只有一个子列只能贴在末尾(内部有序)
//等待最后一步使整个序列完全有序
    if(i+length<N){
        Merge1(A,TmpA,i,i+length,N-1);
    }else{
        for(int j=i;j<N;j++) TmpA[j]=A[j];
    }
}

void Merge_Sort(int* A,int N){
    int length=1;//初始化子序列长度

    int* TmpA=new int[N];
    if(TmpA){
        while(length<N){
            Merge_pass(A,TmpA,N,length);
            length*=2;
            Merge_pass(TmpA,A,N,length);
            length*=2;
        }
        delete(TmpA);
    }
    else printf("空间不足\n");  
}

七、快速排序

#include <iostream>
#define MAXN 100001
using namespace std;

//或者直接用库函数swap(int,int)也行
void swap1(int* a,int* b){
    int t=*a;
    *a=*b;
    *b=t;
}

void Insertion_Sort(int* a,int N){
    int j;
    int tmp;
    for(int i=1;i<N;i++){
        tmp=a[i];
        for(j=i-1;j>=0;j--){
            if(a[j]>tmp) a[j+1]=a[j];
            else         break;
        }
        a[j+1]=tmp;
    }
}


int Median3(int* a,int Left,int Right){
    int center=(Left+Right)/2;
    if(a[center]<a[Left])  swap1(&a[center],&a[Left]);
    if(a[Left]>a[Right])   swap1(&a[Left],&a[Right]);
    if(a[center]>a[Right]) swap1(&a[center],&a[Right]);
    
    swap1(&a[Right-1],&a[center]);
    return a[Right-1];
}

void QSort(int* a,int Left,int Right){
    int Cutoff=200;
//Cutoff不能取1,算High会越界
    if(Cutoff<=Right-Left){
        int Pivot=Median3(a,Left,Right);
        //Pivot主元的值
        int Low=Left,High=Right-1;
        while(1){
            while(a[++Low]<Pivot) ;
            while(a[--High]>Pivot);
            if(Low<High) swap1(&a[Low],&a[High]);
            else break;
        }
        //Low是正确的主元位置
        swap1(&a[Low],&a[Right-1]);
        
        QSort(a,Left,Low-1);
        QSort(a,Low+1,Right);
    }
    else Insertion_Sort(a+Left,Right-Left+1);
}

void Quick_Sort(int* a,int N){
    QSort(a,0,N-1);
}
#include<stdio.h>
#include<stdlib.h>
int a[1010];
int n;
void partition(int begin,int last){
 if(begin>=last) return;
    
 int key=a[begin];
 int left=begin,right=last;
 while(1){
    while(a[right]>key){
        if((right-1)>=begin) right--;
        else break;
    }
    while(a[left]<=key){
        if(left+1<=last) left++;
        else break;
    }
    if(left<right){
        int t=a[left];
        a[left]=a[right];
        a[right]=t;
    }else break;
 }
 a[begin]=a[right];
 a[right]=key;


 for(int i=0;i<n;i++){
        printf("%d ",a[i]);
 }
 printf("\n");
 
 partition(begin,right-1);
 partition(right+1,last);
}

int main(){
 scanf("%d",&n);
 for(int i=0;i<n;i++){
  scanf("%d",&a[i]); 
 }

 
 partition(0,n-1);
  
  for(int i=0;i<n;i++){
     printf("%d ",a[i]);
}
 
 return 0;
} 

八、基数排序

  

//版本1:只适用于0和正整数大小,没法比较负数
#include <iostream>
#define MAXN 100001
using namespace std;

#define MaxDigit 10//最大MaxDigit位数,最多MaxDigit个关键字
#define Radix 10  //进制基数,桶数量

struct node
{
    int key;
    node* next;
};

struct HeadNode{
    node* head;
    node* tail;
};
typedef HeadNode Bucket[Radix];//Radix个桶

int GetDigit(int x,int D){
//获取x第D次位上的数
    int d;
    for(int i=1;i<=D;i++){
        d=x%Radix;
        x/=Radix;
    }
    return d;
}

void Radix_LSD_Sort(int* a,int N){
    Bucket B;
    //初始化每个桶为空链表
    for(int i=0;i<Radix;i++){
        B[i].head=B[i].tail=NULL;
    }
    //将初始待排序列逆序存入初始链表List
    node* List=NULL;
    node* tmp;
    for(int i=0;i<N;i++){
        tmp=new node;
        tmp->key=a[i];
        tmp->next=List;
        List=tmp;
    }

    //开始排序
    int Di;
    for(int D=1;D<=MaxDigit;D++){//对每个次位依次处理
        node* p=List;
        while(p){
            //获得当前元素(p->key)的当前位(D)上数字
            Di=GetDigit(p->key,D);
            //从List中摘除,此时p为头结点,只需要指向下一个就行了
            tmp=p;p=p->next;
            tmp->next=NULL;
            //插入B[Di]号桶尾
            if(B[Di].head==NULL) B[Di].head=B[Di].tail=tmp;//当为空桶时
            else{
                B[Di].tail->next=tmp;
                B[Di].tail=tmp;
            }
        }
        //收集本轮排序结果过程
        List=NULL;//重复利用List
        for(int Di=Radix-1;Di>=0;Di--){
            //如果桶不为空,整桶倒插进List
            if(B[Di].head){
                B[Di].tail->next=List;
                List=B[Di].head;
                B[Di].head=B[Di].tail=NULL;
            }
        }
    }
    //将最终排序结果List倒入a,并释放空间
    for(int i=0;i<N;i++){
        tmp=List;
        List=List->next;
        a[i]=tmp->key;
        delete tmp;
    }

}
//版本2:支持负数的基数排序
//利用偏移量,注意修改最大位数
//为了防止溢出,可能还需要修改key的类型
#include <iostream>
#define MAXN 100001
using namespace std;

#define keyType long long int
#define OFFSET 10000000000
#define MaxDigit 13//最大MaxDigit位数,最多MaxDigit个关键字
#define Radix 10  //进制基数,桶数量

struct node
{
    keyType key;
    node* next;
};

struct HeadNode{
    node* head;
    node* tail;
};
typedef HeadNode Bucket[Radix];//Radix个桶

int GetDigit(keyType x,int D){
//获取x第D次位上的数
    int d;
    for(int i=1;i<=D;i++){
        d=x%Radix;
        x/=Radix;
    }
    return d;
}

void Radix_LSD_Sort(int* a,int N){
    Bucket B;
    //初始化每个桶为空链表
    for(int i=0;i<Radix;i++){
        B[i].head=B[i].tail=NULL;
    }
    //将初始待排序列逆序存入初始链表List
    node* List=NULL;
    node* tmp;
    for(int i=0;i<N;i++){
        tmp=new node;
        tmp->key=a[i]+OFFSET;
        tmp->next=List;
        List=tmp;
    }

    //开始排序
    int Di;
    for(int D=1;D<=MaxDigit;D++){//对每个次位依次处理
        node* p=List;
        while(p){
            //获得当前元素(p->key)的当前位(D)上数字
            Di=GetDigit(p->key,D);
            //从List中摘除,此时p为头结点,只需要指向下一个就行了
            tmp=p;p=p->next;
            tmp->next=NULL;
            //插入B[Di]号桶尾
            if(B[Di].head==NULL) B[Di].head=B[Di].tail=tmp;//当为空桶时
            else{
                B[Di].tail->next=tmp;
                B[Di].tail=tmp;
            }
        }
        //收集本轮排序结果过程
        List=NULL;//重复利用List
        for(Di=Radix-1;Di>=0;Di--){
            //如果桶不为空,整桶倒插进List
            if(B[Di].head){
                B[Di].tail->next=List;
                List=B[Di].head;
                B[Di].head=B[Di].tail=NULL;
            }
        }
    }
    //将最终排序结果List倒入a,并释放空间
    for(int i=0;i<N;i++){
        tmp=List;
        List=List->next;
        a[i]=tmp->key-OFFSET;
        delete tmp;
    }

}

int main(){
    int N;
    int a[MAXN];
    scanf("%d",&N);

    for(int i=0;i<N;i++){
        scanf("%d",&a[i]);
    }
    
    Radix_LSD_Sort(a,N);
    
    int flag=0;
    for(int i=0;i<N;i++){
        if(flag) printf(" %d",a[i]);
        else{
            printf("%d",a[i]);
            flag=1;
        }
    }
    
    system("pause");
    return 0;
}

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值