Bootstrap

排序(数据结构)

<1>冒泡排序

冒泡排序的思想是每次将最大的一下一下运到最右边,然后将最右边这个确定下来,再来确定第二大的,再确定第三大的…由于排序过程中,数字像冒泡泡一样从左往右换过去,故名冒泡排序。时间复杂度为O(n^2)。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 9;
int a[N];

int main(){
	int n;cin >> n;  //输入3 
	for(int i = 1;i <= n;i++) cin>>a[i];  //输入1 3 2 
	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]<<' '; //输出1 2 3 
	return 0;
}

<2>选择排序

选择排序思想和冒泡排序类似,是每次找出最大的然后直接放到右边对应位置,然后将最右边这个确定下来(而不是一个一个地交换过去)。对于数组a[],具体来说,每次确定操作(假设当前要确定的是i位置)就是从左往右扫描,计算出最大元素的下标max_i,最后执行一次swap(a[max_i],a[i])将两项交换即可。和冒泡排序的区别就是,冒泡排序需要每次都交换,而选择排序则是确定了某个数第几大直接交换,时间复杂度和冒泡排序一样,都是O(n^2),但是交换的次数减少了。

#include<bits/stdc++.h>
using namespace std;

const int N = 1e3+9;
int a[N];
int main(){
	int n;cin>>n;
	for(int i = 1;i <= n;i++) cin>>a[i];
	
	//i表示当前要确定的位置
	for(int i = n;i >= 1;--i){
		int max_i = 1;
		for(int j = 1;j <= i;++j){
			if(a[j] > a[max_i]) max_i = j;
		}
		swap(a[max_i],a[i]);
	} 
	for(int i = 1;i <= n;i++) cout<<a[i]<<' ';
	return 0;
} 

#*这里的j的范围是[1,i],而在冒泡排序中j的范围是[1,i-1]。

<3>插入排序

插入排序是一种简单直观的排序算法,其基本思想是将待排序的元素逐个插入到已排序序列的合适位置中,使得已排序序列逐渐扩大,从而逐步构建有序序列,最终完全得到完全有序的序列。时间复杂度为O(n^2)。

#include<bits/stdc++.h>
using namespace std;

const int N = 1e3+9;
int a[N];
int main(){
	int n;cin>>n;
	for(int i = 1;i <= n;i++) cin>>a[i];
	for(int i = 2;i <= n;++i){
		int val = a[i],j;
		for(j = i;j > 1 && val < a[j-1];j--) a[j] = a[j-1];
		a[j] = val;
	}
	for(int i = 1;i <= n;i++) cout<<a[i]<<' ';
	return 0;
} 

<4>快速排序

快速排序是一种基于分治法的排序方法,基本思想是,先选定pivot中心轴,再将大于pivot的数字放在pivot的右边,小于pivot的数字放在pivot的左边,然后分别对左右子序列重复前三步操作,得到一个升序的序列。快速排序拥有更好的时间复杂度O(nlogn),且不需要额外空间。

#include<bits/stdc++.h>
using namespace std;

const int N = 1e3+9;
int a[N];

int partitions(int a[],int low,int high){
	int pivot = a[low];
	while(low < high){
		while(low < high && a[high] >= pivot) high--;
		a[low] = a[high];
		while(low < high && a[low] <= pivot) low++;
		a[high] = a[low];
	}
	a[low] = pivot;// or a[high] = pivot;
	return low;
}

void quickSort(int a[],int low,int high){
	if(low < high){
		int pivotpos = partitions(a,low,high);
		quickSort(a,low,pivotpos-1);
		quickSort(a,pivotpos+1,high);
	}
}


int main(){
	int n;cin>>n;
	int low = 1,high = n;
	for(int i = 1;i <= n;i++) cin>>a[i];
	quickSort(a,low,high);
	for(int i = 1;i <= n;i++) cout<<a[i]<<' ';
	return 0;
}

<5>归并排序

归并排序和快速排序类似,也是基于分治法的排序方法。原理是将一个数组分为两个子数组,将子数组向下递归的排序后(当数组中仅有一个元素值无需再排序了,直接返回),得到两个有序数组,然后进行O(n)的合并,最终合并成有序的原数组。归并排序拥有较好的时间复杂度O(nlogn),但需要额外的空间用于合并数组。

#include<bits/stdc++.h>
using namespace std;

const int N = 1e3+9;
int a[N],b[N];

//归并
void merge(int a[],int low,int mid,int high){
	int i,j,k;
	for(k = low;k <= high;++k){
		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++]; // 将较小值复制到a中
		else a[k] = b[j++]; 
	}
	while(i <= mid) a[k++] = b[i++];
	while(j <= high) a[k++] = b[j++]; 
} 

void mergeSort(int 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);
	}
}

int main(){
	int n;cin>>n;
	for(int i = 1;i <= n;i++) cin>>a[i];
	mergeSort(a,1,n);
	for(int i = 1;i <= n;++i) cout<<a[i]<<' ';
	return 0;
}

;