十种排序算法总结——直接插入排序+折半插入排序+希尔排序+冒泡排序+快速排序+简单选择排序+堆排序(大根堆+小根堆)+归并排序+基数排序+桶排序+数组散列、集合模拟桶排序

十种常用排序算法总结

直接插入排序+折半插入排序+希尔排序+冒泡排序+快速排序+简单选择排序+堆排序(大根堆+小根堆)+归并排序+基数排序+桶排序+数组散列、集合模拟桶排序

  • 算法稳定性:即两关键字相同元素在排序过程中位置在前者是否能始终保持位置在前。稳定性不能决定算法好坏,只是一种性质。常用于求逆序对的题目。

稳定的有:直接插入、冒泡、归并、基数排序;
不稳定的:简单选择、希尔、快速、堆排序。

  1. 直接插入排序(时间复杂度:最好情况O(n) 、平均O(n^2) 、最坏O(n^2); 空间复杂度:O(1) )
#include
#include
#include
#include 
#include
#include
#include 
#include
#include 
#include 
#include
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a)))
#define w while
#define vr vector
#define gr greater
typedef long long ll;
//next_permutation(arr, arr+size);全排列
//prev_permutation(arr, arr+size);

int n, a[100005];

void Insertsort()
{
	int j;
	req(i, 2, n)
	{
		if(a[i] < a[i-1])
		{
			a[0] = a[i];
			for(j=i-1; a[0]<a[j]; j--)
			a[j+1] = a[j];
			a[j+1] = a[0];
		}
	}
}

void display()
{
	req(i, 1, n)
	printf("%d ",a[i]);
	prk;
}

int main()
{
	sc(n);
	req(i, 1, n)
	sc(a[i]);
	Insertsort();
	display();
	return 0;
}

/*
input:
11
2 1 5 4 3 3 6 1 3 2 3
output:
1 1 2 2 3 3 3 3 4 5 6
*/

  1. 折半插入排序(时间复杂度:最好情况O(n) 、平均O(n^2) 、最坏O(n^2); 空间复杂度:O(1) )
#include
#include
#include
#include 
#include
#include
#include 
#include
#include 
#include 
#include
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a)))
#define w while
#define vr vector
#define gr greater
typedef long long ll;
//next_permutation(arr, arr+size);全排列
//prev_permutation(arr, arr+size);

int n, a[100005];

void Half_Insertsort()
{
	int j, low, high, mid;
	req(i, 2, n)
	{
		a[0] = a[i];
		low = 1, high = i-1;
		while(low <= high)
		{
			mid = (low+high) >> 1;
			if(a[mid] > a[0])
			high = mid-1;
			else low = mid+1;
		}
		for(j=i-1; j>=high+1; j--)
		a[j+1] = a[j];
		a[j+1] = a[0];
	}
}

void display()
{
	req(i, 1, n)
	printf("%d ",a[i]);
	prk;
}

int main()
{
	sc(n);
	req(i, 1, n)
	sc(a[i]);
	Half_Insertsort();
	display();
	return 0;
}

/*
input:
11
2 1 5 4 3 3 6 1 3 2 3
output:
1 1 2 2 3 3 3 3 4 5 6
*/

  1. 希尔排序(时间复杂度:平均O(n^1.3) 其实无法计算shell排序的时间复杂度; 空间复杂度:O(1) )
#include
#include
#include
#include 
#include
#include
#include 
#include
#include 
#include 
#include
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a)))
#define w while
#define vr vector
#define gr greater
typedef long long ll;
//next_permutation(arr, arr+size);全排列
//prev_permutation(arr, arr+size);

int n, a[100005];

void Shell_Insertsort() //是直接插入排序的改进
{
	int j; 
	for(int d=n>>1; d>=1; d>>=1) //直接插入排序步长是1 ,这里改成逐步缩短为1的d 
	{
		req(i, d+1, n)
		{
			if(a[i] < a[i-d]) //其余部分同直接插入一样,只是把步长为1的代码改成d 
			{				  //相当于让没d个单位的数据组成新数组 
				a[0] = a[i];
				for(j=i-d; a[j]>a[0]&&j>0; j-=d)
				a[j+d] = a[j];
				a[j+d] = a[0];
			}
		}
	}
}

void display()
{
	req(i, 1, n)
	printf("%d ",a[i]);
	prk;
}

int main()
{
	sc(n);
	req(i, 1, n)
	sc(a[i]);
	Shell_Insertsort();
	display();
	return 0;
}

/*
input:
11
2 1 5 4 3 3 6 1 3 2 3
output:
1 1 2 2 3 3 3 3 4 5 6
*/


  1. 冒泡排序(时间复杂度:最好情况O(n) 、平均O(n^2) 、最坏O(n^2); 空间复杂度:O(1) )
