数据结构之二叉堆

二叉堆的介绍

二叉堆是完全二元树或者是近似完全二元树,按照数据的排列方式可以分为两种:最大堆和最小堆。

  • 最大堆:父结点的键值总是大于或等于任何一个子节点的键值;
  • 最小堆:父结点的键值总是小于或等于任何一个子节点的键值。

示意图如下:

二叉堆一般都通过”数组”来实现。数组实现的二叉堆,父节点和子节点的位置存在一定的关系。有时候,我们将”二叉堆的第一个元素”放在数组索引0的位置,有时候放在1的位置。当然,它们的本质一样(都是二叉堆),只是实现上稍微有一丁点区别。
假设”第一个元素”在数组中的索引为 0 的话,则父节点和子节点的位置关系如下:
(01) 索引为i的左孩子的索引是 (2*i+1);
(02) 索引为i的左孩子的索引是 (2*i+2);
(03) 索引为i的父结点的索引是 floor((i-1)/2);

实现

以最大堆为例

template <class T>
class MaxHeap{private:T *mHeap;        // 数据int mCapacity;    // 总的容量int mSize;        // 实际容量private:// 最大堆的向下调整算法void filterdown(int start, int end);// 最大堆的向上调整算法(从start开始向上直到0,调整堆)void filterup(int start);public:MaxHeap();MaxHeap(int capacity);~MaxHeap();// 返回data在二叉堆中的索引int getIndex(T data);// 删除最大堆中的dataint remove(T data);// 将data插入到二叉堆中int insert(T data);// 打印二叉堆void print();
};

添加

假设在最大堆[90,80,70,60,40,30,20,10,50]种添加85,需要执行的步骤如下

如上图所示,当向最大堆中添加数据时:先将数据加入到最大堆的最后,然后尽可能把这个元素往上挪,直到挪不动为止!
将85添加到[90,80,70,60,40,30,20,10,50]中后,最大堆变成了[90,85,70,60,80,30,20,10,50,40]。

/** 最大堆的向上调整算法(从start开始向上直到0,调整堆)** 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。** 参数说明:*     start -- 被上调节点的起始位置(一般为数组中最后一个元素的索引)*/
template <class T>
void MaxHeap<T>::filterup(int start)
{int c = start;            // 当前节点(current)的位置int p = (c-1)/2;        // 父(parent)结点的位置 T tmp = mHeap[c];        // 当前节点(current)的大小while(c > 0){if(mHeap[p] >= tmp)break;else{mHeap[c] = mHeap[p];c = p;p = (p-1)/2;   }       }mHeap[c] = tmp;
}/* * 将data插入到二叉堆中** 返回值:*     0,表示成功*    -1,表示失败*/
template <class T>
int MaxHeap<T>::insert(T data)
{// 如果"堆"已满,则返回if(mSize == mCapacity)return -1;mHeap[mSize] = data;        // 将"数组"插在表尾filterup(mSize);    // 向上调整堆mSize++;                    // 堆的实际容量+1return 0;
}

删除

假设从最大堆[90,85,70,60,80,30,20,10,50,40]中删除90,需要执行的步骤如下:

/* * 最大堆的向下调整算法** 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。** 参数说明:*     start -- 被下调节点的起始位置(一般为0,表示从第1个开始)*     end   -- 截至范围(一般为数组中最后一个元素的索引)*/
template <class T>
void MaxHeap<T>::filterdown(int start, int end)
{int c = start;          // 当前(current)节点的位置int l = 2*c + 1;     // 左(left)孩子的位置T tmp = mHeap[c];    // 当前(current)节点的大小while(l <= end){// "l"是左孩子,"l+1"是右孩子if(l < end && mHeap[l] < mHeap[l+1])l++;        // 左右两孩子中选择较大者,即mHeap[l+1]if(tmp >= mHeap[l])break;        //调整结束else{mHeap[c] = mHeap[l];c = l;l = 2*l + 1;   }       }   mHeap[c] = tmp;
}/** 删除最大堆中的data** 返回值:*      0,成功*     -1,失败*/
template <class T>
int MaxHeap<T>::remove(T data)
{int index;// 如果"堆"已空,则返回-1if(mSize == 0)return -1;// 获取data在数组中的索引index = getIndex(data); if (index==-1)return -1;mHeap[index] = mHeap[--mSize];    // 用最后元素填补filterdown(index, mSize-1);        // 从index位置开始自上向下调整为最大堆return 0;
}

