用仿函数实现大小堆及堆排序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用仿函数实现大小堆及堆排序相关的知识,希望对你有一定的参考价值。


"2.h"
#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;
template<class T>
struct Less
{
	bool operator()(const T& left,const T& right)
	{
		return left<right;
	}
};
template<class T>
struct Greater
{
	bool operator()(const T& left,const T& right)
	{
		return left>right;
	}
};
template<class T,class Compare=Less<T>>//小堆//修改
class Heap
{
public:
	Heap();
	Heap(const T* a,size_t size);
	void Push(const T& x);
	void Pop();
	T& Top();
	void Print();
	void HeapSort();
	void HeapSort1();
protected:
	void AdjustDown(int parent);
	void AdjustUp(int child);
	void _AdjustDown(int child,int size);
protected:
	vector<T> _array;
	Compare _compare;
};
template<class T,class Compare>
Heap<T,Compare>::Heap(const T* a,size_t size)
	{
		for(size_t i=0;i<size;i++)
		{
			_array.push_back(a[i]);
		}
		for(int i=(_array.size()-2)/2;i>=0;i--)//求父节点的下标为:((子-1)/2),而size()比最大下标多一,所以为减2
		{
			AdjustDown(i);
		}
		/*for(int i=_array.size()-1;i>0;i--)
		{
			AdjustUp(i);
		}*/
	}
template<class T,class Compare>
void Heap<T,Compare>::AdjustDown(int parent)
	{
		int child=parent*2+1;
		while(child<_array.size())
		{
			if((child+1<_array.size())&&_compare(_array[child+1],_array[child]))//右孩子是否越界条件易忘
				swap(_array[child],_array[child+1]);
			if(Compare()(_array[child],_array[parent]))
			{
				swap(_array[child],_array[parent]);
				parent=child;
				child=parent*2+1;
			}
			else
				break;
		}
	}
template<class T,class Compare>
void Heap<T,Compare>::AdjustUp(int child)
{
	int parent=(child-1)/2;
	while(child>0)//条件不能写成parent>=0,因为parent不可能小于0
	{
		if(child+1<_array.size()&&_compare(_array[child+1],_array[child]))  
			swap(_array[child],_array[child+1]);
		if(Compare()(_array[child],_array[parent]))
		{
			swap(_array[child],_array[parent]);
			child=parent;
			parent=(child-1)/2;
		}
		else
			break;
	}
}
//插进来的放在最后的子节点位置
template<class T,class Compare>
void Heap<T,Compare>::Push(const T& x)//记住加上const和&
{
	_array.push_back(x);
	//AdjustDown(0);  //想清楚可不可用AdjustDown(0); //不可以,主要看哪儿动了
	AdjustUp(_array.size()-1);
}
//Pop出去的是根,下标为0
template<class T,class Compare>
void Heap<T,Compare>::Pop()
{
	//
	swap(_array[0],_array[_array.size()-1]);
	_array.pop_back();
	AdjustDown(0);
}
template<class T,class Compare>
T& Heap<T,Compare>::Top()
{
	return _array[0];
}
template<class T,class Compare>
void Heap<T,Compare>::Print()
{
	for(size_t i=0;i<_array.size();i++)
	{
		cout<<_array[i]<<" ";
	}
	cout<<endl;
}
	
//把堆排成大堆,交换堆顶和堆尾,每次除掉堆尾数据其余数据继续排成大堆...
//理解错误,虽然能实现堆排序,但误用AdjustUp(int child)(没去掉注释的两行)——向上排序只用于已排好二叉树进行插入时,少数数据的改变,不能在构造函数中直接用向上排序构造template<class T,class Compare>
void Heap<T,Compare>::HeapSort()
{
	for(int i=_array.size()-1;i>=0;i--)
	{			
		for(int j=_array.size()-1;j>0;j--)//除掉堆尾数据有误
			AdjustUp(j);
		swap(_array[0],_array[i]);
	}
}
//由于要改变size,所以得重建AdjustDown
template<class T,class Compare>
void Heap<T,Compare>::HeapSort1()
{
	for(int size=_array.size();size>1;size--)
	{
		for(int i=(size-2)/2;i>=0;i--)
		{
			_AdjustDown(i,size);
		}
		swap(_array[0],_array[size-1]);
	}	
}
template<class T,class Compare>
void Heap<T,Compare>::_AdjustDown(int parent,int size)
{
	int child=parent*2+1;
	while(child<size)
	{
		if((child+1<size)&&_compare(_array[child+1],_array[child]))
			swap(_array[child],_array[child+1]);
		if(Compare()(_array[child],_array[parent]))
		{
			swap(_array[child],_array[parent]);
			parent=child;
			child=parent*2+1;
		}
		else
			break;
	}
}
#include "2.h"
#include<iostream>
using namespace std;
void Test1()
{
	int a[]={1,2,9,5,8,7,4,3};
	//Heap<int> hp1(a,8);
	Heap<int,Greater<int>> hp1(a,8);
	hp1.Print();
	hp1.Push(0);
	hp1.Print();
	hp1.Pop();
	hp1.Print();
	int top=hp1.Top();
	cout<<top<<endl;
	hp1.HeapSort();
	hp1.Print();
}
int main()
{
	Test1();
	system("pause");
	return 0;
}


本文出自 “sunshine225” 博客,请务必保留此出处http://10707460.blog.51cto.com/10697460/1758170

以上是关于用仿函数实现大小堆及堆排序的主要内容,如果未能解决你的问题,请参考以下文章

最大堆,最小堆及堆排序

堆及堆的变种

挖掘算法中的数据结构:排序算法总结 和 索引堆及优化(堆结构)

堆结构及堆排序详解

二叉堆及优先级队列

最小/大堆的操作及堆排序