堆(插入,删除)
2016-05-08 23:01
411 查看
首先呢,先来了解一个何为堆?
堆数据结构是一种数组对象,它可被视为一棵完全二叉树结构。
堆结构的二叉树存储是:
最大堆:每个父节点的都大于孩子节点
最小堆:每个父节点的都小于孩子节点
最大堆:a[] = {19,17,18,14,16,13,15,12,10,11}
最小堆:a[] = {10,11,13,12,16,18,15,17,14,19}
代码实现最大堆:
若要实现最小堆,可将上述代码中(1)(2)(3)处的大于改为小于即可。
但是这样使得代码冗余,不容易维护。
那么如何用一个来实现即可建最大堆也可建最小堆呢?我们之前见的仿函数就用上场喽!
回顾一下什么是仿函数?
仿函数的机制就是通过对()进行重载。
堆数据结构是一种数组对象,它可被视为一棵完全二叉树结构。
堆结构的二叉树存储是:
最大堆:每个父节点的都大于孩子节点
最小堆:每个父节点的都小于孩子节点
最大堆:a[] = {19,17,18,14,16,13,15,12,10,11}
最小堆:a[] = {10,11,13,12,16,18,15,17,14,19}
代码实现最大堆:
#pragma once #include <iostream> #include <assert.h> #include <vector> using namespace std; template <class T> class Heap { public: Heap() //无参构造函数 {} Heap(T* a,size_t size) { for(size_t i=0;i<size;++i) { _a.push_back(a[i]); } //建堆 for(int i=(_a.size()-2)/2;i>=0;--i) { _ApDown(i); } } void Push(const T& x)//插入元素 { _a.push_back(x);//在堆尾插入元素 _ApHeapUp(_a.size()-1); //向上调整 } void Pop()//删除(删除优先级高) { swap(_a[0],_a[_a.size()-1]);//交换堆的第一个元素和最后一个元素 _a.pop_back();//删除最后一个元素 _ApDown(0);//向下调整 } size_t Size()//堆的大小 { return _a.size(); } bool Empty()//堆是否为空 { return _a.empty(); } public: void _ApDown(size_t parent) { size_t child = parent*2+1; while(child < _a.size()) { //找到左右孩子中较大的 if((child+1) < _a.size() && _a[child+1] > _a[child]) { ++child; } //比较较大孩子与父亲 if(_a[child] > _a[parent]) //(2) { swap(_a[child],_a[parent]); parent = child; child = parent*2+1; } else { break; } } } void _ApHeapUp(size_t child) { size_t parent = (child-1)/2; while(child > 0) { if(_a[child] > _a[parent])//比较孩子与父亲 (3) { swap(_a[child],_a[parent]); child = parent; parent = (child-1)/2; } else { break; } } } protected: vector<T> _a; };
若要实现最小堆,可将上述代码中(1)(2)(3)处的大于改为小于即可。
但是这样使得代码冗余,不容易维护。
那么如何用一个来实现即可建最大堆也可建最小堆呢?我们之前见的仿函数就用上场喽!
回顾一下什么是仿函数?
仿函数的机制就是通过对()进行重载。
template <class T> struct Less //小于 { bool operator()(const T& l,const T& r) { return l < r; } }; template <class T> struct Greater //大于 { bool operator()(const T& l,const T& r) { return l > r; } }; template <class T,class Comper = Greater<T> >//默认建大堆 class Heap { public: Heap() //无参构造函数 {} Heap(T* a,size_t size) { for(size_t i=0;i<size;++i) { _a.push_back(a[i]); } //建堆 for(int i=(_a.size()-2)/2;i>=0;--i) { _ApDown(i); } } void Push(const T& x)//插入元素 { _a.push_back(x);//在堆尾插入元素 _ApHeapUp(_a.size()-1); //向上调整 } void Pop()//删除(删除优先级高) { swap(_a[0],_a[_a.size()-1]);//交换堆的第一个元素和最后一个元素 _a.pop_back();//删除最后一个元素 _ApDown(0);//向下调整 } size_t Size()//堆的大小 { return _a.size(); } bool Empty()//堆是否为空 { return _a.empty(); } public: void _ApDown(size_t parent) { size_t child = parent*2+1; while(child < _a.size()) { Comper com; //找到左右孩子中较大的 if((child+1) < _a.size() && com(_a[child+1],_a[child])) { ++child; } //比较较大孩子与父亲 if(com(_a[child],_a[parent])) { swap(_a[child],_a[parent]); parent = child; child = parent*2+1; } else { break; } } } void _ApHeapUp(size_t child) { size_t parent = (child-1)/2; Comper com; while(child > 0) { if(com(_a[child],_a[parent]))//比较孩子与父亲 { swap(_a[child],_a[parent]); child = parent; parent = (child-1)/2; } else { break; } } } protected: vector<T> _a; };测试函数:
void Test1() { int a[] = {10,16,18,12,11,13,15,17,14,19}; //Heap<int> hp(a,sizeof(a)/sizeof(a[0])); //默认建大堆 Heap<int,Less<int> > hp1(a,sizeof(a)/sizeof(a[0])); //建小堆 }
相关文章推荐
- 一看就懂:图解C#中的值类型、引用类型、栈、堆、ref、out
- 浅析栈区和堆区内存分配的区别
- PHP SPL标准库之数据结构堆(SplHeap)简单使用实例
- 浅谈C#中堆和栈的区别(附上图解)
- C语言之栈和堆(Stack && Heap)的优缺点及其使用区别
- Java中堆和栈的区别详解
- 详解Java的堆内存与栈内存的存储机制
- java中堆和栈的区别分析
- C++中静态存储区与栈以及堆的区别详解
- 大话JMM
- [数据结构]堆
- java 虚拟机--新生代与老年代GC
- java堆内存与栈内存
- 堆和栈的区别
- 转贴一份挺好的堆和栈区别的资料
- C语言之内存分配
- 初学算法-基于最小堆的优先级队列C++实现
- Head First C学习日志 第六章用堆进行动态存储
- 关于java内存使用的相关问题(寄存器、栈、堆、静态存储、常理存储、非RAM存储)
- 关于栈、堆、静态变量区的访问效率