八种常用排序算法参考

写在前面:

因为网络上有很多篇讲排序算法的,所以这里就不详细讲了,只作为参考和自己查阅

当然了,虽然篇幅也会短很多,但部分重点和要点还在


八种排序算法分别是:

选择排序; ②冒泡排序; ③插入排序; ④快速排序

⑤归并排序; ⑥计数排序; ⑦希尔排序; ⑧堆排序;(蓝色为不稳定排序)


一,选择排序:

特点:应该是90%的人学C语言,所会的第一个排序

步骤:每次选择后n-i个数字中最小的和当前第i位交换

复杂度Θ(n²),O(n²)


void Select_sort(int *a, int n)
{
	int i, j, now, id;
	for(i=1;i<=n;i++)
	{
		id = i;
		now = a[i];
		for(j=i+1;j<=n;j++)
		{
			if(a[j]<now)
				now = a[j], id = j;
		}
		swap(a[i], a[id]);
	}
}


二,冒泡排序:

特点应该是剩下10%的人学C语言,所会的第一个排序

步骤①暴力枚举相邻的两个数,如果逆序就把它们交换

②一趟下来最大的数肯定在第n位,那么对前n-1位再来一趟……以此类推直到有序

复杂度Θ(n²),O(n²)


void Bubble_sort(int *a, int n)
{
	int i, j;
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n-i;j++)
		{
			if(a[j+1]<a[j])
				swap(a[j], a[j+1]);
		}
	}
}



三,插入排序:

特点很像玩扑克牌时,每摸一张牌,就把这张牌插入一个合适的位置,使得手牌保持有序

步骤就是模拟上述过程

复杂度Θ(n²),O(n²)


void Insert_sort(int *a, int n)
{
	int i, j, temp;
	for(i=2;i<=n;i++)
	{
		if(a[i]>=a[i-1])
			continue;
		temp = a[i];
		for(j=i-1;a[j]>temp&&j>=1;j--)
			a[j+1] = a[j];
		a[j+1] = temp;
	}
}


四,快速排序

特点非常著名的排序算法,在所有交换类排序中,它是最快的!

步骤①在无序的数组中选择一个数x作为基数

②把比x小的数扔到x左边,比x大的数字扔到x右边(这个步骤当然是线性的,处理方法略)

③这样x会把整个数组分成两个部分,对于两个部分重复操作直到有序

注意:一般来讲都是选择当前第一个数作为基数,如果每次选的基数都恰好是当前最大/最小的,那么复杂度会达到n²,为了防止上述过程发生,可以有很多优化方法,例如随机选择三个数,将其中第二大的数作为基数

复杂度Θ(nlogn),O(n²)


void Quick_sort(int *a, int L, int R)
{
	int i, j, x;
	if(L>=R)
		return;
	i = L, j = R;
	x = a[i];
	while(i<j)
	{
		while(i<j && a[j]>=x)	/*两个while循环不能交换*/
			j--;
		while(i<j && a[i]<=x)
			i++;
		swap(a[i], a[j]);
	}
	a[L] = a[i];
	a[i] = x;
	Quick_sort(a, L, i-1);
	Quick_sort(a, i+1, R);
}



五,归并排序:

特点分治,核心是将两个有序的数组合并只需要线性的复杂度

步骤对于样例 1 5 2 8 9 5 4 6;① 1 5 | 2 8 | 5 9 | 4 6

② 1 2 5 8 | 4 5 6 9;③ 1 2 4 5 5 6 8 9 完成排序

复杂度Θ(nlogn),O(nlogn)

缺点:需要多开一倍空间(一个数组搞不定)


void Merge_sort(int *a, int *b, int L, int R)
{
	int i, j, m, p;
	if(L==R)
		return;
	m = (L+R)/2;
	Merge_sort(a, b, L, m);
	Merge_sort(a, b, m+1, R);
	i = L, j = m+1, p = L-1;
	while(i<=m || j<=R)
	{
		if(j>R || a[i]<a[j])
			b[++p] = a[i++];
		else
			b[++p] = a[j++];
	}
	for(i=L;i<=R;i++)
		a[i] = b[i];
}


六,计数排序(桶排序):

特点非常简单的排序,对于数据相对集中的数列才能使用这种方法

步骤①计算数列的最大值Max和最小值Min

②申请一个大小为Max-Min的数组,遍历一遍统计b[x-Min]表示数字x出现次数

②再遍历一遍b[]把所有数字列出来(有序还原)

复杂度Θ(n),O(n)


void Count_sort(int *a, int n)
{
	int *b, i, p, Min, Max;
	Min = Max = a[1];
	for(i=2;i<=n;i++)
	{
		Min = min(Min, a[i]);
		Max = max(Max, a[i]);
	}
	b = new int[Max-Min+1];
	memset(b, 0, (Max-Min+1)*sizeof(int));
	for(i=1;i<=n;i++)
		b[a[i]-Min]++;
	p = 0;
	for(i=0;i<=Max-Min;i++)
	{
		while(b[i]--)
			a[++p] = Min+i;
	}
	delete []b;
	b = NULL;
}


七,希尔排序(缩小增量排序、Shell排序):

特点对于元素基本有序的序列,效率极高

步骤①设数列有14个元素,设k = 14/2 = 7,对a[1], a[8]进行插入排序,a[2], a[9]进行插入排序,a[3], a[10]进行插入排序……

②再次设k = 7/2 = 3,对a[1], a[4], a[7], a[10], a[13]进行插入排序,a[2], a[5], a[8], a[11], a[14]进行插入排序……

②再次设k = 3/2 = 1,对a[1], a[2], …, a[14]进行插入排序

复杂度Θ(n^1.3),O(n²)


void Shell_sort(int *a, int n)
{
	int i, j, z, temp;
	for(z=n/2;z>=1;z/=2)	//z为增量,这里可以用其它的增量数组代替
	{
		for(i=z+1;i<=n;i++)
		{
			if(a[i]>=a[i-z])
				continue;
			temp = a[i];
			for(j=i-z;a[j]>temp&&j>=1;j-=z)
				a[j+z] = a[j];
			a[j+z] = temp;
		}
	}
}


八,堆排序(二叉排序):

特点最复杂的一个排序,详细讲解请戳这里

步骤①构造初始堆,将给定无序序列构造成一个大顶堆(升序采用大顶堆,降序采用小顶堆)

②将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端

③重新调整堆结构,继续执行步骤②直到有序

复杂度Θ(nlogn),O(nlogn)


void Adjust(int *a, int p, int n)	//调整节点p
{
	int x, i;
	x = a[p];
	for(i=2*p;i<=n;i=i*2)	//从p点的两个孩子开始
	{
		if(i+1<=n && a[i+1]>a[i])	//寻找两个孩子中更大的那个
			i++;
		if(a[i]>x)		//如果当前节点比父亲大(不满足大顶堆性质)
		{
			a[p] = a[i];	//交换这个节点与父亲的值
			p = i;
		}
		else
			break;
	}
	a[p] = x;	
}
void Heap_sort(int *a, int n)		//注意我的数组下标是从1开始的!
{
	int i;
	for(i=n/2;i>=1;i--)
		Adjust(a, i, n);
	for(i=n;i>=2;i--)
	{
		swap(a[1], a[i]);	//堆顶和末尾交换
		Adjust(a, 1, i-1);
	}
}


End


  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值