堆排序

堆排序的时间复杂度是O(nlgn),堆排序具有空间原址性:任何时候都只需要常数个额外的元素空间存储临时数据。

1.堆

二叉堆是一个数组,可视为一个近似的完全二叉树,除最底层外,该树是完全充满的,而且是从左到右填充。堆的数组A包括两个属性,A.length给出数组元素的个数,A.heap-size表示有多少个堆元素存储在数组中。虽然A[1...A.length]可能都存储数据,但只有A[1...A.heap-size]中存放的是堆的有效元素。给定节点的下标i(从0开始编号),

父节点PARENT(i)=(i-1)/2

左节点LEFT(i)=2i+1

右节点RIGHT(i)=2i+2

最大堆:除根节点外所有节点i满足 A[PARENT(i)]>=A[i]。最小堆:除根节点外所有节点i满足 A[PARENT(i)]<=A[i]。堆排序算法中使用的是最大堆,最小堆通常用于构造有限队列。

2.函数及运行效率说明

2.1 fMaxheapify(int i);//建立i为根节点的最大堆,时间复杂度O(lgn),维护堆的性质。在调用fMaxheapify()时假定左右子树都是最大堆,是下标为i的根节点的子树重新遵循最大堆的性质。

  2.2 fBuildheap(int n);//建立数组长度为n的最大堆,时间复杂度O(n)

fBuildheap(A)

A.heap-size = A.lengh

for i = (A.heap-size-1)/2 downto 0 

fMaxheapify(i)

2.2 fHeapsort();//堆排序O(nlgn)

将数组构建成最大堆后,最大元素总是在根节点A[0],通过把A[0]与A[A.length]交换,从堆中去掉节点n(A.heap-size--),调用fMaxheapify(0),可以在A[0, A.length-1]上构建一个新的最大堆,重复这一过程。

HEAPSORT(A)

  fBuildheap(A)

  for i = A.length downto 1 

exchange A[0] with A[i]

A.heap-size--

fMaxheapify(0)

3.源代码

#include <iostream>
using namespace std;

template <class T>
void fExchange(T &a, T &b)
{ 
	T temp = b; 
	b = a; 
	a = temp; 
}

template<class T>
class heapify
{
private:
	T* heap;
	int nHeapSize;//heap数组实际大小,下标从0计
	int nMaxSize;//heap最大包含元素的个数,下标从1计
public:
	heapify(T* h, int HS, int MS)
	{ 
		nHeapSize = HS-1;
		nMaxSize = MS;
		heap = h;
	}
	void fBuildheap(int n);//数组长度为n的最大堆
	void fMaxheapify(int i);//建立i为根节点的最大堆
	void fHeapsort();//堆排序O(nlgn)
	void fInsert(T p);//插入新结点,结点值为p
	T fExtractMAX();//删除根节点
	void fIncreaseKey(int pos, T value);//将heap[i]的结点值增加为value
	
};


template<class T>
void heapify<T>::fMaxheapify(int i)
{
	while (i < (nHeapSize+1)/2)//以循环结构代替递归,到叶子节点结束
	{
		int left = 2 * i + 1;//从0开始,所以左节点2i+1
		int right = 2 * i + 2;
		int max;
		if (left <= nHeapSize && heap[left] > heap[i])
			max = left;
		else
			max = i;
		if (right <= nHeapSize && heap[right] > heap[max])
			max = right;
		if (max != i)
		{
			fExchange(heap[i], heap[max]);
			i = max;
		}
		else//不交换,结束循环
			break;
	}

}

template<class T>
void heapify<T>::fBuildheap(int n)
{
	for (int i = n / 2 - 1; i >= 0; i--)
	{
		fMaxheapify(i);
	}
}

template<class T>
void heapify<T>::fInsert(T p)
{
	nHeapSize++;
	heap[nHeapSize] = p;
	fIncreaseKey(nHeapSize, p);

}

template<class T>
void heapify<T>::fIncreaseKey(int pos, T value)
{
	if (heap[pos] < value)
		cout << "new key is no larger than current key\n";
	else
	{
		heap[pos] = value;
		while (pos >= 0 && heap[(pos - 1) / 2] < heap[pos])
		{
			fExchange(heap[(pos - 1) / 2], heap[(pos)]);
			pos = (pos - 1) / 2;
		}
	}
	
}


template<class T>
T heapify<T>::fExtractMAX()
{
	if (nHeapSize < 0)
		cerr << "heap underflow\n";
	else
	{
		T max = heap[0];
		heap[0] = heap[nHeapSize];
		nHeapSize--;
		fMaxheapify(0);
		return max;
	}
}

template<class T>
void heapify<T>::fHeapsort()
{
	int nNum = nHeapSize;
	for (int i = nHeapSize; i >= 1; i--)//当nHeapSize=0时,堆“underflow”
	{
		fExchange(heap[nHeapSize], heap[0]);
		nHeapSize--;
		fMaxheapify(0);
	}
	for (int i = 0; i <=nNum; i++)
		cout << heap[i] << " ";
	cout << endl;
}

void main()
{
	int A[15] = { 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 };
	heapify<int> Myheap(A, 10, 15);//构造函数,第一个变量指向数组指针,第二个变量表示设定heap实际包含的个数,第三个变量表示数组最大包含个数,两个变量的下标均从1计
	Myheap.fBuildheap(10);
	Myheap.fInsert(24);//插入新的元素后,因为Myheap的指针指向数组A,A的大小设定为10,所以插入后会导致数组越界。
	int max = Myheap.fExtractMAX();//Run-Time Check Failure #2 - Stack around the variable 'A' was corrupted.所以A的大小可以申请大一些
	Myheap.fHeapsort();
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值