堆、堆排序、优先队列

大根堆的实现

注意:数据存储在heap数组中,而且是从下标1开始存储的

#ifndef _MAX_HEAP_
#define _MAX_HEAP_

#include <iostream>
#include <assert.h>
using namespace std;
const int HeapIncreMent = 20;  

template<typename T>
class MaxHeap 
{
public:
	MaxHeap(int capacity = 100);
	~MaxHeap();
public:
	const T& FindMax()const;
	bool IsMaxHeap() const;

	/*插入或删除元素*/
	void Insert(const T& x);
	void DeleteMax();
	void DeleteMax(T& maxItem);

	/*输出堆*/
	friend ostream& operator<< <>(ostream& cout,MaxHeap& Heap);
private:
	int maxSize;
	int curSize;
	T* heap;
private:
	void BuildHeap();
	void HeapAdjust(int hole);
};

template<typename T>
MaxHeap<T>::MaxHeap(int capacity):curSize(0),maxSize(capacity)
{
	heap = new T[maxSize];
}

template<typename T>
MaxHeap<T>::~MaxHeap()
{
	if (heap != NULL)
	{
		maxSize = 0;
		curSize = 0;
		delete[] heap;
		heap = NULL;
	}
}

template<typename T>
const T& MaxHeap<T>::FindMax() const
{
	return heap[1];
}

/*新插入的元素总是和自己的双亲比较,直到找到自己的位置*/
template<typename T>
void MaxHeap<T>::Insert(const T& insertItem)
{
	if (curSize == maxSize - 1)
	{
		maxSize += HeapIncreMent;
		T* newHeap = new T[maxSize];
		memcpy(newHeap,heap,maxSize);
		delete heap;
		heap = newHeap;
	}

	//插入元素,刚开始放入叶子处,之后依次与其双亲比较
	int hole = ++curSize;//首先把元素放入最后面
	heap[0] = insertItem;//做监视哨,减少while循环中的比较次数
	while (insertItem > heap[hole/2])
	{
		heap[hole] = heap[hole/2];//把双亲放到孩子处,腾出位置放待插项
		hole /= 2;
	}
	heap[hole] = insertItem;
}

/*从hole位置开始向下调整,有孩子时继续比较*/
/*调整时,总是与自己的孩子比较,直到没孩子或是比自己孩子都大为止*/
/*与孩子比较时,先找到一个孩子中比较大的,之后再与这个大的比较*/
template<typename T>
void MaxHeap<T>::HeapAdjust(int hole)
{
	T adjustItem = heap[hole];
	for (int child = 2 * hole;child <= curSize;child *= 2)//有孩子才继续比较
	{
		if (child < curSize && heap[child] < heap[child + 1])
		{
			child++;//child总是指向值最大的那个孩子
		}
		if (heap[child] > adjustItem)
		{
			//孩子大于被调整项,孩子要移到双亲的位置,为双亲腾出位置,之后继续比较
			heap[hole] = heap[child];
		}
		else
		{
			break;
		}
		hole = child;
	}
	//循环结束,此时hole就是目标位置
	heap[hole] = adjustItem;
}

/*所有元素均在数组中,调用此函数建堆*/
template<typename T>
void MaxHeap<T>::BuildHeap()
{
	for (int i = curSize / 2;i > 0;i--)
	{
		HeapAdjust(i);
	}
}

template<typename T>
void MaxHeap<T>::DeleteMax(T& maxItem)
{
	assert(curSize > 0);
	maxItem = heap[1];
	heap[1] = heap[curSize--];
	HeapAdjust(1);
}

template<typename T>
void MaxHeap<T>::DeleteMax()
{
	assert(curSize > 0);
	heap[1] = heap[curSize--];
	HeapAdjust(1);
}

//测试函数
template<typename T>
bool MaxHeap<T>::IsMaxHeap() const
{
	assert(curSize > 0);
	for (int hole = curSize;hole > 1;hole /= 2)
	{
		if(heap[hole] > heap[hole/2])
		{
			return false;
		}
	}
	return true;
}

