堆,与其说是一种数据结构,不如说是一种排序算法。用堆算法,可以轻松得到一组数据中最大的或最小的元素。
其结构就是完全二叉树的顺序存储方式。即在一个数组中存储一颗完全二叉树。
通常,堆分为"大根堆"和"小根堆",前者的树顶元素是数组中最大的一个,后者是最小的一个。
常用操作:
入堆:元素被加入到堆中,以小根堆为例,新元素首先被放到队列最尾端,然后何其父节点比较,如果小于其父节点,则交换两者。以此类推,一直追溯到树顶元素,或者在半途,它不再小于它的父节点。操作完成。
出堆:出堆操作,就是得到当前队列中最大或最小的元素。对于一个合法的堆结构,其首元素就是所要找的。关键是这个元素取出后,其他元素要填补其移走的空白。和入堆操作相反,出堆操作是从树顶至叶节点的操作。
将一个队列构建成堆:这个操作相对复杂一些,每次都从堆底向堆顶找到其最大或最小的元素,然后分别对起两个子节点作此操作。
1 #include "Array.h"
2 #include <utility>
3 #include <algorithm>
4 template <typename T>
5 class heap
6 {
7 public:
8 heap(){}
9
10 void push_heap(const T& data)
11 //入堆
12 {
13 if(m_array.empty())
14 {
15 m_array.push_back(data);
16 }
17 else
18 {
19 heapify(data);
20 }
21 }
22
23 T pop_heap()
24 //出堆
25 {
26 std::swap(m_array[0], m_array[m_array.size()-1]);
27 int i = 0;
28 if(m_array.size()%2 == 1 && m_array.size() > 2 && m_array[m_array.size()-2] < m_array[0])
29 {
30 std::swap(m_array[0], m_array[m_array.size()-2]);
31 }
32 while(i*2+2 < m_array.size()-1)
33 {
34 if(m_array[i*2+1] < m_array[i*2+2])
35 {
36 std::swap(m_array[i], m_array[i*2+1]);
37 i = i*2+1;
38 }
39 else if(i*2+2 < m_array.size()-1)
40 {
41 std::swap(m_array[i], m_array[i*2+2]);
42 i = i*2+2;
43 }
44
45
46 }
47
48 T tmp = m_array[m_array.size()-1];
49 m_array.remove(m_array.end()-1);
50
51 return tmp;
52 }
53
54 template <typename IT>
55 void insert(IT _First, IT _Last)
56 //将数组插入堆,并保持堆的合法性
57 {
58 for(;_First != _Last; )
59 {
60 push_heap(*_First++);
61 }
62 }
63
64 template <typename IT>
65 static void make_heap(IT _First, IT _Last)
66 //把现有队列创建为堆结构
67 {
68 size_t dist = (_Last - _First-1) /2;
69 for(int i = 0; i < dist; i ++)
70 _make_heap(_First, _Last,i);
71 }
72
73 private:
74 void heapify(const T& data)
75 {
76 size_t off = m_array.size();
77 m_array.push_back(data);
78
79 int i = (off-1)/2;
80
81 do
82 {
83 if(m_array[i] > m_array[off])
84 {
85 std::swap(m_array[i], m_array[off]);
86 }
87 else
88 {
89 break;
90 }
91 off = (off-1)/2;
92 i = (off-1)/2;
93 }while(off > 0);
94 }
95
96 template <typename IT>
97 static void _make_heap(IT _First, IT _Last, int len)
98 {
99 int n = _Last - _First;
100 int nLength = (_Last - _First)/2 -1;
101
102 if(nLength <= 1)
103 {
104 return;
105 }
106
107 if(nLength%2 == 0)
108 //当堆的长度为偶数时,即完全二叉树上的最后一个叶子节点是其父节点的左孩子,且没有兄弟节点。
109 //则对二叉树中最后一棵子树特殊处理,下面的循环中不再理会它
110 {
111 if(*(_First+nLength) > *(_First+(nLength*2+1)))
112 {
113 std::swap(*(_First+nLength), *(_First+(nLength*2+1)));
114
115 }
116 nLength --;
117 }
118
119 for(; nLength >= len; nLength --)
120 {
121 T a = *(_First+(nLength*2+1));
122 T b = *(_First+(nLength*2+2));
123 if(*(_First+nLength) < min(*(_First+(nLength*2+1)), *(_First+(nLength*2+2))))
124 {
125 continue;
126 }
127 else if(*(_First+(nLength*2+1)) < *(_First+(nLength*2+2)))
128 {
129 std::swap(*(_First+nLength), *(_First+(nLength*2+1)));
130 }
131 else
132 {
133 std::swap(*(_First+nLength), *(_First+(nLength*2+2)));
134 }
135 }
136 }
137
138 Array<T> m_array;
139 };
140
来源:https://www.cnblogs.com/yjsoft/archive/2008/10/11/1308831.html