树 - 堆排序(C++)

前言:

      理论(文字)知识很枯燥,但是如果读者真正想把一个问题搞明白,搞清楚,光靠成天撸代码是不行的,而需要理解其中的思想本质,否则只能是知其然而不知其所以然,我之前常说:“话不多说,直接上代码”希望不要误导读者。SO,请耐心的看下去,平常心,借用金庸老先生的一句话:“他强由他强,清风拂山岗;他横由他横,明月照大江.他自狠来他自恶,我自一口真气足。”
最后,希望各位同行者可以提出问题,我们共同进步。
博客地址;https://blog.csdn.net/y_16041527点击打开链接

   今天我们来讲一讲堆排序,介绍堆排序之前请大家先回想一下直接选择排序,其采用的是直接从剩余记录中线性查找最大记录的方法,没有充分的利用前一轮查找所能得到的information。所以,我们今天用堆数据结构来保持剩余记录相对大小的信息,因而是更有效的选择排序。

涉及到的知识点:

1. 堆排序主要包括两个步骤:(1)对所有记录建立最大堆。(2)取出堆顶的最大记录与数组末端的记录交换,最大记录放在下标n-1的位置,原数组末端元素临时处于根节点;将根元素向下调整到合适的位置,即剩余的n-1个记录重新调整为堆,再取新堆顶最大记录,与数组n-2位交换;.......;不断重复这一操作,直到堆为空。这时数组正好是按从大到小排序。

完整代码如下:(基于最大堆的排序算法 - 元素从下标为0的位置开始存放)

下面....
上代码
// 排序问题总结.cpp: 定义控制台应用程序的入口点。
//排序顺序:从小到大
//堆元素从下标为0的地方开始存放
#include "stdafx.h"
#include <iostream>
using namespace std;

template <class T>
class Heap
{
	private:
		T * A;  //存放堆元素的数组
		int size;  //堆中的元素个数

	public:
		Heap(int InputSize);  //构造函数
		~Heap() { delete[] A; cout << "析构函数执行成功" << endl; }  //析构函数
		void HeapSort();  //堆排序
		void PercDown(int p,int N);  //将N个元素的数组中以A[p]为根的子堆调整为最大堆
		void PrintHeap();  //输出堆中的元素
		friend void Swap(T* a, T* b);  //交换堆顶和堆末尾的元素 - 友元函数类似于全局函数
};

//Heap类的实现
//Heap(int InputSize) - 构造函数
template <class T> Heap<T>::Heap(int InputSize)
{
	this->size = InputSize;  //this指当前对象
	this->A = new T[size];  //为数组分配空间
	for (int i = 0; i < size; ++i)
		cin >> A[i];
}

//Swap(T,T) - 交换堆顶和堆末尾的元素
template <class T> void Swap(T* a, T* b)
{
	int tmp;
	tmp = *a;
	*a = *b;
	*b = tmp;
}

//堆排序 - HeapSort()
template <class T> void Heap<T>::HeapSort()
{
	int i;
	//for循环中的语句是针对从下标为0的位置开始存放的情况 
	//该最大堆的建立是从完全二叉树的倒数第二层开始的 
	for (i = size / 2 - 1; i >= 0; i--)   //建立最大堆
		PercDown(i,size);
	for (i = size - 1; i > 0; i--)
	{
		//删除最大堆顶
		Swap(&A[0], &A[i]);  //将堆顶元素放到堆末尾,并且堆的规模减1 
		PercDown(0,i);  //将规模减小的堆再一次调整为最大堆 
	}
}

//将N个元素的数组中以A[p]为根的子堆调整为最大堆
//最大堆的建立不是一步到位的
//先调整其左、右子树,一步一步上滤
template <class T> void Heap<T>::PercDown(int p,int N)
{
	int parent, child;
	int x;

	x = A[p];      //取出根节点存放的值
	for (parent = p; (parent * 2 + 1) < N; parent = child)
	{
		child = parent * 2 + 1;
		if ((child != N - 1) && (A[child] < A[child + 1]))
			child++;   //child指向左右子节点的最大值
		if (x > A[child]) break;   //找到了合适的位置
		else        //下滤x
			A[parent] = A[child];
	}
	A[parent] = x;
}

//PrintHeap()
template <class T> void Heap<T>::PrintHeap()
{
	for (int i = 0; i < size; ++i)
		cout << A[i] << " ";
}

int main()
{
	int size;
	cin >> size;
	Heap<int> h(size);

	h.HeapSort();

	h.PrintHeap();

	cout << endl;
	
	return 0;
}

运行结果:

第一行为待排元素个数
第二行为初始序列
第三行为结果

猜你喜欢

转载自blog.csdn.net/y_16041527/article/details/80448979
今日推荐