堆及其应用
来源:互联网 发布:大学生网络创业问题 编辑:程序博客网 时间:2024/05/27 20:50
应用1.优先级队列
优先级队列 是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素。
#pragma once#include <cassert>#include <iostream>#include <cstdlib>#include "Heap.h"using namespace std;template <class T , class Compare = Greater<T>>class PriorityQueue{public: PriorityQueue(T* array, size_t size) :_h(array, size) {} void Push(const T& d) { _h.Push(d); } void Pop() { _h.Pop(); } const T& Top() { return _h.GetTop(); }protected: Heap <T, Compare> _h;};void TestPriorityQueue(){ int a[] = { 3, 8, 12, 2, 19, 11, 14, 13, 15, 10 }; PriorityQueue<int> a1(a, 10);}
应用2.n个数中找出最大的前k个数
在有大量的数据时,找出最大的前k个数。此类问题可以用堆来解决。
首先,取出n个数据中的前k个数,创建一个有k个数据的小堆。
然后,把后面的数据依次和堆顶的数据比较,找出俩个数中大的数据放在堆顶,调用向下调整算法,保证这是一个小堆。这样就可以找出最大的前k个数。
找出最小的k个数的方法也类似。
注意:找最大数时建的是小堆,找最小数时建的是大堆。
#pragma once#include <cassert>#include <iostream>#include <cstdlib>using namespace std;#define K 10#define N 10000template <class T>//将根节点向下调整void AdjustDown(T *top,int root){ assert(root < K); size_t parent = root; size_t child = parent * 2 + 1; while (child < K) { if (child + 1 < K && top[child + 1] < top[child]) { ++child; } if (top[child] < top[parent] && child < K) { swap(top[parent], top[child]); parent = child; child = parent * 2 + 1; } else { return; } }}template <class T>void GetTopK(T *arr,T *top){ assert(K < N); for (size_t i = 0; i < K; i++)//取出N个数据的前K个数 { top[i] = arr[i]; } for (int j = (K - 2) / 2; j >= 0; j--)//创建一个有K个数据的小堆 { AdjustDown(top, j); } for (size_t i = K; i < N; i++)//比较第K+1--第N个数据,找出最大的K个数 { if (arr[i] > top[0]) { swap(arr[i], top[0]); AdjustDown(top, 0); } }}template <class T>void print(T *top){ for (size_t i = 0; i < K; i++) { cout << top[i] << " "; } cout << endl;}void TestGetTopK(){ int arr[N] = { 0 }; int top[K] = { 0 }; for (size_t i = 0; i < N; i++) { arr[i] = i; } GetTopK(arr, top); print(top);}
应用3.堆排序
以升序为例,堆排序首先建一个小堆,找到最小的数据,放到最后。通过向下调整算法(此时不用管数组的最后一个元素),找到最小的数据,放到最后,这样依次操作,可把数组排序。
#pragma once#include <cassert>#include <iostream>#include <cstdlib>using namespace std;template <class T>void Adjustdown(T* arr ,size_t root,size_t size){ size_t parent = root; size_t child = parent * 2 + 1; while (parent < size) { if (arr[child] > arr[child + 1] && child + 1 < size) { ++child; } if (arr[child] < arr[parent] && child < size) { swap(arr[child], arr[parent]); parent = child; child = parent * 2 + 1; } else { break; } }}template <class T>void HeapSort(T* arr, size_t size){ assert(arr); for (int i = (size - 2) / 2; i >= 0; i--) //建小堆 { Adjustdown(arr, i, size); } size_t end = size - 1; while (end > 0) { swap(arr[0], arr[end]); Adjustdown(arr, 0, end); end--; }};template<class T>void print(T* arr,size_t size){ for (int i = 0; i < size; i++) { cout << arr[i] << " "; } cout << endl;}void TestHeapSort(){ int a[] = {7,1,0,5,8,2}; HeapSort(a, sizeof(a)/sizeof(a[0])); print(a, sizeof(a) / sizeof(a[0]));}
堆的性质:
1、可以通过一个简单的数组实现
2、支持最坏情况为O(logN)的insert和deleteMin
3、支持常量平均时间的insert操作以及常量平均最坏时间的findMin操作。
4、二叉堆是实现优先级队列的典型方法
堆所支持的基本操作:
template<typename T> class BinaryHeap { typedef HeapNode<T> Node; public: BinaryHeap(); BinaryHeap(const vector<Node> &v); void Insert(const Node& data); void DeleteMin(Node& data = Node()); //删除最小元素,可以通过参数返回最小值 void MakeHeap(); //置空堆 bool IsEmpty()const; //判断堆是不是为空 const Node& findMin()const; //查找堆中的最小元素 protected: void buildHeap(); //恢复堆的顺序 void percolate(int hole); //从hole开始下滑调整 protected: vector<Node> _Heap; //存储的堆中元素的数组 int _Size; //标记堆中元素的个数 };
一、堆的建立
堆的建立有两种方式,一种是建立一个空堆,另一种是通过复制一个记录数组并对其加以调整形成一个堆。
BinaryHeap() :_Heap(0) , _Size(0) {} BinaryHeap(const vector<Node> &v) :_Heap(v.size()+1) //为了便于计算,多开辟一个空间 , _Size(v.size()) { for (int i = 1; i <=_Size; i++) //_Heap[0]不存放 { _Heap[i] = v[i-1]; } buildHeap(); }
时间复杂度:O(N*lgN)
二、Insert操作
Insert所需要的是上滑调整,直接向_Heap中插入数据,然后通过上滑调整顺序。
void Insert(const Node& data) { _Heap.push_back(data); _Size++; int i = _Size; int parent= 0; for (; i/2>0; i /= 2) //i这点的结点要有父亲节点 { parent = i / 2; //父亲结点的位置 if (_Heap[parent] < data) //如果父亲结点比插入的值小,则有序 { break; } else //如果父亲结点比插入值大 { _Heap[i] = _Heap[parent]; } } _Heap[i] = data; }
时间复杂度:O(lgN)
三、deleteMin操作
由于最小堆的性质,根节点总是最小值,所以将数组中最后一个结点的值放到根节点的位置,然后_Size自减,再从根节点开始进行一次下滑操作恢复堆的顺序。
void DeleteMin(Node& data=Node()) //删除最小元素,可以通过参数返回最小值 { assert(_Size>0); data = findMin(); _Heap[1] = _Heap[_Size--]; int i = 0; percolate(1); //从根结点处开始下滑调整顺序 }
时间复杂度:O(lgN)
完整代码:
#pragma once #include<cassert> #include<vector> template<typename T> struct HeapNode { T _data; size_t _key; HeapNode() {} HeapNode(const T& data,size_t key) :_data(data) , _key(key) {} friend ostream& operator<<(ostream& os,const HeapNode<T>& heap) { os << heap._data; return os; } friend bool operator>(const HeapNode<T>& h1,const HeapNode<T>& h2) { if (h1._key > h2._key) return true; else return false; } friend bool operator<(const HeapNode<T>& h1, const HeapNode<T>& h2) { if (h1._key < h2._key) return true; else return false; } }; template<typename T> class BinaryHeap { typedef HeapNode<T> Node; public: BinaryHeap() :_Heap(0) , _Size(0) {} BinaryHeap(const vector<Node> &v) :_Heap(v.size()+1) //为了便于计算,多开辟一个空间 , _Size(v.size()) { for (int i = 1; i <=_Size; i++) //_Heap[0]不存放 { _Heap[i] = v[i-1]; } buildHeap(); } void Insert(const Node& data) { _Heap.push_back(data); _Size++; int i = _Size; int parent= 0; for (; i/2>0; i /= 2) //i这点的结点要有父亲节点 { parent = i / 2; //父亲结点的位置 if (_Heap[parent] < data) //如果父亲结点比插入的值小,则有序 { break; } else //如果父亲结点比插入值大 { _Heap[i] = _Heap[parent]; } } _Heap[i] = data; } void DeleteMin(Node& data=Node()) //删除最小元素,可以通过参数返回最小值 { assert(_Size>0); data = findMin(); _Heap[1] = _Heap[_Size--]; int i = 0; percolate(1); //从根结点处开始下滑调整顺序 } void MakeHeap() //置空堆 { BinaryHeap<T> tmp; swap(tmp._Heap ,_Heap); _Size = 0; } bool IsEmpty()const //判断堆是不是为空 { return _Size == 0; } const Node& findMin()const //查找堆中的最小元素 { assert(_Size>0); return _Heap[1]; } protected: void buildHeap() //恢复堆的顺序 { for (int i =_Size; i > 0; i--) { percolate(i); } } void percolate(int hole) //从hole开始下滑调整 { int child=0; Node tmp = _Heap[hole]; for (;hole*2<=_Size;hole=child) //如果有左孩子则下滑调整 { child = hole * 2; if (child !=_Size&&_Heap[child]> _Heap[child + 1]) //找出左右孩子中值最小的 child++; if (tmp < _Heap[child]) //如果tmp小于孩子的值,则调整结束 { break; } else //如果tmp大于等于孩子的值,则继续调整 { _Heap[hole] = _Heap[child]; } } _Heap[child] = tmp; } protected: vector<Node> _Heap; int _Size; };
- 堆、堆排序及其应用
- 堆及其应用
- 堆及其应用
- 堆及其应用
- 堆排序及其应用
- 堆排序算法及其应用
- 堆排序及其一个应用
- 【DS】堆操作及其应用
- 堆原理及其基本应用
- 数据结构—堆排序及其应用(优先级队列)
- 二叉堆及其在A*算法中的应用
- 堆应用
- 堆排序及其分析
- 堆、栈及其区别
- 堆排序及其源码
- 堆及其算法
- 堆排序及其分析
- 堆排序及其分析
- rex 传参
- 下拉列表ListPopupWindow
- Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock (r)
- bzoj 2095: [Poi2010]Bridges 二分答案+网络流
- 斜线/、反斜线\、双斜线//、双反斜线\\ ,区别
- 堆及其应用
- 数据流图常见错误分析
- url解码
- eclipse新建maven工程
- java中native的用法
- javaweb之监听器详解
- 【Linux】Supervisor快速使用教程
- POJ 1163 The Triangle 笔记
- 627