• 【大学复健】常用排序算法的原理与代码


    洛谷模板P1177

    归并排序

    使用分治思想,后序遍历,处理好左右后,用两个指针将二者合并。
    关键点:使用动态内存定义 的数组,且最后要手动删除,防止内存爆炸。
    关键点:动态定义时,当心越界,多来几个。

    #include
    using namespace std;
    #define in read()
    #define mid ((l+r)>>1)
    int in{
    	int cnt=0,f=1;char ch=0;
    	while(!isdigit(ch)){
    		ch=getchar();if(ch=='-')f=-1;
    	}
    	while(isdigit(ch)){
    		cnt=cnt*10+ch-48;ch=getchar();
    	}return cnt*f;
    }
    const int N=100003;
    
    void merge(int a[],int l,int r){
    	if(l>=r)return;
    	merge(a,l,mid);merge(a,mid+1,r);
    	int x=r-l+1;
    	int *temp=new int[x+3];//重点
    	for(int i=l;i<=r;i++)temp[i-l+1]=a[i];
    	int i,j;i=l,j=mid+1;int cnt=0;
    	while(i<=mid&&j<=r){
    		if(a[i]<a[j]){
    			temp[++cnt]=a[i++];
    		}
    		else{
    			temp[++cnt]=a[j++];
    		}
    	}
    	while(i<=mid)temp[++cnt]=a[i++];
    	while(j<=r)temp[++cnt]=a[j++];
    	for(int k=l;k<=r;k++)a[k]=temp[k-l+1];
    
    	delete []temp;//重点
    }int n,a[N];
    signed main(){
    	n=in;
    	for(int i=1;i<=n;i++)a[i]=in;
    	merge(a,1,n);	
    	for(int i=1;i<=n;i++)cout<<a[i]<<" ";
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    堆排序

    严格的nlogn。
    首先来说明什么是堆(优先队列的一种实现方式):
    一棵完全二叉树,在指定优先级的情况下,根节点一定比两个子节点都优先(比如大根堆的任何根节点都比两个子节点大)。
    对于一个堆,基本操作包含:插入,删除,调用目前的最优先项。
    插入:在树的末尾添加元素,并不断和父节点比较,如果优先级矛盾,就swap。
    调用:输出根节点即可。
    删除:只支持删除根节点(即优先度最高项),删除后,将最后一个点抓来顶替根节点,并每次和两个儿子中优先级最高的点进行交换(否则小儿子在大儿子上面产生矛盾),换到不能换为止。
    复杂度的保证源于完全二叉树的性质。同时,因为是完全二叉树,我们大可以用一个数组来表示这棵树。初始编号1的情况下,u节点左儿子即u * 2,右儿子即u * 2+1。
    对于排序而言,不断调用根节点并做删除操作即可。

    #include
    using namespace std;
    #define in read()
    int in{
    	int cnt=0,f=1;char ch=0;
    	while(!isdigit(ch)){
    		ch=getchar();if(ch=='-')f=-1;
    	}
    	while(isdigit(ch)){
    		cnt=cnt*10+ch-48;ch=getchar();
    	}return cnt*f;
    }
    int n;
    const int N=100003;
    int a[N];
    int q[N],tot;
    void ins(int x){
    	q[++tot]=x;int u=tot;
    	while(u!=1){
    		if(q[u/2]>x)swap(q[u/2],q[u]);
    		else break;
    		u/=2;
    	}
    }
    void del(){
    	swap(q[1],q[tot]);--tot;
    	int u=1;
    	while(u*2<=tot){
    		int v=u*2;
    		if(v+1<=tot&&q[v]>q[v+1])++v;
    		if(q[u]<q[v])break;
    		swap(q[u],q[v]);
    		u=v;
    	}
    }
    signed main(){
    	n=in;
    	for(int i=1;i<=n;i++){
    		a[i]=in;//无效数组,草
    		ins(a[i]); 
    	}
    	for(int i=1;i<=n;i++){
    		printf("%d ",q[1]);del();
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    快速排序

    弱于其余二者。考虑目标升序。
    每次选择一个基准数,将小的丢到左边,大的丢到右边,再递归整左右。
    类似于中序遍历。
    妙处:不用新开数组,自己左右互相覆盖的写法有启发性。
    弱点:复杂度有波动,从n到n^2不等。所以建议使用严格nlogn的算法。

    #include
    using namespace std;
    #define in read()
    #define mid ((l+r)>>1)
    int in{
    	int cnt=0,f=1;char ch=0;
    	while(!isdigit(ch)){
    		ch=getchar();if(ch=='-')f=-1;
    	}
    	while(isdigit(ch)){
    		cnt=cnt*10+ch-48;ch=getchar();
    	}return cnt*f;
    }
    const int N=100003;
    int n,a[N];
    void Sort(int l,int r){
    	if(l>=r)return;
    	int tp=a[l];
    	int i=l,j=r;
    	while(i<j){
    		while(j>i&&a[j]>tp)--j;
    		a[i]=a[j];
    		while(i<j&&a[i]<=tp)++i;
    		a[j]=a[i];
    	}a[i]=tp;
    	Sort(l,i-1);Sort(i+1,r);
    }
    signed main(){
    	n=in;for(int i=1;i<=n;i++)a[i]=in;
    	Sort(1,n);
    	for(int i=1;i<=n;i++)printf("%d ",a[i]);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
  • 相关阅读:
    兄弟凶弟凶帝
    [论文阅读] 颜色迁移-Automated Colour Grading
    传奇单机架设教程,五分钟完成单机架设
    uniapp中videojs、renderjs的使用
    java 基础5道题
    find命令-随心所欲查找服务器的文件
    Java 日志框架,性能无敌横扫所有对手
    数据结构--栈和队列
    IPsec协议
    数据结构:二叉搜索树
  • 原文地址:https://blog.csdn.net/qq_42835815/article/details/126790056