最大堆、最小堆C++实现

最近学习了最大堆、最小堆数据结构,这个并不难懂,但在编程、编写学习笔记时,发现有不少错误、理解不深刻,有比较多的细节需要注意的,特别是孩子节点的访问条件、几个节点之间的比较出了不少错误,但经过一番努力,终于解决了。下面是最大堆的实现过程


最大堆、最小堆 C++实现
最大堆概念:每个节点的值都大于其子节点的值的完全二叉树。
最小堆概念:每个节点的值都小于或等于其子节点的值的完全二叉树。

 

使用数组存储完全二叉树

 

在数组中存储二叉树,父节点 i 与孩子节点的关系是 2i + 1、2i + 2
左孩子:2i + 1 
有孩子:2i + 2

 

 

最大堆构造过程
下面将讲述五个元素{2,5,4,7,9} 构造最大堆过程。开始,插入关键值为2节点,节点2处于树根,插入结束。当插入关键值为5的节点时,由于节点5 比父节点 2大,互换。节点5处于树根,插入结束。插入节点4时,节点4比父节点5小,不用交换,插入结束。插入节点7时,节点7比父节点2大,互换。节点7比父节点5大,继续互换。交换完毕后节点7处于树根,插入结束。插入节点9,节点9比父节点5大,互换。节点9比节点7大,互换。此时节点9位于树根,插入结束。

 

算法过程:
首先检测堆是否已满,如果堆不满,i值编程 n+1,即新堆的长度,然后为item定位,确定它的堆中位置。while循环完成定位工作,具体做法是,从最大堆的新叶子i开始,与位于i/2的父亲比较,这样逐层向上,知道一个父亲关键字不少于它的位置,或者一直到根。(P175《数据结构基础 C语言版》第二版 Ellis Horowitz 、Sartaj Sahni、Susan Anderson-Freed 著)
说明:当初始为1开始,节点i的父亲下标为 i/2,初始以0位开始,节点i的父亲下标为
 (i-1)/2


部分代码
 

void push(T ielement)
 {                
     m_vecheap.push_back(ielement);//为向量增加一个元素位置空间                                        
     int hole=m_vecheap.size()-1;
     while(hole !=0 && ielement > m_vecheap[(hole-1)/2])
     {
          m_vecheap[hole]=m_vecheap[(hole-1)/2];
          hole =(hole-1)/2;                        
      }
      m_vecheap[hole]=ielement;        
 }   

 

最大堆删除过程
保存最后一个节点node,将二叉树中最后一个节点删除,将hole指向0,【1】通过比较node、hole的孩子节点,得到最大的节点max, 如果max是node,则将node存放到hole指向的空间,结束删除动作,否则 将max放到hole指向的空间,然后hole指向max位置。重复【1】步骤,直到hole没有孩子节点,然后将node存放到hole指向的空间。

 

算法过程:
沿堆下滑,一路上比较父亲与孩子的关键字,并做必要交换,直到满足堆性质为止。


部分代码

 

T pop()
{
                
    T retElt;                
    if(m_vecheap.size()==0)return retElt;
    T element = m_vecheap[m_vecheap.size()-1];                
    m_vecheap.pop_back();                
    int hole=0;                        
    int nNum=m_vecheap.size();
    retElt=m_vecheap[hole];
    while(2*hole+1< nNum)
    {                                                                
        //比较hole的两孩子,取数值最大的孩子下标
       int maxIndex;
       int maxIndex;
	if (2 * hole + 1 < m_vecheap.size() && 2 * hole + 2 >= m_vecheap.size()){
	    maxIndex = 2 * hole + 1;
	}
	else{
	maxIndex = m_vecheap[2 * hole + 1] > m_vecheap[2 * hole + 2] ? (2 * hole + 1) : (2 * hole + 2);
	}	                         
        //由最大对定义得m_vecheap[maxIndex]是最大的元素
        if (element >m_vecheap[maxIndex]){break;}
        //填充hole,hole向maxIndex处下滑                               
        m_vecheap[hole] = m_vecheap[maxIndex];                                
        hole =maxIndex;
     }
     m_vecheap[hole]=element;
     return retElt;
}

 

 

 

 

 

 

 

  完整代码

#include<vector>
#include<stdio.h>
#include<stdlib.h>
#define TRACE printf
using namespace std;
template<class T>
template<class T>
class CHeap
{
public:
	explicit CHeap(){}
	~CHeap(){}
	void push(T ielement)
	{
		m_vecheap.push_back(ielement);//为向量增加一个元素位置空间                                        
		int hole = m_vecheap.size() - 1;

		while (hole != 0 && ielement > m_vecheap[(hole - 1) / 2])
		{
			m_vecheap[hole] = m_vecheap[(hole - 1) / 2];
			hole = (hole - 1) / 2;
		}
		m_vecheap[hole] = ielement;
	}

	T pop()
	{
		T retElt;
		if (m_vecheap.size() == 0)return 0;
		int element = m_vecheap[m_vecheap.size() - 1];
		m_vecheap.pop_back();
		if (m_vecheap.size() == 0)return element;
		int hole = 0;
		int nNum = m_vecheap.size();
		retElt = m_vecheap[hole];
		while (2 * hole + 1 < nNum)
		{
			//比较hole的两孩子,取数值最大的孩子下标
			int maxIndex;
			if (2 * hole + 1 < m_vecheap.size() && 2 * hole + 2 >= m_vecheap.size()){
				maxIndex = 2 * hole + 1;
			}
			else{
				maxIndex = m_vecheap[2 * hole + 1] > m_vecheap[2 * hole + 2] ? (2 * hole + 1) : (2 * hole + 2);
			}			
			//由最大对定义得m_vecheap[maxIndex]是最大的元素
			if (element > m_vecheap[maxIndex]){ break; }
			//填充hole,hole向maxIndex处下滑                               
			m_vecheap[hole] = m_vecheap[maxIndex];
			hole = maxIndex;
		}
		m_vecheap[hole] = element;
		return retElt;
	}
public:
	vector<T> m_vecheap;
};
int main(void){		
	CHeap<int> heap;	
 
	heap.push(2);	
    heap.push(3);	
	heap.push(6);	
	heap.push(5);	
	heap.push(9);	
	heap.push(8);
    heap.push(7);
    heap.push(4);
 
	for (unsigned i=0 ; i < heap.m_vecheap.size(); i++)
	{
		TRACE("%d ",heap.m_vecheap[i]);
	}
	TRACE("\n=================================\n");
        int size=heap.m_vecheap.size(); 
	for (unsigned i=0 ; i < size; i++)
	{
                TRACE("pop elt %d\n",heap.pop());			
	}
	TRACE("\n============================\n");
 
	return 0;
}

程序运行结果

 

9 6 8 4 5 3 7 2
=================================
pop elt 9
pop elt 8
pop elt 7
pop elt 6
pop elt 5
pop elt 4
pop elt 3
pop elt 2

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值