二叉堆的C++实现(完整源码)

/*** 二叉堆(最大堆)** @author skywang* @date 2014/03/07*/#include <iomanip>
#include <iostream>
using namespace std;template <class T>
class MaxHeap{private:T *mHeap;        // 数据int mCapacity;    // 总的容量int mSize;        // 实际容量private:// 最大堆的向下调整算法void filterdown(int start, int end);// 最大堆的向上调整算法(从start开始向上直到0,调整堆)void filterup(int start);public:MaxHeap();MaxHeap(int capacity);~MaxHeap();// 返回data在二叉堆中的索引int getIndex(T data);// 删除最大堆中的dataint remove(T data);// 将data插入到二叉堆中int insert(T data);// 打印二叉堆void print();
};/* * 构造函数*/
template <class T>
MaxHeap<T>::MaxHeap()
{new (this)MaxHeap(30);
}template <class T>
MaxHeap<T>::MaxHeap(int capacity)
{mSize = 0;mCapacity = capacity;mHeap = new T[mCapacity];
}
/* * 析构函数*/
template <class T>
MaxHeap<T>::~MaxHeap() 
{mSize = 0;mCapacity = 0;delete[] mHeap;
}/* * 返回data在二叉堆中的索引** 返回值:*     存在 -- 返回data在数组中的索引*     不存在 -- -1*/
template <class T>
int MaxHeap<T>::getIndex(T data)
{for(int i=0; i<mSize; i++)if (data==mHeap[i])return i;return -1;
}/* * 最大堆的向下调整算法** 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。** 参数说明:*     start -- 被下调节点的起始位置(一般为0,表示从第1个开始)*     end   -- 截至范围(一般为数组中最后一个元素的索引)*/
template <class T>
void MaxHeap<T>::filterdown(int start, int end)
{int c = start;          // 当前(current)节点的位置int l = 2*c + 1;     // 左(left)孩子的位置T tmp = mHeap[c];    // 当前(current)节点的大小while(l <= end){// "l"是左孩子,"l+1"是右孩子if(l < end && mHeap[l] < mHeap[l+1])l++;        // 左右两孩子中选择较大者,即mHeap[l+1]if(tmp >= mHeap[l])break;        //调整结束else{mHeap[c] = mHeap[l];c = l;l = 2*l + 1;   }       }   mHeap[c] = tmp;
}/** 删除最大堆中的data** 返回值:*      0,成功*     -1,失败*/
template <class T>
int MaxHeap<T>::remove(T data)
{int index;// 如果"堆"已空,则返回-1if(mSize == 0)return -1;// 获取data在数组中的索引index = getIndex(data); if (index==-1)return -1;mHeap[index] = mHeap[--mSize];    // 用最后元素填补filterdown(index, mSize-1);        // 从index位置开始自上向下调整为最大堆return 0;
}/** 最大堆的向上调整算法(从start开始向上直到0,调整堆)** 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。** 参数说明:*     start -- 被上调节点的起始位置(一般为数组中最后一个元素的索引)*/
template <class T>
void MaxHeap<T>::filterup(int start)
{int c = start;            // 当前节点(current)的位置int p = (c-1)/2;        // 父(parent)结点的位置 T tmp = mHeap[c];        // 当前节点(current)的大小while(c > 0){if(mHeap[p] >= tmp)break;else{mHeap[c] = mHeap[p];c = p;p = (p-1)/2;   }       }mHeap[c] = tmp;
}/* * 将data插入到二叉堆中** 返回值:*     0,表示成功*    -1,表示失败*/
template <class T>
int MaxHeap<T>::insert(T data)
{// 如果"堆"已满,则返回if(mSize == mCapacity)return -1;mHeap[mSize] = data;        // 将"数组"插在表尾filterup(mSize);    // 向上调整堆mSize++;                    // 堆的实际容量+1return 0;
}/* * 打印二叉堆** 返回值:*     0,表示成功*    -1,表示失败*/
template <class T>
void MaxHeap<T>::print()
{for (int i=0; i<mSize; i++)cout << mHeap[i] << " ";
}int main()
{int a[] = {10, 40, 30, 60, 90, 70, 20, 50, 80};int i, len=(sizeof(a)) / (sizeof(a[0])) ;MaxHeap<int>* tree=new MaxHeap<int>();cout << "== 依次添加: ";for(i=0; i<len; i++){cout << a[i] <<" ";tree->insert(a[i]);}cout << "\n== 最 大 堆: ";tree->print();i=85;tree->insert(i);cout << "\n== 添加元素: " << i;cout << "\n== 最 大 堆: ";tree->print();i=90;tree->remove(i);cout << "\n== 删除元素: " << i;cout << "\n== 最 大 堆: ";tree->print();cout << endl; system("pause");return 0;
}

