堆排序 快速排序C实现

堆排序 

堆:堆是一棵完全二叉树,它具有以下的性质,每个结点的值大于等于其左右孩子结点的值,称为大顶堆;或每个结点的值小于等于其左右孩子的值,称为小顶堆。

基本原理:首先需创建一个大顶堆(升序),将堆顶与数组最后一个元素交换,此时堆不再满足堆的性质,因此我们再对剩下的n-1个元素进行调整,使其重新成为一个大顶堆。再将堆顶元素与倒数第二个元素交换,交换之后又不满足堆的性质,此时再对剩余的n-2个元素进行调整,使其重新成为一个大顶堆。依次类推......

那么如何创建大顶堆呢?我们借助一个调整函数,该函数的功能是在某个结点的左右子树均为大顶堆时,对以该结点为根的这棵树进行调整,使其成为大顶堆。在创建时,实际上就是从完全二叉树的最后一个非叶子结点开始向前调整,直到根节点调整完毕,此时大顶堆便创立起来了。

因为堆是一颗完全二叉树,因此可用一维数组来存储。

调整函数具体调整过程如下图,以0号元素(18)为例,先判断左子树是否存在,若不存在则不需要调整,若存在则找出左孩子和右孩子(若右孩子不存在,则左孩子为较大者)中的较大者,比较结点与孩子中的较大者,若结点不小于较大者,则调整结束;否则交换结点与左右孩子中的较大者,又因为交换之后可能使子树又不满足堆的性质,则需继续调整。

调整函数代码:

void HeapAdjust(int arr[], int size, int parent)
{
	int child = 2 * parent + 1;
	while (child < size)
	{
		//找左右孩子中的较大者
		if (child + 1 < size && arr[child + 1] > arr[child])
			child += 1;
		//判断是否需要交换
		if (arr[parent] < arr[child])
		{
			Swap(&arr[parent], &arr[child]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
			return;
	}
}

排序代码:


void HeapSort(int arr[], int size)
{
	//end为最后一个非叶子节点
	int end = (size - 2) / 2;
	//1创建堆
	for (; end >= 0; end--)
		HeapAdjust(arr, size, end);

	//2排序
	end = size - 1;  //end为最后一个结点
	for (; end > 0; end--)
	{
		Swap(&arr[0], &arr[end]);
		HeapAdjust(arr, end, 0);
	}
}


快速排序

基本思想:通过一次排序将待排记录分割成独立的两部分,其中一部分的记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。至于分割的方法则有多种。

方法1:

假设有序列 9, 4, 2, 6, 3, 1, 8, 7, 0, 5

我们选取最后一个元素作为基准值(5),设有begin和end两个指针分别指向第一个元素和最后一个元素,begin从左往右找第一个大于5的元素,此时begin指向9,end从右往左找第一个小于5的元素,end指向0,交换9和0此时变成

0, 4, 2, 6, 3, 1, 8, 7, 9, 5

继续查找,第二次begin指向6,end指向1,交换之后

0, 4, 2, 1, 3, 6, 8, 7, 9, 5

第三次begin向后移动指向6,此时begin==end循环断开,再将基准值与arr[begin]交换得到

0, 4, 2, 1, 3,      5,      8, 7, 9, 6

此时已将序列分成两个序列,且左序列小于右序列。此时继续对左右序列进行分割即可。

代码如下:

//int Partion(int arr[], int left, int right)
//{
//	int key = arr[right];
//	int begin = left;
//	int end = right;
//	while (begin < end)
//	{
//		//从左往右找第一个大于key的数组下标
//		while (begin < end && arr[begin] <= key)
//			begin++;
//		//从右往左找第一个小于key的数组下标
//		while (begin < end && arr[end] >= key)   
//			end--;                                    
//		if (begin != end)
//		{
//			Swap(&arr[begin], &arr[end]);
//		}
//	}
//	Swap(&arr[begin], &arr[right]);
//	return begin;
//}


方法2:挖坑法

和方法1不同的是当从begin位置往右找到第一个大于基准值的元素时,直接用当前元素覆盖end位置元素(当然需先记录基准值),然后再从end位置往左找第一个小于基准值的元素来覆盖begin位置元素。然后再从begin位置继续按上述方法执行,直到begin==end,再用基准值覆盖begin位置元素。至此,完成分割操作。

分割过程如下:

 

9, 4, 2, 6, 3, 1, 8, 7, 0, 5  

                               ←

9, 4, 2, 6, 3, 1, 8, 7, 0,

 

0, 4, 2, 6, 3, 1, 8, 7, 0, 9

                            ←

0, 4, 2, 6, 3, 1, 8, 7, 6, 9

 

0, 4, 2, 1, 3, 1, 8, 7, 6, 9


0, 4, 2, 1, 3, 5, 8, 7, 6, 9

代码如下:

//int Partion(int arr[], int left, int right)
//{
//	int key = arr[right];//用最后一个元素做基准值
//	int begin = left;
//	int end = right;
//	while (begin < end)
//	{
//		//找第一个比基准值大的元素
//		while (begin < end && arr[begin] <= key)
//			begin++;
//		//将比基准值大的移到高端
//		arr[end] = arr[begin];
//		//找第一个比基准值小的的元素
//		while (begin < end && arr[end] >= key)
//			end--;
//		//将比基准值小的移到低端
//		arr[begin] = arr[end];  
//	}
//	arr[begin] = key;
//	return begin;
//}

整体代码:

void QuickSort(int arr[], int left, int right)
{
	if (left < right)
	{
		int div = Partion(arr, left, right);
		QuickSort(arr, left, div - 1);
		QuickSort(arr, div + 1, right);
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值