#include
#include
#include
#include 
#include
#include
#include 
#include
#include 
#include 
#include
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a)))
#define w while
#define vr vector
#define gr greater
typedef long long ll;
//next_permutation(arr, arr+size);全排列
//prev_permutation(arr, arr+size);

int n, a[100005];

void Buddlesort()
{
	rep(i, 1, n)
	{
		bool flag = false;
		for(int j=n; j>i; j--)
		{
			
			if(a[j] < a[j-1])
			{
				swap(a[j-1],a[j]);
				flag = true;
			}
		} 	
		if(!flag) //某一遍没有发生交换时,则停止,减少时间浪费 
		break;    //因此可以发现,数列有序后,冒泡排序仍需再一次遍历判断是否有序才可停止 
	}
	
}

void display()
{
	req(i, 1, n)
	printf("%d ",a[i]);
	prk;
}

int main()
{
	sc(n);
	req(i, 1, n)
	sc(a[i]);
	Buddlesort();
	display();
	return 0;
}

/*
input:
11
2 1 5 4 3 3 6 1 3 2 3
output:
1 1 2 2 3 3 3 3 4 5 6
*/

  1. 快速排序(时间复杂度:最好情况O(nlog2(n)) 、平均O(nlog2(n)) 、最坏O(n^2); 空间复杂度:O(log2(n)) )
#include
#include
#include
#include 
#include
#include
#include 
#include
#include 
#include 
#include
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a)))
#define w while
#define vr vector
#define gr greater
typedef long long ll;
//next_permutation(arr, arr+size);全排列
//prev_permutation(arr, arr+size);

int n, a[100005];

int partition(int low,int high)
{
	int tem = a[low];
	while(low < high)
	{
		while(a[high] > tem && high > low) high--; 
		a[low] = a[high]; //找到第一个比tem小的,放入low位置上
		while(a[low] <= tem && low < high) low++;
		a[high] = a[low]; //找到第一个比tem大的放入刚才空出来的high位置上	
	} //重复进行,low==high时停止循环,此时,比tem大的都去了tem右边,小的都在tem左边,则tem到达指定位置low==high
	a[low] = tem; 
	return low; 
} 

void Quicksort(int low,int high)
{
	int pos = partition(low, high); //快排一趟至少有一个元素到达指定位置,以此为分界线,分割成两部分,再排 
	if(pos-1 > low)
	Quicksort(low, pos-1);
	if(pos+1 < high)
	Quicksort(pos+1, high);
}

void display()
{
	req(i, 1, n)
	printf("%d ",a[i]);
	prk;
}

int main()
{
	sc(n);
	req(i, 1, n)
	sc(a[i]);
	Quicksort(1,n);
	display();
	return 0;
}

/*
input:
11
2 1 5 4 3 3 6 1 3 2 3
output:
1 1 2 2 3 3 3 3 4 5 6
*/

  1. 简单选择排序(时间复杂度:最好情况O(n^2) 、平均O(n^2) 、最坏O(n^2); 空间复杂度:O(1) )
#include
#include
#include
#include 
#include
#include
#include 
#include
#include 
#include 
#include
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a)))
#define w while
#define vr vector
#define gr greater
typedef long long ll;
//next_permutation(arr, arr+size);全排列
//prev_permutation(arr, arr+size);

int n, a[100005];

void Selectsort()
{
	req(i, 1, n-1)
	{
		int min = i;
		req(j, i+1, n)
		{
			if(a[j] < a[min])
			min = j;
		}
		if(min != i)
		swap(a[i], a[min]);
	} 
}

void display()
{
	req(i, 1, n)
	printf("%d ",a[i]);
	prk;
}

int main()
{
	sc(n);
	req(i, 1, n)
	sc(a[i]);
	Selectsort();
	display();
	return 0;
}

/*
input:
11
2 1 5 4 3 3 6 1 3 2 3
output:
1 1 2 2 3 3 3 3 4 5 6
*/

  1. 堆排序(时间复杂度:最好情况O(nlog2(n)) 、平均O(nlog2(n)) 、最坏O(nlog2(n)); 空间复杂度:O(1) )
  • 大根堆代码(升序排列)
#include
#include
#include
#include 
#include
#include
#include 
#include
#include 
#include 
#include
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a)))
#define w while
#define vr vector
#define gr greater
typedef long long ll;
//next_permutation(arr, arr+size);全排列
//prev_permutation(arr, arr+size);

int n, a[100005];