效果如下

这里写图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/494002.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

derby数据库操作比较难理解的错误及解决方法大全

一、插入&#xff08;INSERT时报错&#xff09; 1、错误&#xff1a;java.sql.SQLIntegrityConstraintViolationException: 列“test”无法接受空值。 可能原因&#xff1a;建表时test列为not null 但插入数据时给与了null值 2、错误&#xff1a;java.sql.SQLSyntaxErrorExcept…

手术革命:这三家公司如何用AR技术辅助医疗手术

来源&#xff1a;资本实验室作为一种重要的职业&#xff0c;外科医生特别是手术医生需要具备丰富的专业知识&#xff0c;还需要掌握精准的手术操作技术&#xff0c;这都需要不断的学习与练习。受学习资料、手术练习材料等软硬件条件的制约&#xff0c;医生进行手术学习和手术操…

C# Socket初探

闲着无聊&#xff0c;写了个简单的C/S Socket程序&#xff0c;功能很简单&#xff0c;服务器在9000端口监听socket接入&#xff0c;只要有接入&#xff0c;就发送"Welcome."消息给客户端。 代码分2块&#xff0c;server端&#xff1a; class Program{static void Mai…

最新发布 | 2018年度第八届吴文俊人工智能科学技术奖获奖名单公示

来源&#xff1a;人工智能人物摘要&#xff1a;2018年度第八届吴文俊人工智能科学技术奖评审工作已经完成。根据《吴文俊人工智能科学技术奖励条例》和《吴文俊人工智能科学技术奖励实施细则》相关规定&#xff0c;经全国各地方人工智能学会、各高校及科研院所、团体会员单位和…

ReactNative环境配置

参考链接 Windows系统安装React Native环境 windows下React Native Android 环境搭建 在Windows下搭建React Native Android开发环境 碰到的问题 react-native可能在cmd窗口提示不是内部或外部命令 解决方法&#xff1a;在nodeJS command prompt下可以运行 运行时卡在最…

qt.pro转成vs程序

今天下载了一个smarthome项目&#xff0c;界面用qml实现的&#xff0c; 想用vs编译生成.exe文件&#xff0c;在wince上运行 方法一&#xff08;vs命令行&#xff09;: 一: 打开vs 2008 命令行&#xff0c;进入smarthome目录下&#xff1a; 二: qmake生成 smarthome.vcproj工程…

DNA存储:这些公司正在开启数据存储的未来

来源&#xff1a;资本实验室随着数字化时代的到来&#xff0c;可以毫不夸张地说&#xff0c;数据存储与安全正在成为整个社会正常运行的基础。同时&#xff0c;物联网、人工智能、虚拟现实、自动驾驶等新技术的应用则进一步大幅提升了数据存储要求。据IDC预测&#xff0c;到202…

React基础语法学习

React主要有如下3个特点&#xff1a; 作为UI&#xff08;Just the UI&#xff09;虚拟DOM&#xff08;Virtual DOM&#xff09;:这是亮点 是React最重要的一个特性 放进内存 最小更新的视图,差异部分更新 diff算法数据流&#xff08;Date Flow&#xff09;单向数据流 学习Re…

C#中ListT用法

