基础排序专题(从插入选择到快排分治)

本部分内容借鉴于OI Wiki,详情可查阅该网站

插入排序

#include<bits/stdc++.h>
using namespace std;
void Isort(vector<int>& a,int len){
	for(int i = 1;i < len;i++){
		int key = a[i];//基准数
		int j = i - 1;
		while(j >= 0 && a[j] > key){//从基准数往左找,找插入位置 
			a[j + 1] = a[j];
			j--;
		}
		a[j + 1] = key;//break条件:1)已经找到数组边界  
	}//2)已经找到与基准数相比较小等于数,查找结束 
} 
int main(){
	int n;
	cin>>n;
	vector<int>a(n);
	for(int i = 0;i < n;i++)
		cin>>a[i];
	Isort(a,n);
	for(int i = 0;i < n;i++)
		cout<<a[i]<<' ';
	return 0;
}
  1. 在数组几乎有序的情况下时间复杂度为O(n)
  2. 最差O(n²)
  3. 稳定

选择排序

#include<bits/stdc++.h>
using namespace std;
void Ssort(vector<int>& a,int len){
	for(int i = 0;i < len-1;i++){
		int tem = i;
		for(int j = i+1;j < len;j++){//寻找基准数i右边的最小数 
			if(a[j] < a[tem])
				tem = j;//更新 
		}
		swap(a[i],a[tem]);//交换 i处以前为已排序部分
	}
}
int main(){
	int n;
	cin>>n;
	vector<int>a(n);
	for(int i = 0;i < n;i++)
		cin>>a[i];
	Ssort(a,n);
	for(int i = 0;i < n;i++)
		cout<<a[i]<<' ';
	return 0; 
} 
  1. 最差,最好,平均时间复杂度都是O(n²)
  2. 不稳定

冒泡排序

#include<bits/stdc++.h>
using namespace std;
void Bsort(vector<int>& a,int len){
	int flag = 1;
	while(flag){
		flag = 0;//当扫描一遍发现已经全部有序时就可以结束 
		for(int i = 0;i < len-1;i++){
			if(a[i] > a[i+1]){
				flag = 1;
				swap(a[i],a[i+1]);
			}
		}
	}
} 
int main(){
	int n;
	cin>>n;
	vector<int>a(n);
	for(int i = 0;i < n;i++)
		cin>>a[i];
	Bsort(a,n);
	for(int i = 0;i < n;i++)
		cout<<a[i]<<' ';
	return 0; 
} 
  1. 稳定
  2. 平均时间复杂度是O(n²)

计数排序

#include<bits/stdc++.h>
using namespace std;
void print(vector<int>& a,int len){
	for(int i = 0;i < len;i++)
		cout<<a[i]<<' ';
}
void Csort(vector<int>& a,int len){
	int MAX = a[0];
	int MIN = a[0];
	for(int i = 1;i < len;i++){
		MAX = max(a[i],MAX);
		MIN = min(a[i],MIN);
	}
	int w = MAX - MIN;//大小差值分块
	vector<int>t(w+1);//0 - w
	for(int i = 0;i < len;i++)
		t[a[i] - MIN]++;
	int sum = 0;
	for(int i = 0;i <= w;i++){
		sum += t[i];
		t[i] = sum;
	}//数a[i]应存储在下标为t[i]的位置 
	vector<int>ans(len);
	for(int i = len-1;i >= 0;i--){
		ans[t[a[i] - MIN] - 1] = a[i];//注意 
		t[a[i] - MIN]--;//注意 
	}
	print(ans,len); 
}
int main(){
	int n;
	cin>>n;
	vector<int>a(n);
	for(int i = 0;i < n;i++)
		cin>>a[i];
	Csort(a,n);
	return 0;
}
  1. 前缀和的使用优化保证了排序稳定
  2. 时间复杂度是O(n + w),n是元素个数,w是最大最小值的差(也就是分块个数)

快速排序

#include<bits/stdc++.h>
using namespace std;
void QuickSort(vector<int> &nums, int l, int r){//给nums[l] - nums[r] 排序
	if(l + 1 >= r)
		return;
	int fir = l;
	int last = r; 
	int key = nums[fir];//第一个数为基准数 
	while(fir < last){
		while(fir < last && nums[last] >= key)//从右往左找比基准数小的元素
			last--;
		//swap(nums[fir], nums[last]);
		while(fir < last && nums[fir] <= key) 
			fir++;
		//swap(nums[fir], nums[last]);
		if(fir < last)
			swap(nums[fir] ,nums[last]);
	}
	swap(nums[fir], nums[l]);//nums[last] = key;同理
	QuickSort(nums, l ,fir);
	QuickSort(nums, fir + 1, r); //fir处元素已排好位置
}
int main(){
	int n;
	cin>>n;
	vector<int>a(n);
	for(int i = 0;i < n;i++)
		cin>>a[i];
	QuickSort(a,0,n-1);
	for(int i = 0;i < n;i++)
		cout<<a[i]<<endl;
	return 0; 
} 
  1. 平均时间复杂度是O(nlogn),最差情况下为O(n²)(优化情况:三路快排,内省排序)
  2. 不稳定

优化情况:三路快排

