面试经典算法3之选择排序

选择排序每一趟从待排序的数据元素中选出最小(或最大)的一个元素,放在已排好序的数列的最后,直到全部待排序的数据元素排完。它是一种不稳定的排序方法。选择排序前半部分逐渐有序,每趟是从待排序的数据元素位置开始扫描。

典型的选择排序算法:

(1)  直接选择排序

(2)  堆排序

直接选择排序代码:

//简单选择排序
bool SelectSort1(int A[],int n)
{
	if (A==NULL&n<0)
	{
		printf("Parameter for function SelectSort error!\n");
		return false;
	}
	for (int i=0;i<n;i++)
	{
		for (int j=i+1;j<n;j++)
		{
			if (A[j]>A[i])
			{
				int temp = A[j];
				A[j] = A[i];
				A[i] = temp;
			}
		}
	}

	return true;
}
上述代码中,每次比较发现A[j]>A[i],就交换。可优化为如下的形式:

bool SelectSort2(int A[],int n)
{
	if (A==NULL&n<0)
	{
		printf("Parameter for function SelectSort error!\n");
		return false;
	}
	for (int i=0;i<n;i++)
	{
		int k = i;
		for (int j=i+1;j<n;j++)
		{
			if (A[j]>A[k]) //并不需要每次都交换 
			{
				k = j;
			}
		}
		if (k!=i)
		{
			int temp = A[k];
			A[k] = A[i];
			A[i] = temp;
		}
	}
	return true;
}

直接选择排序的时间复杂度为O(n^2),同样是不稳定的。

堆排序:


当然,这是小顶堆,大顶堆则相反。

如果把堆序列所对应的数组,看作一个完全二叉树的顺序存储,那么,我们可以发现这颗二叉树满足如下的性质:任意分值支节点的值小于等于它左右孩子节点的值,即每一个分支节点是以它为树根的树中的最小者。

小图为一个小顶堆和大顶堆


我们可以看到,对于一个数组,如果我们用该数组建一个小顶堆所对应的完全二叉树,则树的根节点即为最小值。然后我们删除根节点,重新建堆,又可找到次小值,依次类推,即可完成排序。

//A[k]数组元素从小标1开始,并不从0开始
//堆调整
//A[]的大小为size+1,size为实际待排序的数的个数
void HeapAdjust(int A[],int k,int size)
{
	int lchild = 2*k;
	int rchild = 2*k+1;
	int index = k;
	if(lchild<=size&&A[lchild]<A[index])
	{
		index = lchild;
	}
	if(rchild<=size&&A[rchild]<A[index])
	{
		index = rchild; 
	}
	if(index!=k) //index=lchild或者index=rchild
	{
		int A[0] = A[index];
		A[index] = A[k];
		A[k] = A[0];
		HeapAdjust(A,index,size);//调整以index为根的树使其为堆
	}
}

void CreateHeap(int A[],int size)
{
	for(int i=size/2;i>=1;i--)
	{
		HeapAdjust(A,i,size);
	}
}

bool HeapSort(int A[],int size)
{
	if(A==NULL||size<=0)
	{
		printf("Parameter for function HeapSort error!\n");
		return false;
	}
	CreateHeap(A,size); //创建完成后,A[1]为最小值了
	for(int i=size;i>1;i--)
	{
		A[0] = A[1];
		A[1] = A[i];
		A[i] = A[0];
		HeapAdjust(A,1,i-1);
	}
	return true;
}
上面代码中堆的调整使用的是递归实现的,现在使用非递归实现:

//HeapAdjust的非递归实现
void HeapAdjust(int A[],int k,int size)
{
	int j = 2*k;
	int minIndex = k; //minIndex以k为根的树的最小值的下标
	bool finish = false;
	int A[0] = A[k];
	while(j<=size&&!finish)
	{
	
		if(j<size&&A[j+1]<A[j]) //右子树比左子树小
		{
			j++;
		}
		if(A[minIndex]>A[j]) //此时j为左右子树种的较小者
		{
			//根节点比孩子节点大,需调整
			A[minIndex] = A[j];
			//调整以左右孩子节点为根的树为堆
			minIndex = j;
			j = 2*j;
		}
		else  //不需要调整
		{
			finish = true;
		}
	}
	A[minIndex] = A[k];
	
}

参考:http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值