void AdjustDown(int x, int m)
{
	a[0] = a[x];
	for(int i=x*2; i<=m; i*=2)
	{
		if(i<m && a[i]<a[i+1]) //取左右子节点中的较大者 
		i++;
		if(a[0] >= a[i]) //即无需调整 
		break; 
		else
		{
			a[x] = a[i]; //如果子结点较大,将父子结点交换,继续往下调整 
			x = i;
		} 
	}
	a[x] = a[0]; 
}

void BuildMaxHeap()
{
	for(int i=n/2; i>=1; i--) //从最小父节点往上调整 
	AdjustDown(i, n);
}

void Heapsort()
{
	BuildMaxHeap();
	for(int i=n; i>1; i--)
	{
		swap(a[i],a[1]); //每次输出一个a[1],即当时最大根,输出后与a[i]
		AdjustDown(1,i-1); //即最后一个叶节点互换位置,重新调整1~i-1的剩余二叉树 
	}
	//这样建的大根堆每次把最大值调整到最后,类似尾插,结束后的数组就是从小到大的有序序列 
}

void display()
{
	req(i, 1, n)
	printf("%d ",a[i]);
	prk;
}

int main()
{
	sc(n);
	req(i, 1, n)
	sc(a[i]);
	Heapsort();
	display();
	return 0;
}

/*
input:
11
2 1 5 4 3 3 6 1 3 2 3
output:
1 1 2 2 3 3 3 3 4 5 6
*/

  • 小根堆代码(逆序排列)
#include
#include
#include
#include 
#include
#include
#include 
#include
#include 
#include 
#include
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a)))
#define w while
#define vr vector
#define gr greater
typedef long long ll;
//next_permutation(arr, arr+size);全排列
//prev_permutation(arr, arr+size);

 //只有两个地方跟建大根堆不一样 
int n, a[100005];

void AdjustDown(int x, int m)
{
	a[0] = a[x];
	for(int i=x*2; i<=m; i*=2)
	{
		if(i<m && a[i]>a[i+1]) //第一个,找左右子节点较小者 
		i++;
		if(a[0] <= a[i]) //第二个,较小的作为父节点 
		break; 
		else
		{
			a[x] = a[i];
			x = i;
		} 
	}
	a[x] = a[0]; 
}

void BuildMaxHeap()
{
	for(int i=n/2; i>=1; i--) 
	AdjustDown(i, n);
}

void Heapsort()
{
	BuildMaxHeap();
	for(int i=n; i>1; i--)
	{
		swap(a[i],a[1]); 
		AdjustDown(1,i-1);
	}
}

void display()
{
	req(i, 1, n)
	printf("%d ",a[i]);
	prk;
}

int main()
{
	sc(n);
	req(i, 1, n)
	sc(a[i]);
	Heapsort();
	display();
	return 0;
}

/*
input:
11
2 1 5 4 3 3 6 1 3 2 3
output:
1 1 2 2 3 3 3 3 4 5 6
*/

  1. 归并排序(时间复杂度:最好情况O(nlog2(n)) 、平均O(nlog2(n)) 、最坏O(nlog2(n)); 空间复杂度:O(n) )
#include
#include
#include
#include 
#include
#include
#include 
#include
#include 
#include 
#include
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a)))
#define w while
#define vr vector
#define gr greater
typedef long long ll;
//next_permutation(arr, arr+size);全排列
//prev_permutation(arr, arr+size);

int n, a[100005];

void Merge(int low,int mid,int high)
{
	int b[high+5];
	req(i, low, high)
	b[i] = a[i];
	int i, j, k;
	for(i=low,j=mid+1,k=low;i<=mid&&j<=high;k++)
	{
		if(b[i] < b[j]) a[k] = b[i++]; //按序合并 
		else a[k] = b[j++];
	}
	while(i<=mid)  a[k++] = b[i++]; //合并剩余部分 
	while(j<=high) a[k++] = b[j++]; 
}

void Mergesort(int low,int high)
{
	if(low < high) //不断割裂成两部分,排序后合并 
	{
		int mid = (low+high) >> 1;
		Mergesort(low,mid);
		Mergesort(mid+1,high);
		Merge(low,mid,high);
	}
}

void display()
{
	req(i, 1, n)
	printf("%d ",a[i]);
	prk;
}

int main()
{
	sc(n);
	req(i, 1, n)
	sc(a[i]);
	Mergesort(1,n);
	display();
	return 0;
}

/*
input:
11
2 1 5 4 3 3 6 1 3 2 3
output:
1 1 2 2 3 3 3 3 4 5 6
*/

  1. 基数排序(时间复杂度:最好情况O(d*(n+r)) 、平均O(d*(n+r)) 、最坏O(d*(n+r)); 空间复杂度:O(r ) )

