poppo大根堆的原理与实现。
大根堆的定义:1 大根堆是一个大根树 2 大根堆是一个完全二叉树
所以大根堆用数组表示是连续的,不会出现空白字段。
对于大根堆的插入

对于大根堆的插入,可以在排序前确定大根堆的形状,可以确定元素5从位置6插入,那么比较元素5和位置3的元素2,
元素5比元素2大,将2下移。接着比较元素5和元素20,一次类推,直到找到元素5的合理位置。
接着看一下如果插入的元素是21,怎么进行排序。

21比2大,所以将2下移,接着比较21和20,发现20比21小,20下移,最终21放到
根的位置。形成大根堆。
对于大根堆的删除

大根堆删除根元素,那么可以确定删除后的形状。可以理解成将最后一个叶子节点放在
合理位置,首先比较叶子节点元素10和根节点的两个孩子15和2,选出两个节点中最大的
元素15,15比10大,所以15进行气泡。放到根节点。然后15所在的位置2,变为不确定的问号。
由于14比10大,那么14起泡放到位置2,根据大根堆的形状,最后将10放到左节点。
将一个无序的完全二叉树变为大根堆

将一个无序的完全二叉树变为大根堆(或者小根堆),首先要找到最有一个叶子节点的父节点,
对该父节点为根节点的子树进行排序,生成一个大根堆(小根堆)。然后从节点位置依次
向前做同样的排序,将该节点到根节点的所有子树变为大根堆(小根堆)
举例子:

如上图所示,因为总共有6个节点,6/2 = 3,所以元素19的父节点是位置3的元素4,
将以4位根的子树变为大根堆。因为19比4大,所以19上移,4做叶子节点。依次类推,
从位置3到位置1的所有子树都按照这种逻辑处理,最终变成大根堆。
接着要处理位置2的子树,位置2的元素为1,两个节点为25和12,选最大的元素25,因为
25比1大,所以25进行上移,1变为叶子节点。这样位置2的子树就处理完了。
接着处理位置1,因为位置1的元素为6,两个节点分别为25和19,取最大节点元素25,
因为25比6大,所以25上移,而此时位置2还有两个节点元素1和元素12,需要比较元素6
和这两个节点中最大的,以确定大根堆。由于12比6大,所以12上移,6变为叶子节点。
最终用数组表示这个大根堆就是[25,12,19,1,6,4]
下面是代码实现和测试:
大根堆的类结构:
template <class T>
class maxHeap
{
public:
maxHeap(void)
{
m_nHeapSize = ;
m_nHeapCapacity = ;
m_pHeapArray = NULL;
} maxHeap(const maxHeap& tempHeap);
maxHeap(T * heapArray, int arrayLen); ~maxHeap(){ if(m_pHeapArray)
{
free(m_pHeapArray);
} m_pHeapArray = NULL;
m_nHeapSize = ;
m_nHeapCapacity = ;
} //插入节点
void insertNode(const T& t);
//pop堆顶元素
const T& popRoot();
//打印自己的堆元素,用数组表示法输出
void printHeap();
//将一个无序的数组变为大根堆
void createMaxHeap(T * heapArray, int arrayLen);
//销毁自己的堆元素
void deallocMaxHeap();
//打印数组的元素
void printHeap(T * heapArray, int arrayLen); private:
//堆的数组元素,连续区间首地址
T* m_pHeapArray;
//当前使用的大小
int m_nHeapSize;
//堆的容量,实际开辟的大小
int m_nHeapCapacity;
};
两个构造函数:
template <class T>
maxHeap<T>::maxHeap(const maxHeap &tempHeap){
m_nHeapSize = tempHeap.m_nHeapSize;
m_pHeapArray = malloc(sizeof(class maxHeap) *m_nHeapSize);
m_nHeapCapacity = m_nHeapSize;
} template <class T>
maxHeap<T>::maxHeap(T * heapArray, int arrayLen)
{
m_nHeapSize = arrayLen;
m_pHeapArray = malloc(sizeof(class maxHeap) * m_nHeapSize);
m_nHeapCapacity = arrayLen;
}
插入节点:
template <class T>
void maxHeap<T>::insertNode(const T& node)
{
m_nHeapSize ++;
if(m_nHeapSize >= m_nHeapCapacity)
{
m_pHeapArray = (T *)realloc(m_pHeapArray, sizeof(T) * m_nHeapSize *);
} m_nHeapCapacity = m_nHeapSize*; //当前节点所在位置
int currentIndex = m_nHeapSize;
//该节点父节点所在位置
int parentIndex = currentIndex/;
//当前节点为根节点,跳出循环直接插入即可
while(currentIndex != )
{
//父节点元素小于该node,因为是大根堆,所以父节点下移
if(m_pHeapArray[parentIndex -] < node)
{
//父节点数据下移
m_pHeapArray[currentIndex - ] = m_pHeapArray[parentIndex -];
//更新当前节点位置,当前比较位置上移
currentIndex = currentIndex/;
//父节点位置同样上移
parentIndex = parentIndex/;
}
else
{
break;
}
}
//因为节点数是从1开始的,所以节点数-1表示数组中的位置
m_pHeapArray[currentIndex -] = node; }
打印元素:
template <class T>
void maxHeap<T>::printHeap()
{
cout <<"current max heap array is :" << endl;
for(int i = ; i < m_nHeapSize; i++)
{
cout << m_pHeapArray[i] << " ";
}
cout << endl;
} template <class T>
void maxHeap<T>::printHeap(T * heapArray, int arrayLen)
{
cout <<"current max heap array is :" << endl;
for(int i = ; i < arrayLen; i++)
{
cout << heapArray[i] << " ";
}
cout << endl;
}
pop堆顶的元素,取出最大值
template <class T>
const T& maxHeap<T>::popRoot()
{
//先取出最后的叶子节点
const T& lastEle = m_pHeapArray[m_nHeapSize-]; //更新heapsize
m_nHeapSize --; //删除时需要从根节点开始,找到最大值起泡
int currentIndex= ;
//当前节点的做孩子
int leftChild = currentIndex *;
//当前节点的孩子节点超过堆大小,说明该节点为叶子节点
while(leftChild <= m_nHeapSize)
{
int bigChild = leftChild;
//取出两个孩子中大的孩子,然后将大的孩子节点数据上移
if(leftChild < m_nHeapSize && m_pHeapArray[leftChild-] < m_pHeapArray[leftChild])
{
//更新大孩子节点为右节点
bigChild = leftChild +;
}
//比较两个节点中大的孩子节点和取出的最后叶子节点,那个数值大
//如果最后的叶子节点数值大,那么可以跳出循环,因为找到了lastEle的合理位置
//剩余的树也是大根堆
if(m_pHeapArray[bigChild -] <= lastEle)
{
break;
}
//大节点数据上移
m_pHeapArray[currentIndex -] = m_pHeapArray[bigChild-];
//更新插入位置为当前大节点位置
currentIndex = bigChild;
leftChild = currentIndex *;
} m_pHeapArray[currentIndex-] = lastEle; return lastEle;
}
将一个无序的数组元素,变为大根堆
template <class T>
void maxHeap<T>::createMaxHeap(T * heapArray, int arrayLen)
{
//判断异常
if(arrayLen <= || heapArray == NULL)
{
return ;
} //从最后一个叶子节点的父节点开始,依次从该位置到根节点
//例如该位置为3,那么位置3,位置2,位置1的根节点的子树依次处理为大根堆 int currentIndex = arrayLen;
//父节点位置
int beginIndex = currentIndex/;
//依次处理,形成子树大根堆
for(int i = beginIndex; i > ; i--)
{
int rootEle = heapArray[i-]; int curNode = i;
int leftChild = i *;
while(leftChild <= arrayLen)
{
int bigChild = leftChild; int rootElePrint = heapArray[leftChild-];
int rightElePrint = heapArray[leftChild+ -] ; if(leftChild + <= arrayLen && heapArray[leftChild+ -] > heapArray[leftChild-])
{
bigChild = leftChild +;
} if(heapArray[bigChild -] <= rootEle )
{
break;
} heapArray[curNode -] = heapArray[bigChild -];
curNode = bigChild;
leftChild = curNode *;
} heapArray[curNode -] = rootEle; }
}
源代码下载地址: http://download.csdn.net/detail/secondtonone1/9575112
整个代码就到这里吧,这是我的公众号,希望关注下:

poppo大根堆的原理与实现。的更多相关文章
- Java实现堆排序(大根堆)
堆排序是一种树形选择排序方法,它的特点是:在排序的过程中,将array[0,...,n-1]看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲节点和孩子结点之间的内在关系,在当前无序区中选择关键 ...
- bzoj4919 [Lydsy1706月赛]大根堆
Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质: ...
- bzoj 4919: [Lydsy六月月赛]大根堆
Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质: ...
- BZOJ4919:[Lydsy1706月赛]大根堆(set启发式合并)
Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质: ...
- 【BZOJ4919】[Lydsy六月月赛]大根堆 线段树合并
[BZOJ4919][Lydsy六月月赛]大根堆 Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切 ...
- CJOJ 2482 【POI2000】促销活动(STL优先队列,大根堆,小根堆)
CJOJ 2482 [POI2000]促销活动(STL优先队列,大根堆,小根堆) Description 促销活动遵守以下规则: 一个消费者 -- 想参加促销活动的消费者,在账单下记下他自己所付的费用 ...
- bzoj 4919 [Lydsy1706月赛]大根堆 set启发式合并+LIS
4919: [Lydsy1706月赛]大根堆 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 599 Solved: 260[Submit][Stat ...
- java堆排序(大根堆)
实现堆排序的算法思路是先创建堆,也就是从叶子节点起对每一层的孩子节点及其对应位置的父亲节点进行比较,较大的孩子节点替换较小的父亲节点,一级一级比较替换,就创建出了大根堆,小根堆反之.创建好大根堆以后, ...
- bzoj 1577: [Usaco2009 Feb]庙会捷运Fair Shuttle——小根堆+大根堆+贪心
Description 公交车一共经过N(1<=N<=20000)个站点,从站点1一直驶到站点N.K(1<=K<=50000)群奶牛希望搭乘这辆公交车.第i群牛一共有Mi(1& ...
随机推荐
- windows8和windows server2012不联网安装.net 3.5(包括2.0和3.0)
安装完win8后 发现系统默认没有安装.net3.5 如果使用在线更新的话需要很久才能完成,特别是当前的网速以及微软的服务器.速度很忙,其实我们利用win8的安装盘就可以不需要联网更新,而且几分钟就搞 ...
- 《linux内核分析》 第一周
20135130 王川东 计算机是如何工作的? 计算机的基本原理是存储程序和程序控制.预先要把指挥计算机如何进行操作的指令序列(称为程序)和原始数据通过输入设备输送到计算机内存贮器中.每一条指令中明 ...
- 使用JSon实现三级联动
JSon实现三级联动 我觉得我这个方法比较麻烦,但是目前技术还比较弱,所以先做个笔记自己理解.目前没有和后台交互,只是在前台页面实现了 jQuery和JSon数据实现的,代码如下: <!DOCT ...
- Windows Forms编程实战学习:第一章 初识Windows Forms
初识Windows Forms 1,用C#编程 using System.Windows.Forms; [assembly: System.Reflection.AssemblyVersion(& ...
- vs2015关于_CRT_SECURE_NO_WARNINGS警告说明
vs2015关于_CRT_SECURE_NO_WARNINGS警告说明 在VS中调用 strcpy.strcat 等函数时会提示 _CRT_SECURE_NO_WARNINGS 警告,原因是这些函数不 ...
- 一次WebSphere性能问题诊断过程
一次接到用户电话,说某个应用在并发量稍大的情况下就会出现响应时间陡然增大,同时管理控制台的响应时间也很慢,几乎无法进行正常工作. 赶到现场后,查看平台版本为Webshpere6.0.2.29,操作系统 ...
- Windows下基于http的git服务器搭建-gitstack
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Windows下基于http的git服务器搭建-gitstack 本文地址:http: ...
- 【Biocode】产生三行的seq+01序列
代码说明: sequence.txt与site.txt整合 如下图: sequence.txt: site.txt: 整理之后如下: 蛋白质序列中发生翻译后修饰的位置标记为“1”,其他的位置标记为“0 ...
- jdk&tomcat环境变量配置及同时运行多个tomcat方法
一:jdk配置 安装jdk1.7.0_51,安装过程中所有选项保持默认:最后配置 JDK的环境变量: 在“我的电脑”上点右键—>“属性”—>“高级”—>“环境变量(N)”. 1.新建 ...
- saltstack基础篇
使用saltstack的前提是PPT 服务.流程.工具和技术 安装 rpm -Uvh http://mirrors.yun-idc.com/epel/6Server/x86_64/epel- ...