堆(树形结构应用)

堆其实就是由完全二叉树组成的,

目录

 最大堆的插入与删除

 最小堆的定义

 最小堆的建立

 初始化最小堆(向下调整)

 最小堆的插入(向上调整)

 最小堆的删除算法(向下调整)


 

堆(heap)
堆(英语:heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。
堆的性质:
1.堆中某个节点的值总是不大于或不小于其父节点的值。
2.堆总是一棵完全二叉树。

堆的分类
将根节点最大的堆叫做最大堆或大顶堆,根节点最小的堆叫做最小堆或小顶堆。常见的堆有二叉堆、斐波那契堆等。
堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。
(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4…n/2)
若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。
每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:

 最大堆的插入与删除

 由于堆是由完全二叉树构成,所以堆用二叉树的顺序结构组成

由于堆存储在下标从 0 开始计数的一维数组中,因此在堆中给定下标为 i 的结点时
如果 i = 0 ,结点 i 是根结点,无双亲;否则结点 i 父结点 为结点 (i-1)/2(向下取整)
如果 2 i +1 n - 1 ,则结点 i 无左子女;否则结点 i 左子女 为结点 2 i +1
如果 2 i +2 n - 1 ,则结点 i 无右子女;否则结点 i 右子女 为结点 2 i +2

 最小堆的定义

template <class T, class E>
class MinHeap : public MinPQ<T, E> {
//最小堆继承了(最小)优先级队列
public: 
     MinHeap (int sz = DefaultSize);	//构造函数
     MinHeap (E arr[], int n);		//构造函数
     ~MinHeap() { delete [ ] heap; }	//析构函数
     bool Insert (E& d);			//插入
     bool Remove (E& d);			//删除
     bool IsEmpty () const		//判堆空否
       { return  currentSize == 0; }
     bool IsFull () const		//判堆满否
 	   { return currentSize == maxHeapSize; }	
	 void MakeEmpty () { currentSize = 0; }	//置空堆
private: 
     E *heap;			//最小堆元素存储数组
     int currentSize;		//最小堆当前元素个数
     int maxHeapSize;	//最小堆最大容量
     void siftDown (int start, int m);	//调整算法
     void siftUp (int start);		          //调整算法
};

 最小堆的建立

template <class T, class E>
MinHeap<T>::MinHeap (int sz) {
     maxHeapSize = (DefaultSize < sz) ? sz : DefaultSize;
     heap = new E[maxHeapSize];  	//创建堆空间
     if (heap == NULL) {
          cerr << “堆存储分配失败!” << endl;  exit(1);
     }
     currentSize = 0;				//建立当前大小
};

 初始化最小堆(向下调整)

template <class T, class E>
MinHeap<T>::MinHeap (E arr[], int n) {
     maxHeapSize = (DefaultSize < n) ? n : DefaultSize;
     heap = new E[maxHeapSize]; 
	 if (heap == NULL) {
        cerr << “堆存储分配失败!” << endl;  exit(1);
     }
     for (int i = 0; i < n; i++) heap[i] = arr[i];
     currentSize = n;	       //复制堆数组, 建立当前大小
	 int currentPos = (currentSize-2)/2;//减去n包含的0节点与最后一位n节点	
                        //找最初调整位置:最后分支结点
     while (currentPos >= 0) {	    //逐步向上扩大堆
       siftDown (currentPos, currentSize-1);
           	//局部自上向下下滑调整
           currentPos--;
     }					
};

 

 

template <class T, class E>
void MinHeap<T>::siftDown (int start, int m ) {
//私有函数: 从结点start开始到m为止, 自上向下比较, 
//如果子女的值小于父结点的值,  则关键码小的上浮, 
//继续向下层比较, 将一个集合局部调整为最小堆。
	int i = start,   j = 2*i+1;  	//j是i的左子女位置
	E temp = heap[i]; 			
	while (j <= m) {			//检查是否到最后位置
	     if ( j < m && heap[j] > heap[j+1] ) j++;
				 	     //让j指向两子女中的小者
 		if ( temp <= heap[j] ) break;	//小则不做调整
		else { heap[i] = heap[j];  i = j; j = 2*j+1; }
				     	//否则小者上移, i, j下降
	 }
	 heap[i] = temp;	      	//回放temp中暂存的元素
};

 最小堆的插入(向上调整)

 每次插入都加在堆的最后,再自下向上执行调整,使之重新形成堆,时间复杂性O(log2n)

template <class T, class E>
bool MinHeap<T>::Insert (const E& x )  {
//公共函数: 将x插入到最小堆中
    if ( currentSize == maxHeapSize ) 	//堆满
        { cerr << "Heap Full" << endl;  return false; }
	heap[currentSize] = x;  		//插入
	siftUp (currentSize);			//向上调整
	currentSize++;				//堆计数加1
	return true;
};


template <class T, class E>
void MinHeap<T>::FilterUp (int start) {
//私有函数: 从结点start开始到结点0为止, 自下向上
//比较, 如果子女的值小于父结点的值, 则相互交换, 
//这样将集合重新调整为最小堆。关键码比较符<=
//在E中定义。
int j = start,  i = (j-1)/2;   E temp = heap[j];
while (j > 0) {		//沿父结点路径向上直达根
	      if (heap[i] <= temp)
                break;							//父结点值小, 不调整
		  else { 
                heap[j] = heap[i];  
                j = i; 
                i = (i-1)/2; }
					//父结点结点值大, 调整
}	
	heap[j] = temp;				//回送
};

 最小堆的删除算法(向下调整)

template <class T, class E>
bool MinHeap<T>::Remove (E& x) {
	if ( !currentSize ) {		//堆空, 返回false
	     cout << "Heap empty" << endl;  return false;
    }
	x = heap[0];  
	heap[0] = heap[currentSize-1];
	currentSize--;
	siftDown(0, currentSize-1);    	//自上向下调整为堆
	return true;			//返回最小元素
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值