template<typename T>
ostream& operator<<(ostream& cout,MaxHeap<T>& Heap)
{
	for (int i = 1;i <= Heap.curSize;i++)
	{
		cout<<Heap.heap[i]<<" ";
	}
	cout<<endl;
	return cout;
}

#endif //_MAX_HEAP_

int main()
{
	int num = 0;
	int maxNum = 0;
	MaxHeap<int> maxHeap;

	//测试Insert函数
	for (int i = 0;i < 20;i++)
	{
		num = rand()%100;
		maxHeap.Insert(num);
	}

	cout<<maxHeap<<endl;
	bool isMaxHeap = maxHeap.IsMaxHeap();
	if (isMaxHeap)
	{
		cout<<"这是个大根堆"<<endl;
	}
	else
	{
		cout<<"这不是个大根堆"<<endl;
	}

	//测试FindMax函数
	cout<<maxHeap.FindMax()<<endl;

	//测试DeleteMax函数
	maxHeap.DeleteMax();
	cout<<maxHeap<<endl;
	maxHeap.DeleteMax(maxNum);
	cout<<maxNum<<endl;

	isMaxHeap = maxHeap.IsMaxHeap();
	if (isMaxHeap)
	{
		cout<<"这是个大根堆"<<endl;
	}
	else
	{
		cout<<"这不是个大根堆"<<endl;
	}

	system("pause");
}

堆排序

注意:数据从下标1开始存储的

#include <iostream>
using namespace std;
const int len = 20;

void swap(int& m,int& n)
{
	int tmp = m;
	m = n;
	n = tmp;
}

void HeapAdjust(int arr[],int hole,int curSize)
{
	int adjustItem = arr[hole];
	for (int child = 2 * hole;child <= curSize;child *= 2)
	{
		if (child < curSize && arr[child] < arr[child + 1])
		{
			child++;//child总是指向值最大的那个孩子
		}
		if (arr[child] > adjustItem)
		{
			//孩子大于被调整项,孩子要移到双亲的位置,为双亲腾出位置,之后继续比较
			arr[hole] = arr[child];
		}
		else
		{
			break;
		}
		hole = child;
	}
	//循环结束,此时hole就是目标位置
	arr[hole] = adjustItem;
}


//从小到大排序,建立一个大根堆,先输出最大数放到数组的最后面,次之放到其前面
void HeapSort(int arr[],int curSize)
{
	//建堆
	for (int hole = curSize / 2;hole > 0;hole--)
	{
		HeapAdjust(arr,hole,curSize);
	}
	//调整堆
	for (int i= curSize;i >= 1;i--)
	{
		//堆顶元素和最后一个元素互换
		swap(arr[i],arr[1]);
		//重新调整堆--调整堆顶位置
		//这时待排序元素个数为i-1。需要排序的序列为1 - i-1
		//要对第一个位置(0)进行调整
		HeapAdjust(arr,1,i-1);
	}
}

int main()
{
	int arr[len+1];//下标为0的位置不用
	for (int i = 1;i <= len;i++)
	{
		arr[i]=rand()%1000;
	}
	//输出排序前的序列
	for (int i = 1;i <= len;i++)
	{
		cout<<arr[i]<<" ";
	}
	cout<<endl;

	HeapSort(arr,len);

	//输出排序后的序列
	for (int i = 1;i <= len;i++)
	{
		cout<<arr[i]<<" ";
	}
	cout<<endl;

	system("pause");
	return 1;
}

优先队列

注意:数据从下标1开始存储的,值越高优先级越大

#ifndef _PRIORITY_QUEUE_H_
#define _PRIORITY_QUEUE_H_

#include <iostream>
#include <assert.h>
using namespace std;
const int HeapIncreMent = 20;  

template<typename T>
class PriQueue 
{
public:
	PriQueue(int capacity = 100);
	PriQueue(const PriQueue& priQueue);
	~PriQueue();
public:
	/*查找元素*/
	int Find(const T& insertItem)const; 
	const T& FindMax()const;
	
	bool IsMaxHeap() const;
	
