选择类排序总结

选择类排序总结

所谓选择类排序的思想就是:从数组的中选出最大或最小的,通过多次选择最后达到排序的目的

首先是简单选择排序

思想:每趟扫描中,选出最小的数字放在最前面,然后从第二个数字开始扫描,直到只剩下最后一个数不需要扫描

void EasySelect_Sort(int a[],int n)
{
	int k;
	for(int i=1;i<n;i++)
	{
		k=i-1;
		for(int j=i;j<n;j++)
		{
			if(a[j]<a[k])
			{
				k=j;
			}
		}
		if(k!=(i-1))
		{
			int temp=a[i-1];
			a[i-1]=a[k];
			a[k]=temp;
		}
	}
}

  

经过分析可以得到,最坏时间复杂度为O(n²),最好时间复杂度为O(n²)

空间复杂度为O(1);

简单选择排序是不稳定的!,例如3,3,2

二.堆排序

上面的简单选择排序中,一趟只能选出一个最大的,一趟比较完之后第二趟重新开始比较,这样一来,第一趟比较时的结果就浪费了,我们如果能够将他们利用起来的话,可想而知,可以提高不少效率,堆排序就是在这样的情况下提出来的

堆排序通过维护堆的数据特点,来实现排序,所谓堆,分为大根堆和小根堆,大根堆就是,根节点大于左子结点且根节点大于右子结点(a[i]>=a[2i]&&a[i]>=a[2i+1])

我们以大根堆为例,分析,堆排序的过程:

堆排序分为:维护堆,建立堆,堆排序三个过程

所谓维护堆:

       也就是保持他堆的性质,假设我们现在将原大根堆的根,也就是最大的结点更换为一个比较小的数值,这样,就破坏了 大根堆的性质,维护堆就是此时发挥作用的,维护堆就是要将这样一个已经被破坏的大根堆恢复为大根堆

void Keep_Sort(int a[],int n,int m)
{
	int x=a[n];
	int k=n;
	int i=2*k;
	bool finish=false;
	while((i<=m)&&(!finish))
	{
		if(i<m&&a[i]<a[i+1])
		{
			i+=1;	
		}
		if(a[i]<x)
		{
			finish=true;
		}
		else
		{
			a[k]=a[i];
			k=i;
			i=2*k;	
		}
	}
	a[k]=x;
}

  以上代码就是维护堆的代码,注意第一个if中不要忘了第一个条件!!!防止越界,调试半天才调出错误

还有就是建立堆了,

为了建立堆,我们可以从二叉树的第一个非叶子结点开始,倒着不断地维护堆,直到维护到根节点,这样依赖,一个完美的大根堆就建立了

void Create_Heap(int a[],int n)
{
	for(int i=n/2;i>=1;i--)
	{
		Keep_Sort(a,i,n);
	}	
}

  

第三步就是堆排序了,


堆排序利用了大根堆的性质,我们不断地取出大根堆的根,然后使出维护堆的神术,直到,堆灯尽油枯,只剩下一个结点,这时候我们的堆排序也完成了,哈哈,有一种,牺牲小堆,完成大排序的错觉

在实际的排序过程中,我们首先建立一个堆,然后将根节点与最后一个元素互换,这样最后一个元素就是最大的了,然后使出维护堆的大招,不过这时候维护堆就只维护前面n-1个数,最后的一个数(也就是最大数)我们把他踢出堆外,直到堆中只剩下一个元素,那他自然是最小的了,这时候所有元素从小到大排列

void Heap_Sort(int a[],int n)
{
	Create_Heap(a,n);
	for(int i=n;i>=2;i--)
	{
		int temp=a[i];
		a[i]=a[1];
		a[1]=temp;
		Keep_Sort(a,1,i-1);
	}
}

  

注意,堆排序的最好时间复杂度和最坏时间复杂度都为O(nlog2(n))

 空间复杂度为O(1)

堆排序不稳定

可以看出,选择排序基本上都是不稳定的

亲爱的听众朋友我是你的代班DJ
原文地址:https://www.cnblogs.com/YTYMblog/p/6103203.html