C++数据结构--用向量数组实现大(小)根堆的插入和删除

来源:互联网 发布:网络男歌手名字大全 编辑:程序博客网 时间:2024/06/05 19:25
1.基于数组的二叉树
  例如,可以用向量数组{5,1,3,9,6,2,4,7,0,8}表示下图的完全二叉树
 
  
  Tips:
  对于结点v[i],可利用下列公式计算其子结点和父结点
  左结点:v[2*i+1]
  右结点:v[2*i+2]
  父结点: v[int((i-1)/2] <==> v[(i-1)/2]  因为i为整数


2.大根堆:父结点总是大于或等于它的每个子结点
  小根堆:父结点总是小于或等于它的每个子结点
  example:
   




3.大根堆的插入操作
  Example:在大根堆插入50
 


  调整大根堆
 


 


4从对中删除堆中的根节点元素
  Example:
   step1: 把根结点和最后一个结点交换
   


   step2:调整
   
    






 实现代码:
#include <iostream>
#include<vector>
#include<functional>
using namespace std;


template<typename T,typename compare>
/*v为向量数组 
 *last为向量数组的size(), 
 *此算法假设[0,last-2]范围是已经调整好了的大根堆 
 *cp为比较函数对象,例如:当greater_equal<int> ge时实现大根堆 
 *当less_equal<int>  le时实现小根堆 
 */

void insertHeap(vector<T> &v,int last,compare cp=compare())
{
int currPos=last-1;
//当前结点索引 
int prtPos=(currPos-1)/2;
//父结点索引
T target=v[last-1]; //保存将要被调整的目标结点 
while(currPos)//当currPos!=0
{
if(cp(target,v[prtPos]))
{
v[currPos]=v[prtPos];  //用父结点的值覆盖当前结点
currPos=prtPos;     //改变当前结点索引为父结点,继续向上查找 
prtPos=(currPos-1)/2; 
}
else    //找到了正确位置,跳出循环 
 {
 break; 
 }
}

v[currPos]=target;   //把被调整的目标结点放到正确的位置 
}


template<typename T,typename compare>
/*此算法假设v[first,last-1]范围内只有v[fisrt]需要被调整 
 *fisrt为需要被调整的结点索引 
 *last为向量数组中可能被调整结点的最后一个节点的下标+1 
 */ 

void adjustHeap(vector<T> &v,int first,int last,compare cp=compare())
{
int prtPos=first;  //当前父结点索引
int chilPos=2*prtPos+1; //左结点或右节点索引
    T target=v[first];   //将要被调整的结点 
while(chilPos<=last-1)
{
if((chilPos+1<=last-1)&&cp(v[chilPos+1],v[chilPos]))//如果存在左右结点,则找出符合条件的结点 
{
chilPos=chilPos+1;
}

if(cp(v[chilPos],target))//当前父结点和孩子结点 
{
v[prtPos]=v[chilPos];
prtPos=chilPos;//继续向下查找 
chilPos=2*prtPos+1;
}
else  //找到了正确位置,跳出循环 
{
break;


}

v[prtPos]=target; //把被调整的目标结点放到正确的位置
}


template<typename T,typename compare>
//删除堆中的根结点 
//可能需要调整的范围[0,v.size()-2]
//last为向量数组的size() 

void popHeap(vector<T> &v,int last,compare cp=compare())
{
        T tem=v[0];     //交换根结点和最后一个节点 
v[0]=v[last-1];
v[last-1]=tem; 
adjustHeap(v,0,last-1,cp); //重新调整堆 
}




测试代码 
int main(int argc, char** argv)
 {
  
   int arr[]{20,25,22,10,5,11,55,52,50}; 
   vector<int> vec;
   for(int x:arr)  //vec每插入一个元素,就调用insertHeap来构建堆 
   {
    vec.push_back(x);
    insertHeap(vec,vec.size(),greater_equal<int>());
    
   }
   
  
  while(!vec.empty()) //每删除一个根结点就重新调整堆 
   {
    popHeap(vec,vec.size(),greater_equal<int>());
    cout<<vec.back()<<ends;
    vec.pop_back();
   }
   
  return 0;
}


output:
   55 52 50 25 22 20 11 10 5
原创粉丝点击