【算法学习】排序

排序这个东西真的挺卷的,有些就追求极致的速度,有些追求极致的简洁,有必要学一学提一提,尽管 \(sort\) 能解决绝大部分问题。

学习笔记

优缺点

冒泡排序

mpft

冒泡

第一个学的排序也是最简单的排序,也就是一个一个比较,如果右边的数大于左边的数就交换,我当初老师说这一个一个交换是不是就像冒泡一样,那确实哈。

#include<bits/stdc++.h>
using namespace std;
int n;
int a[100000];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n-i;j++){
			if(a[j]>a[j+1]){
				swap(a[j],a[j+1]);
			}
		}
	}
	for(int i=1;i<=n;i++){
		cout<<a[i]<<" ";
	}
	return 0;
}

选择排序

排序

就如同他的名字一样,每次从剩下的区间的中选择最小的数放到区间最开始,确实挺好理解。

#include <bits/stdc++.h>
using namespace std;
int n;
int a[1000000];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		int minn=10000,id=0;
		
		for(int j=i;j<=n;j++){
			 if(a[j]<minn){
			 	 id=j;
			 	 minn=a[j];
			 }
		}
		swap(a[i],a[id]);
	}
	for(int i=1;i<=n;i++){
		cout<<a[i]<<" ";
	}
	return 0;
}

插入排序

排序

感觉和选择排序有点像,每个数向前找,如果比他大就交换位置,如果小就停止判断下一个数。

#include <bits/stdc++.h>
using namespace std;
int n;
int a[1000000];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=i;j>=1;j--){
			if(a[j]<a[j-1]){
			 	swap(a[j],a[j-1]);
			}
			else{
			 	break;
			}
		}
	}
	for(int i=1;i<=n;i++){
		cout<<a[i]<<" ";
	}
	return 0;
}

堆排序

排序

用一个堆的数据结构来维护单调性,单调队列的底层原理,后来的平衡树还会再见的。

stl

#include <bits/stdc++.h>
using namespace std;
#define ll long long 
ll n;
ll a[50005];
priority_queue<ll,vector<ll>,greater<ll> > q;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		q.push(a[i]);
	}

	
	for(int i=1;i<=n;i++){
		cout<<q.top()<<"\n";
		q.pop();
	}

	return 0;
}

手写堆

#include <bits/stdc++.h>
using namespace std;
int n,x;
int heap[1000005];
int siz=0; 
void up(int idx){
	while(idx!=1 && heap[idx]<heap[idx/2]){
		swap(heap[idx],heap[idx/2]);
		idx/=2;
	}
}
void add(int k){
	heap[++siz]=k;
	up(siz);
}

void down(int idx){
	int r=idx;
	if(heap[r]>heap[idx*2]&&idx*2<=siz){
		r=idx*2;
	}
	if(heap[r]>heap[idx*2+1]&&idx*2+1<=siz){
		r=idx*2+1;
	}
	if(r==idx){
		return;
	}
	swap(heap[r],heap[idx]);
	down(r);
} 
void del(){
	heap[1]=heap[siz--];
	down(1);	
}
int main (){
	cin>>n;
	while(n--){
		cin>>x;
		if(x==1){
			cin>>x;
			add(x);
		}
		else if(x==2){
			cout<<heap[1]<<endl;		
		}
		else{
			del();
		}
	}
	return 0;
}

归并排序

分而治之好

1.逆序对

排序

排序

发明分治的人真是个人才,真的太厉害了,像我们的线段树最底层就是靠分治来实现的,而分治排序就更厉害了,直接把逆序对秒了。

#include<bits/stdc++.h>
using namespace std;
int n;
int a[100005];
int b[100005];
void mergee(int l,int r){
	int mid=(l+r)>>1;
	int lp=l,rp=mid+1,x=l;//左端到中间,中间到右端点 
	//x=l 为了最后修改在原数组的位置的数 
	while(lp <= mid && rp <= r){ 
		if(a[lp]<=a[rp]){//左右比较 
			b[x++]=a[lp];//修改b 
			lp++;
		}
		else{
			b[x++]=a[rp];
			rp++;
		}
	}
	while(lp<=mid){//左边没到中间,比已经排好的打,依次放入最后 
		b[x++]=a[lp];
		lp++;
	}
	while(rp<=r){
		b[x++]=a[rp];
		rp++;
	}
	for(int i=l;i<=r;i++){//修改原数组 
		a[i]=b[i];
	}
  	return;
}
void mergesort(int l,int r){
	if(l==r){//缩小到一个点返回 
		return;
	}
	int mid=(l+r)>>1;//分治 
	mergesort(l,mid);//左区间 
	mergesort(mid+1,r);//右区间 
	mergee(l,r);//合并左右区间 
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	mergesort(1,n);
	for(int i=1;i<=n;i++){
		cout<<a[i]<<" ";
	}
	return 0;
} 

基数排序

排序

依次对每一位进行排序,对排序后进行整理后继续对按位排序,直到全部数排完序为止。

#include<bits/stdc++.h>
using namespace std;
int n;
int a[100005];
vector<int> v[10];
int mod=1;
void solve(){
	for(int i=1;i<=10;i++){
		for(int j=1;j<=n;j++){
			v[(a[j]/mod)%10].push_back(a[j]);
		}
		int cnt=1;
		for(int k=0;k<=9;k++){
			for(int j=0;j<v[k].size();j++){
				a[cnt++]=v[k][j];
			}
			v[k].clear();
		}
		mod*=10;
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	solve();
	for(int j=1;j<=n;j++){
		cout<<a[j]<<" ";
	}
	return 0;
}
posted @ 2024-08-27 19:51  sad_lin  阅读(6)  评论(0编辑  收藏  举报