	/*插入或删除元素*/
	void Insert(const T& insertItem);
	void DeleteMax();
	void DeleteMax(T& maxItem);

	/*删除、增加和减少某一优先级*/
	void Delete(int loc);
	void DecreaseKey(int loc,unsigned int det);
	void IncreaseKey(int loc,unsigned int det);

	PriQueue& operator =(const PriQueue& priQueue);
	
	/*输出优先队列*/
	friend ostream& operator<< <>(ostream& cout,PriQueue& priQueue);
private:
	int maxSize;
	int curSize;
	T* heap;
private:
	void BuildHeap();
	void PercolateUp(int hole);
	void PercolateDown(int hole);
};

template<typename T>
PriQueue<T>::PriQueue(int capacity):curSize(0),maxSize(capacity)
{
	heap = new T[maxSize];
}

template<typename T>
PriQueue<T>::PriQueue(const PriQueue& priQueue):curSize(priQueue.curSize),maxSize(priQueue.maxSize)
{
	heap = new T[maxSize];
	for (int i = 1;i <= curSize;i++)
	{
		heap[i] = priQueue.heap[i];
	}

}

template<typename T>
PriQueue<T>::~PriQueue()
{
	if (heap != NULL)
	{
		maxSize = 0;
		curSize = 0;
		delete[] heap;
		heap = NULL;
	}
	
}

template<typename T>
const T& PriQueue<T>::FindMax() const
{
	return heap[1];
}

/*新插入的元素总是和自己的双亲比较,直到找到自己的位置*/
template<typename T>
void PriQueue<T>::Insert(const T& insertItem)
{
	if (curSize == maxSize - 1)
	{
		maxSize += HeapIncreMent;
		T* newHeap = new T[maxSize];
		memcpy(newHeap,heap,maxSize);
		delete heap;
		heap = newHeap;
	}

	//插入元素,刚开始放入叶子处,之后依次与其双亲比较
	int hole = ++curSize;
	heap[curSize] = insertItem;//把元素放入最后面
	PercolateUp(hole);
}

template<typename T>
void PriQueue<T>::PercolateUp(int hole)
{
	heap[0] = heap[hole];//做监视哨,减少while循环中的比较次数
	while (heap[0] > heap[hole/2])
	{
		heap[hole] = heap[hole/2];//把双亲放到孩子处,腾出位置放待插项
		hole /= 2;
	}
	heap[hole] = heap[0];
}

/*从hole位置开始向下调整,有孩子时继续比较*/
/*调整时,总是与自己的孩子比较,直到没孩子或是比自己孩子都大为止*/
/*与孩子比较时,先找到一个孩子中比较大的,之后再与这个大的比较*/
template<typename T>
void PriQueue<T>::PercolateDown(int hole)
{
	T adjustItem = heap[hole];
	for (int child = 2 * hole;child <= curSize;child *= 2)//有孩子才继续比较
	{
		if (child < curSize && heap[child] < heap[child + 1])
		{
			child++;//child总是指向值最大的那个孩子
		}
		if (heap[child] > adjustItem)
		{
			//孩子大于被调整项,孩子要移到双亲的位置,为双亲腾出位置,之后继续比较
			heap[hole] = heap[child];
		}
		else
		{
			break;
		}
		hole = child;
	}
	//循环结束,此时hole就是目标位置
	heap[hole] = adjustItem;
}

/*所有元素均在数组中,调用此函数建堆*/
template<typename T>
void PriQueue<T>::BuildHeap()
{
	for (int i = curSize / 2;i > 0;i--)
	{
		PercolateDown(i);
	}
}

template<typename T>
void PriQueue<T>::DeleteMax(T& maxItem)
{
	assert(curSize > 0);
	maxItem = heap[1];
	heap[1] = heap[curSize--];
	PercolateDown(1);
}

template<typename T>
void PriQueue<T>::DeleteMax()
{
	assert(curSize > 0);
	heap[1] = heap[curSize--];
	PercolateDown(1);
}