#include<bits/stdc++.h>
using namespace std;
void quicksort(int arr[],int len){
	if(len <= 1)
		return;
	int key = arr[rand() % len];//随机化
	int i = 0;//表示当前元素
	int j = 0;//小于key
	int k = len;//大于key
	while(i < k){
		if(arr[i] < key)//让小于key的右一元素跟等于key的右一元素交换 
			swap(arr[i++],arr[j++]);//小于key部分增加 
		else if(arr[i] > key)//让大于key的左一元素跟等于key的右一元素交换 
			swap(arr[i],arr[--k]);//大于key部分增加 
		else//等于时不做操作 
			i++;
	}
	quicksort(arr,j);
	quicksort(arr+k,len-k);
}
int main(){
	int n;
	cin>>n;
	int arr[100];
	for(int i = 0;i < n;i++)
		cin>>arr[i];
	quicksort(arr,n);
	for(int i = 0;i < n;i++)
		cout<<arr[i]<<' ';
	return 0;
} 
/*
	本质是将数组分成三部分
	小于key || 等于key || 大于key
	 0 -- j   j+1 -- i    k -- len-1
	利用随机化排除重复元素堆积导致的时间复杂度升高情况
	这种写法的partition还可用于寻找数组中第k大元素(O(n))
*/

归并排序

#include<bits/stdc++.h>
using namespace std;
int t[101], a[101]; 
void merge(int l, int r){//给a[l]~a[r-1]的数组排序 
	if(r - l == 1)//长度为0返回空 
		return;
	int mid = l + (r - l) / 2;	
	merge(l, mid);
	merge(mid, r);
	int p = l, q = mid, s = l;//p为左侧数组指针,q为右侧数组指针,s为已复制的位置 
	while(s < r){
		if(p >= mid||(a[p] > a[q] && q < r))//对应两种情况:1)左侧已经复制完,复制右侧 2)右元素小于左边,正常复制右元素 
			t[s++] = a[q++];
		else//否则就是复制左侧元素
			t[s++] = a[p++];
	} 
	for(int i = l;i < r;i++)//复制已排序好的组合进原数组 
		a[i] = t[i];
}
int main(){
	memset(t, 0, sizeof(t));
	for(int i = 0;i < 5;i++)
		cin>>a[i];
	merge(0, 5);
	for(int i = 0;i < 5;i++)
		cout<<a[i]<<endl;
	return 0;
}
  1. 最优,平均,最差时间复杂度都是O(nlogn)
  2. 需要O(n)的空间
  3. 稳定
  4. 可用来求逆序对

堆排序

#include<bits/stdc++.h>
using namespace std;
void heapify(int arr[], int st, int en){//大根堆,节点下标从0开始,向下调整
	int root = st;
	int right = root*2+1;
	while(right <= en){
		if(right + 1 <= en && arr[right+1] > arr[right]){
			right++;
		}
		if(arr[root] > arr[right])
			break;
		else{
			swap(arr[root],arr[right]);
			root = right;
			right = root*2+1; 
		}
	}
}
void Hsort(int arr[], int len){
	for(int i = len/2-1;i >= 0;i--)//从最后一个父节点逐步向上进行向下调整 
		heapify(arr,i,len-1);
	for(int i = len - 1;i > 0;i--){//由于大根堆性质,arr[0]为部分数组的最大值
		swap(arr[0],arr[i]);//下标为i位置的节点已经排好 
		heapify(arr,0,i-1);//右边界减一,对0-i-1位置继续调整
	}
}
int main(){
	int n;
	int arr[101];
	cin>>n;
	for(int i = 0;i < n;i++)
		cin>>arr[i];
	Hsort(arr,n);
	for(int i = 0;i < n;i++)
		cout<<arr[i]<<' ';
	return 0;
}
  1. 最优,平均,最差时间复杂度都是O(nlogn)
  2. 不稳定

桶排序

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;//元素个数 
int w;//最大最小差值,用于分桶
int a[N];//存数数组
vector<int>bucket[N];//桶
void Isort(vector<int>& A){//在每个桶中进行插入排序 
	for(int i = 1;i < A.size();i++){
		int key = A[i];
		int j = i-1;
		while(j >= 0 && A[j] > key){
			A[j+1] = A[j];
			j--;
		}
		A[j+1] = key;
	}
}
void bucketsort(){
	int MIN = a[0];
	int MAX = a[0];
	for(int i = 1;i < n;i++){
		MIN = min(a[i],MIN);
		MAX = max(a[i],MAX);
	}
	w = MAX - MIN;
	int size = w/n + 1;//桶大小 
	for(int i = 0;i < n;i++)
		bucket[i].clear();//清桶 
	for(int i = 0;i < n;i++){
		bucket[(a[i]-MIN)/size].push_back(a[i]); 
	}
	int p = 0;
	for(int i = 0;i < n;i++){
		Isort(bucket[i]);
		for(int j = 0;j < bucket[i].size();j++){
			a[p++] = bucket[i][j];//桶内元素已保证相对顺序 复制回原数组 
		}
	}
} 
int main(){
	cin>>n;
	for(int i = 0; i < n;i++)
		cin>>a[i];
	bucketsort();
	for(int i = 0;i < n;i++)
		cout<<a[i]<<" ";
}
  1. 内部排序使用了插入排序保证了稳定性
  2. 在数据分布均匀时,时间复杂度为O(n)
  3. 最差情况的时间复杂度为O(n²)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值