C++ 堆排序算法 分治法(递归)

本文介绍了C++实现堆排序算法的过程,包括最大堆的性质、如何维护堆的性质、建堆步骤以及堆排序算法的完整代码示例,重点阐述了分治法和递归在算法中的应用。

(二插)是一个数组,可以被看成一个近似的完全二叉树。

树的根节点是A[1]

第一步:

给定一个节点的下标i,我们可以计算得到它的 父结点和左右孩子的下标:

int Parent(int i)
{
	return floor(i / 2.0);
}

int Left(int i)
{
	return 2 * i;
}

int Right(int i)
{
	return 2 * i + 1;
}

最大堆性质:除了根以外的所有节点i都满足:

A[Parent(i)] >= A[i]

最小堆性质:除了根以外的所有节点i都满足:

A[Parent(i)] <= A[i]

以下我们讨论最大堆

第二步:

我们需要一个过程来维护堆的性质:

//使二叉树满足最大堆性质
void Max_Heapify(int* A, int i)
{
	int l = Left(i);
	int r = Right(i);
	int largest = 0;

	if(l <= heap_size && A[l] > A[i])
		largest = l;
	else
		largest = i;
	if(r <= heap_size && A[r] > A[largest])
		largest = r;
	if(largest != i)
	{
		int temp = A[i];
		A[i] = A[largest];
		A[largest] = temp;
		Max_Heapify(A,largest);
	}
}

我们从A[i]、A[Left(i)]、A[Right(i)]中选出最大的,并将其下标存在largest中。

如果非叶子结点A[i]是最大的,那么以i为根结点的子树已是最大堆,过程结束。

否则,最大的是i的某个孩子,那么,交换A[i]A[largest]的值。从而i其孩子都满足最大堆的性质(也就是递归,因为在交换后,下标为largest的结点的值为原来的A[i],这样可能导致以该结点的子树违反最大堆的性质。因此,需要递归调用Max_Heapify)。


第三步:

建堆:

我们先利用Max_Heapify过程把数组转换为最大堆。

//建堆
void Build_Max_Heap(int* A)
{
	heap_size = length;
	for(int i = floor(length / 2.0); i >=1; i--)
	{
		Max_Heapify(A, i);
	}
}


第四步:

堆排序算法:

void Heap_Sort(int* A)
{
	Build_Max_Heap(A);
	printf("建立最大堆:");
	for(int i=1;i<=length;i++)
		printf("%d ", A[i]);
	printf("\n");
	for(int i = length;i >= 2; i--)
	{
		int temp = A[1];
		A[1] = A[i];
		A[i] = temp;
		heap_size = heap_size - 1;
		Max_Heapify(A, 1);
		printf("第%d次排序:", ++iter);
		for(int i=1;i<=length;i++)
			printf("%d ", A[i]);
		printf("\n");
	}
}


完整程序示例代码:

#include "stdafx.h"
#include <math.h>

int length = 10;
int heap_size;
int A[11] = {0,16,14,10,8,7,9,3,2,4,1};
int iter = 0;
int Parent(int i)
{
	return floor(i / 2.0);
}

int Left(int i)
{
	return 2 * i;
}

int Right(int i)
{
	return 2 * i + 1;
}

//使二叉树满足最大堆性质
void Max_Heapify(int* A, int i)
{
	int l = Left(i);
	int r = Right(i);
	int largest = 0;

	if(l <= heap_size && A[l] > A[i])
		largest = l;
	else
		largest = i;
	if(r <= heap_size && A[r] > A[largest])
		largest = r;
	if(largest != i)
	{
		int temp = A[i];
		A[i] = A[largest];
		A[largest] = temp;
		Max_Heapify(A,largest);
	}
}

//建堆
void Build_Max_Heap(int* A)
{
	heap_size = length;
	for(int i = floor(length / 2.0); i >=1; i--)
	{
		Max_Heapify(A, i);
	}
}

void Heap_Sort(int* A)
{
	Build_Max_Heap(A);
	printf("建立最大堆:");
	for(int i=1;i<=length;i++)
		printf("%d ", A[i]);
	printf("\n");
	for(int i = length;i >= 2; i--)
	{
		int temp = A[1];
		A[1] = A[i];
		A[i] = temp;
		heap_size = heap_size - 1;
		Max_Heapify(A, 1);
		printf("第%d次排序:", ++iter);
		for(int i=1;i<=length;i++)
			printf("%d ", A[i]);
		printf("\n");
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	Heap_Sort(A);
	printf("最后排序结果:");
	for(int i=1;i<=length;i++)
		printf("%d ", A[i]);
	getchar();
	return 0;
}

结果展示:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值