r是关键字种类,d是分组,n是元素个数,如一组数据15、233、168,r=6,因为出现了1、2、3、5、6、8,这六个关键字,d=3,因为最高位是百位,需要将关键字拆分为3组,第一组{5、3、8},第二组{1、3、6},第三组{0,2,1},n=3,因为有15、233、168三个数据,辅助空间是O®是因为基数排序按关键字种类存在对应队列中

  • 这里以LSD最低位优先为例
#include
#include
#include
#include 
#include
#include
#include 
#include
#include 
#include 
#include
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a)))
#define w while
#define vr vector
#define gr greater
typedef long long ll;
//next_permutation(arr, arr+size);全排列
//prev_permutation(arr, arr+size);

//基数排序有MSD:最高位优先 和 LSD:最低位优先两种
//取决于基数如只出现1 2 3 4 5,则只需要五个队列
//显然现实排序没这么简单,所以用0~9十个队列


int n, a[100005];
vector<int> q[10];

void display();

void Base() //将每个队列按基数排序的加入原数组,原数组顺序得以改变 
{			//出于基数排序具有稳定性,下一轮相同数字的前后顺序就不会再调整了 
	int k = 1;
	req(i, 0, 9)
	{
		rep(j, 0, q[i].size())
		a[k++] = q[i][j];
	}
}

void Basesort(int d)
{
	req(i, 0, 9) //每轮将上轮数据清空 
	q[i].clear();
	int res = 0; 
	req(i, 1, n) //d=1象征个位,d=10,象征十位,依次取位置 
	{
		int x = a[i];
		x /= d; //如2723/100=27;27%10=7,就取到了百位上的数字 
		if(x == 0) //判断该数是不是已经不够取了,中间有0和不够取是不一样的,要分清 
		res++;
		x %= 10;
		q[x].push_back(a[i]); //将a[i]这个数加入到对应队列中 
	}
	Base();
	if(res != n) //即如果不是所有数都取不到了,就意味着还有数有位数,需要继续排序 
	Basesort(d*10); 
}



void display()
{
	req(i, 1, n)
	printf("%d ",a[i]);
	prk;
}

int main()
{
	sc(n);
	req(i, 1, n)
	sc(a[i]);
	Basesort(1);
	display();
	return 0;
}

/*
input:
11
2 1 5 4 3 3 6 1 3 2 3
output:
1 1 2 2 3 3 3 3 4 5 6

intput:
7
329 457 657 839 436 720 355 
output:
329 355 436 457 657 720 839

intput:
16
88 883 882 885 8 882 88881 2 19 235 15 883 100000000 100000001 23 89
output:
2 8 15 19 23 88 89 235 882 882 883 883 885 88881 100000000 100000001
*/

  1. 桶排序和利用散列、集合数组模拟桶排序(平均O(n) ; 空间复杂度:桶排序与元素种类有关,数组O(1) ,并不是说桶排序耗空间更多,而是数组可以定义一个N大小的数组,N是常数,常数即O(1),而map与元素种类有关)
#include
#include
#include
#include 
#include
#include
#include 
#include
#include 
#include 
#include
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a)))
#define w while
#define vr vector
#define gr greater
typedef long long ll;
//next_permutation(arr, arr+size);全排列
//prev_permutation(arr, arr+size);

//这两个太简单,放在一起写了 
//不过要注意,数组排序是集合、散列的运用,输入数据x不能大于数组边界n 

int n, a[100005];

void Mapsort()
{
	map<int,int> m;
	int x;
	sc(n);
	req(i, 1, n) //可以直接输入到桶里,我这里为了方便和格式一致,保持前面的输入
	{
		sc(x);
		m[x]++; //数据出现一次加一次 
	}
	puts("\nresult for Map:"); 
	//类似于for(int i=1; i
	for(map<int,int>::iterator it=m.begin(); it!=m.end(); it++)
	{
		while(it->second) //first指向元素,second指向个数 
		{
			printf("%d ",it->first);
			it->second--; 
		}
	}
	prk;prk;
}

void Numsort()
{
	int x;
	sc(n);
	req(i, 1, n) //这里把元素视作下标,所以x<=n 
	{
		sc(x);
		a[x]++;
	}
	puts("\nresult for Num:"); 
	req(i, 1, n) //map中没出现过的数据不会在遍历过程中遇到,数组的话只能从头判断 
	{
		while(a[i])
		{
			printf("%d ",i);
			a[i]--;
		}
	}
	prk;
}

int main()
{
	Mapsort(); //桶排序 
	Numsort(); //数组排序 
	return 0;
}

/*
input:
11
2 1 5 4 3 3 6 1 3 2 3
11
2 1 5 4 3 3 6 1 3 2 3
output:

result for Map:
1 1 2 2 3 3 3 3 4 5 6

result for Num:
1 1 2 2 3 3 3 3 4 5 6
*/

你可能感兴趣的:(C++)