所属命名空间&#xff1a;System.Collections.Generic public classList<T> :IList<T>,ICollection<T>,IEnumerable<T>,IList,ICollection,IEnumerable List<T>类是ArrayList类的泛型等效类。该类使用大小可按需动态增加的数组实现IList<…

算力超英伟达?华为推出两款“昇腾”芯片;五大AI战略正式公布

来源&#xff1a;AI科技大本营华为也像是要 All in AI 了。10 月 10 日&#xff0c;华为全联接大会 2018 上&#xff0c;华为轮值董事长徐直军带来了一系列的硬核 AI。在大会上&#xff0c;他系统公布了华为的 AI 发展战略&#xff0c;以及全栈全场景 AI 解决方案&#xff0c;其…

Qt5:渐变效果的实现

http://devbean.blog.51cto.com/448512/238168/ 转载于:https://www.cnblogs.com/wowk/p/3174602.html

React之JSX入门

React是由ReactJS与React Native组成&#xff0c;其中ReactJS是Facebook开源的一个前端框架&#xff0c;React Native 是ReactJS思想在native上的体现&#xff01; JSX并不是一门新的语言&#xff0c;仅仅是个语法糖&#xff0c;允许开发者在JavaScript中书写HTML语法。&…

英特尔人工智能副总裁:AI不是一种技能,而是一种对于工作的描述

来源&#xff1a;网络大数据人工智能领域的迅速发展&#xff0c;相关人才不能满足需求已经成为业界共识。有报道称&#xff0c;因为人工智能工程师庞大的缺口&#xff0c;一些公司为了获得人才不得不支付数百万美元的薪水。如何满足对人工智能工程师不断增长的招聘和培训的需求…

html 中表格长度固定

2010-02-03 14:25 1070人阅读 评论(0) 收藏 举报htmlclassxhtml产品bordertable<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns"http://www.w3.org/1999/xht…

React Native实例

本文主要包括以下内容 View组件的实例 Text组件实例 Navigator组件实例 TextInput组件实例 View组件的实例 效果如下 代码如下 /*** Sample React Native App* https://github.com/facebook/react-native* flow*/import React, { Component } from react; import {AppRe…

谷歌的硬件梦:Pixel手机、ChromeOS平板和Home音箱

来源&#xff1a; 网易智能&#xff08;北京时间10月9日23点&#xff09;&#xff0c;谷歌在纽约如期举行了主题为“谷歌制造”&#xff08;Made By Google&#xff09;的硬件发布会&#xff0c;推出了Pixel手机、平板 笔记本&#xff0c;以及音箱等一系列新品硬件。一个月以来…

浅用block 转

block是一门有用的大后期学问。现在我只是列出一点基本用法。 1.快速枚举&#xff08;Enumeration&#xff09; 通常是和NSArray, NSDictionary, NSSet, NSIndexSet放在一起用。 当和以上这两种东西放在一起用时&#xff0c;通常block有两种用处。&#xff08;代码为实例操作&a…

数据结构之图的实现

本文主要包括以下内容 邻接矩阵实现无向图 邻接表实现无向图 邻接矩阵实现有向图邻接表实现有向图 图的理论基础&#xff0c;请参考&#xff1a;图的理论基础 - 如果天空不死 - 博客园 邻接矩阵实现无向图 MatrixUDG是邻接矩阵对应的结构体。 mVexs用于保存顶点&#xf…

“万维网之父”发文阐述其下一个网络时代:将数据与应用分离,互联网去中心化正在路上...

来源&#xff1a;Deep Tech深科技关注“万维网之父”Tim Berners-Lee 动态的人&#xff0c;一定知道这位业内大神正在投身于下一代互联网的建设——一个去中心化的互联网。他正在领导其 MIT 团队搭建一个名为“ Solid ”&#xff08;Social Linked Data 社交关联数据&#xff0…

设置easyui input默认值

/*设置input 焦点*/ $(function () {//集体调用 $(".formTextBoxes input").each(function () {$(this).setDefauleValue();});//单个调用 $(".textkey").setDefauleValue(); })//设置input,textarea默认值 .之前写法$.fn.seDefauleValue function(){ $.f…