/*删除、增加和减少某一优先级*/
/*先把loc的值变为最大,上升到堆顶,在删除堆顶*/
template<typename T>
void PriQueue<T>::Delete(int loc)
{
	assert(loc > 0);
	heap[loc] += FindMax();
	PercolateUp(loc);//把loc位置的值变最大
	DeleteMax();
}

template<typename T>
void PriQueue<T>::DecreaseKey(int loc,unsigned int det)
{
	assert(loc > 0);
	heap[loc] -= det;//值变小,大根堆中应该向下移动
	PercolateDown(loc);
}

template<typename T>
void PriQueue<T>::IncreaseKey(int loc,unsigned int det)
{
	assert(loc > 0);
	heap[loc] += det;
	PercolateUp(loc);
}


template<typename T>
bool PriQueue<T>::IsMaxHeap() const
{
	assert(curSize > 0);
	for (int hole = curSize;hole > 1;hole /= 2)
	{
		if(heap[hole] > heap[hole/2])
		{
			return false;
		}
	}
	return true;
}

template<typename T>
int PriQueue<T>::Find(const T& insertItem) const
{
	for (int i = 1;i <= curSize;i++)
	{
		if (insertItem == heap[i])
		{
			return i;
		}
	}
	return -1;
}

template<typename T>
PriQueue<T>& PriQueue<T>::operator =(const PriQueue& priQueue)
{
	if (this != &priQueue)
	{
		if (maxSize <= priQueue.curSize)
		{
			maxSize = priQueue.maxSize;
			T* tmp = new T[maxSize];
			heap = tmp;
		}
		curSize = priQueue.curSize;
		for (int i = 1;i <= curSize;i++)
		{
			heap[i] = priQueue.heap[i];
		}
	}
	return *this;
}


template<typename T>
ostream& operator<<(ostream& cout,PriQueue<T>& priQueue)
{
	for (int i = 1;i <= priQueue.curSize;i++)
	{
		cout<<priQueue.heap[i]<<" ";
	}
	cout<<endl;
	return cout;
}

#endif  _PRIORITY_QUEUE_H_

int main()
{
	int num = 0;
	int maxNum = 0;
	PriQueue<int> priQueue;

	//测试Insert函数
	for (int i = 0;i < 10;i++)
	{
		num = rand()%100;
		priQueue.Insert(num);
	}
	//测试IsMaxHeap函数
	bool isMaxHeap = priQueue.IsMaxHeap();
	if (isMaxHeap)
	{
		cout<<"这是个大根堆"<<endl;
	}
	else
	{
		cout<<"这不是个大根堆"<<endl;
	}
	cout<<priQueue<<endl;

	//测试拷贝构造函数
	PriQueue<int> priQueue1(priQueue);
	cout<<priQueue1<<endl;

	//测试赋值构造函数
	PriQueue<int> priQueue2;
	priQueue2 = priQueue;
	cout<<priQueue2<<endl;

	//测试FindMax函数
	cout<<"堆顶元素:"<<priQueue.FindMax()<<endl;

	//测试DeleteMax函数
	priQueue.DeleteMax();
	cout<<"删除优先级最大的元素后的序列:"<<endl<<priQueue<<endl;
	priQueue.DeleteMax(maxNum);
	cout<<"优先级最大的元素:"<<maxNum<<endl;
	cout<<"删除优先级最大的元素后的序列:"<<endl<<priQueue<<endl;

	isMaxHeap = priQueue.IsMaxHeap();
	if (isMaxHeap)
	{
		cout<<"这是个大根堆"<<endl;
	}
	else
	{
		cout<<"这不是个大根堆"<<endl;
	}

	/*删除、增加和减少某一优先级*/
	priQueue.IncreaseKey(5,maxNum/2);
	cout<<priQueue<<endl;

	priQueue.DecreaseKey(2,maxNum/2);
	cout<<priQueue<<endl;

	priQueue.Delete(2);
	cout<<priQueue<<endl;
	system("pause");
}

测试代码

for (int hole = curSize;hole > 1;hole /= 2)
{
	assert(heap[hole] <= heap[hole/2]);//孩子要小于双亲
}



 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值