堆实现及堆的基本接口
2018-03-16 09:18
106 查看
堆的实质是一个完全二叉树并具有以下属性:每一个子树的父节点都大于或等于左右孩子节点,这种堆称为大堆;每一个子树的父节点都小于或等于左右孩子节点,这种堆称为小堆。
由于堆的父节点和子节点之间有清楚地表示方法,所以堆可以不采用链式存储,这时堆是用顺序结构进行存储的,用STL中的vector存储数据。
设父节点的编号是m,则左孩子节点的编号是m*2+1,右孩子节点的编号是m*2+2;
设子节点的编号是i,则父节点的编号是(i-1)/2 .
为了实现大堆和小堆,必须依赖于两个算法:向上调整算法,向下调整算法
首先定义仿函数,用仿函数实现两个节点数值的比较。
向上调整算法:
当一个已经调整好的堆,在堆尾又插入了一个数之后,这时堆的顺序被打乱,利用向上调整算法以新插入的节点和父节点为一条路径进行向上调整。
向下调整算法:
向下调整算法采用子树的思想,将每一个节点看作一个子树进行向下调整。
具体思路是:先找出最后一个叶子节点的父节点,在子树中选出大的或小的子树和父节点进行比较,如果父节点小于或大于选出的子节点就将父节点和子节点进行交换,然后在判断子节点有没有子树再进行调整;当这个子树调整完之后,父节点进行减减再去调整下一个子树。
堆的构造函数:
vector中扩容函数reserve和resize的区别:
resize():重新申请并改变当前vector对象的有效空间大小,并进行初始化;
reserve():重新申请并改变当前vector对象的总空间(_capacity)大小。
堆的插入:
堆的删除:
思路:要删除堆顶元素,直接删的话效率低,所以将堆顶元素和堆底元素进行交换,将堆底元素进行pop_back操作,再对堆内剩下的节点从父节点进行向下调整。
取堆顶元素:
由于堆的父节点和子节点之间有清楚地表示方法,所以堆可以不采用链式存储,这时堆是用顺序结构进行存储的,用STL中的vector存储数据。
设父节点的编号是m,则左孩子节点的编号是m*2+1,右孩子节点的编号是m*2+2;
设子节点的编号是i,则父节点的编号是(i-1)/2 .
为了实现大堆和小堆,必须依赖于两个算法:向上调整算法,向下调整算法
首先定义仿函数,用仿函数实现两个节点数值的比较。
template <class T> struct Less { bool operator()(const T& l, const T& r) { return l < r; } }; template<class T> struct Greator { bool operator()(const T& l, const T& r) { return l>r; } };
向上调整算法:
当一个已经调整好的堆,在堆尾又插入了一个数之后,这时堆的顺序被打乱,利用向上调整算法以新插入的节点和父节点为一条路径进行向上调整。
void AdjustUp(int child) { Compare ref; int parent = (child - 1) / 2; while (child > 0) { if (ref( _a[parent],_a[child])) { //顺着父节点和插入节点的路径向上调整 swap(_a[child], _a[parent]); child = parent; parent = (child - 1) / 2; } else { break; } } }
向下调整算法:
向下调整算法采用子树的思想,将每一个节点看作一个子树进行向下调整。
具体思路是:先找出最后一个叶子节点的父节点,在子树中选出大的或小的子树和父节点进行比较,如果父节点小于或大于选出的子节点就将父节点和子节点进行交换,然后在判断子节点有没有子树再进行调整;当这个子树调整完之后,父节点进行减减再去调整下一个子树。
void AdjustDown(int parent) { Compare ptr; int child = parent * 2 + 1; while (child <(int) _a.size()) { if (child + 1 < (int)_a.size() && ptr(_a[child], _a[child+1])) { ++child; } if (ptr(_a[parent], _a[child])) { //交换并判断有没有子树 swap(_a[child], _a[parent]); parent = child; child = parent * 2 + 1; } else { break; } } }
堆的构造函数:
vector中扩容函数reserve和resize的区别:
resize():重新申请并改变当前vector对象的有效空间大小,并进行初始化;
reserve():重新申请并改变当前vector对象的总空间(_capacity)大小。
template<class T,class Compare> class Heap { public: //这里堆的默认构造函数和有参数的构造函数都需要写 //因为没有缺省构造函数的类成员变量需要在初始化列表初始化 Heap() {} Heap(T* a, size_t size) { //对vector进行容量扩充 _a.reserve(size); //将数组中的元素压入vector中 for (int i = 0; i < (int)size; ++i) { _a.push_back(a[i]); } //建堆 //(_a.size-2)/2代表第一个叶子节点的父亲节点 for (int i = (_a.size() - 2) / 2; i >= 0; --i) { //向下调整算法 AdjustDown(i); } }
堆的插入:
void Push(const T& x) { _a.push_back(x); AdjustUp(_a.size() - 1); }
堆的删除:
思路:要删除堆顶元素,直接删的话效率低,所以将堆顶元素和堆底元素进行交换,将堆底元素进行pop_back操作,再对堆内剩下的节点从父节点进行向下调整。
void Pop() { assert(!_a.empty()); swap(_a[0], _a[_a.size() - 1]); _a.pop_back(); AdjustDown(0); }
取堆顶元素:
const T& Top() { if (_a.size() == 0) { return NULL; } return _a[0]; }
相关文章推荐
- JEE数据库基本操作Basedao层通用接口的实现
- java接口基本概念及实现
- 35. OP-TEE中基本算法接口调用实现
- 地磅称量系统之(53)在封装对象的类库中实现包括IDataErrorInfo接口提供的所有方法和并且扩展对异常具有添加和删除功能的基本业务对象基类
- RecyclerView的基本用法 (一个控件实现ListView, GridView等效果)+接口回调点击事件
- 医保接口实现的基本流程
- Dao接口实现基本的数据库操作。增删改查
- 利用C++实现双链表基本接口示例代码
- 集合框架_用户登录注册案例详细分析和分包的实现、用户基本描述类和用户操作接口的实现、用户操作类的具体实现、用户测试类的实现、加入猜数字小游戏
- MyBatis 增、删、改、查的基本实现---面向接口
- C++实现双链表基本接口
- 夺命雷公狗---微信开发53----网页授权(oauth2.0)获取用户基本信息接口(3)实现世界留言版
- JAVA 线程的两种基本实现方法(继承Thread类和实现Runnable接口)
- 基于hibernate的基本dao接口与实现 及 sql模糊查询特殊字符处理 及 struts 特殊字符在界面正常回显
- 基本数据结构-队列的实现及其运用
- 通用权限实现标准52个接口参考
- 基本A*算法python实现
- 关于接口的基本知识01
- 实验一:线性表的基本操作实现及其应用
- Java容器学习笔记(二) Set接口及其实现类的相关知识总结