Skip to content

Commit 8caabf1

Browse files
committed
a better implementation of heap inspired by golang/heap
1 parent a5c5240 commit 8caabf1

File tree

11 files changed

+133
-243
lines changed

11 files changed

+133
-243
lines changed

Makefile

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ PROGRAMS = m_based_demo \
5353
random_demo \
5454
k-means_demo \
5555
kmp_demo \
56-
heap_sort_demo \
57-
kruskal_mst_demo \
5856
LRU_cache_demo \
5957
base64_demo \
6058
max_subarray_demo \
@@ -209,9 +207,6 @@ k-means_demo: $(SRCDIR)/k-means_demo.cpp
209207
kmp_demo : $(SRCDIR)/kmp_demo.cpp
210208
$(CPP) $(CFLAGS) -o $@ $^ $(INCLUDEDIR) $(LIBS)
211209

212-
heap_sort_demo: $(SRCDIR)/heap_sort_demo.cpp
213-
$(CPP) $(CFLAGS) -o $@ $^ $(INCLUDEDIR) $(LIBS)
214-
215210
kruskal_mst_demo: $(SRCDIR)/kruskal_mst_demo.cpp
216211
$(CPP) $(CFLAGS) -o $@ $^ $(INCLUDEDIR) $(LIBS)
217212

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
Radix sort
4545
Quick sort
4646
Merge sort
47-
Heap sort
4847
Double linked list
4948
Skip list
5049
Self-organized linked-list ops (move-to-front, move-ahead-one)

include/astar.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ namespace alg {
9393
// initialy containing the start node
9494
// encoding [x,y] to [x*ncol + y]
9595
// using binary heap ...
96-
m_openset.insert(0, x1*ncol+y1);
96+
m_openset.push(0, x1*ncol+y1);
9797
// record the starting point in openset_grid
9898
m_openset_grid(x1,y1) = true;
9999

@@ -109,7 +109,8 @@ namespace alg {
109109

110110
// the main A*algorithm
111111
while(!m_openset.is_empty()) {
112-
uint32_t value = m_openset.min_value();
112+
Heap<uint32_t>::elem e = m_openset.pop();
113+
uint32_t value = e.data;
113114
int cx = value/ncol;
114115
int cy = value%ncol;
115116

@@ -136,8 +137,7 @@ namespace alg {
136137
return as;
137138
}
138139

139-
// delete current positon from openset and move it into closed set.
140-
m_openset.delete_min();
140+
// move it into closed set.
141141
m_closedset(cx, cy) = true;
142142
m_openset_grid(cx, cy) = false;
143143

@@ -168,7 +168,7 @@ namespace alg {
168168
g_score(nx,ny) = tentative; // update path cost for current position
169169
f_score(nx,ny) = tentative + estimate(nx,ny,x2,y2); // record path cost to this neighbour
170170
if (!m_openset_grid(nx,ny)) { // only insert the neighbour if it hasn't been add to the openset.
171-
m_openset.insert(f_score(nx,ny), nx*ncol+ny);
171+
m_openset.push(f_score(nx,ny), nx*ncol+ny);
172172
m_openset_grid(nx,ny) = true;
173173
}
174174
}

include/dijkstra.h

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ namespace alg {
3737
class Dijkstra {
3838
public:
3939
static const int UNDEFINED = -1;
40+
static const int LARGE_NUMBER = 999999;
4041
// run dijkstra algorithm, and return the previous table
4142
static HashTable<int32_t, int32_t> * run(const Graph & g, uint32_t src_id) {
4243
// a binary heap
@@ -51,43 +52,35 @@ namespace alg {
5152
// all vertices
5253
Graph::Adjacent * a;
5354
list_for_each_entry(a, &g.list(), a_node){
54-
dist[a->v.id] = INT_MAX; // set inital distance to each vertex as INT_MAX
55+
dist[a->v.id] = LARGE_NUMBER; // set inital distance to each vertex to a large number
5556
(*previous)[a->v.id] = UNDEFINED; // clear path to UNDEFINED
5657
visited[a->v.id] = false; // all vertices are not visited
58+
Q.push(LARGE_NUMBER, a->v.id); // push all vertices to heap
5759
}
5860

5961
// source vertex, the first vertex in Heap-Q
60-
Q.insert(0, src_id);
6162
dist[src_id] = 0;
63+
// decrease-key the source vertex to 0
64+
Q.decrease_key(src_id,0);
6265

6366
while(!Q.is_empty()) { // for every un-visited vertex, try relaxing the path
64-
int32_t id = Q.min_value();
65-
Q.delete_min(); // remove u from Q
66-
if (visited[id]) { // jump visited vertex, it means a closer vertex has found
67-
// printf("visted:%d %d\n", id, dist[id]);
67+
Heap<uint32_t>::elem e = Q.pop();
68+
uint32_t id = e.data;
69+
if (visited[id]) { // ignore visited vertex
6870
continue;
6971
}
7072

7173
Graph::Adjacent * u = g[id]; // the vertex to process
7274
int dist_u = dist[id]; // current known shortest distance to u
73-
visited[id] = true; // mark the vertex as visited.
75+
visited[id] = true; // mark the vertex as visited.
7476

7577
Graph::Vertex * v;
7678
list_for_each_entry(v, &u->v_head, v_node){
7779
uint32_t alt = dist_u + v->weight;
78-
uint32_t dist_v = dist[v->id];
79-
if (alt < dist_v) {
80-
/*
81-
uint32_t tmp = dist[v->id];
82-
if (tmp != INT_MAX) {
83-
printf("old %d %d\n", v->id, tmp);
84-
printf("new %d %d\n", v->id, dist[v->id]);
85-
}
86-
*/
87-
80+
if (alt < dist[v->id]) {
8881
dist[v->id] = alt;
89-
(*previous)[v->id] = u->v.id;
90-
Q.insert(alt, v->id);
82+
(*previous)[v->id] = id;
83+
Q.decrease_key(v->id, alt); // decrease-key
9184
}
9285
}
9386
}

include/heap.h

Lines changed: 89 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
* Heap Data structure
99
*
1010
* Heaps can be used as an array. For any key at array position I,
11-
I left child is at ( 2i ), right child is at ( 2i+1 ) and parent is
12-
I at (int) (i / 2). Heap size is stored at index 0.
11+
* left child is at ( 2i ), right child is at ( 2i+1 ) and parent is
12+
* at (int) (i / 2). Heap size is stored at index 0.
1313
*
1414
* Basic operations of a heap are:
1515
*
@@ -27,80 +27,58 @@
2727
#include <stdint.h>
2828
#include <stdbool.h>
2929
#include <limits.h>
30-
#include "hash_code.h"
31-
#include "hash_table.h"
30+
#include "generic.h"
3231

3332
namespace alg {
3433
/**
3534
* define binary heap structure.
3635
*/
3736
template<typename T>
3837
class Heap {
39-
private:
38+
public:
4039
/**
4140
* define key-value pair of heap struct.
4241
*/
43-
struct KV {
42+
struct elem {
4443
public:
45-
int32_t key;
46-
T value;
44+
int key;
45+
T data;
4746
};
48-
int32_t m_size; // current heap size.
49-
int32_t m_max; // max heap size.
50-
KV * m_kvs; // key value pairs.
51-
52-
HashTable<T, int32_t> * m_idx; // key -> idx
5347

48+
private:
49+
int m_size; // current heap size.
50+
int m_max; // max heap size.
51+
elem * m_heap; // key value pairs.
5452
public:
5553
Heap(int max) {
5654
m_size = 0;
5755
m_max = max+1;
58-
m_kvs = new KV[m_max];
59-
m_kvs[0].key = INT_MIN;
60-
m_idx = new HashTable<T, int32_t>(m_max);
56+
m_heap = new elem[m_max];
6157
};
6258

6359
~Heap() {
64-
delete [] m_kvs;
65-
delete m_idx;
60+
delete [] m_heap;
6661
};
6762

6863
private:
6964
Heap(const Heap &);
7065
Heap& operator=(const Heap&);
7166

7267
public:
73-
74-
inline int min_key() const { return m_kvs[1].key; };
75-
inline const T & min_value() const { return m_kvs[1].value; };
76-
7768
// for loop through the kvs
78-
inline uint32_t count() const { return m_size; };
79-
inline const T & operator[] (uint32_t idx) const { return m_kvs[idx+1].value; };
69+
inline int count() const { return m_size; };
8070

8171
/**
8272
* insert a 'key'->'value' pair into the heap.
8373
*/
84-
void insert(int key, const T & value) {
74+
void push(int key, const T & data) {
8575
// heap full, just return;
8676
if(m_size == m_max) return;
87-
77+
// put in the back, and try move upward the heap
78+
m_heap[m_size].key = key;
79+
m_heap[m_size].data= data;
80+
up(m_size);
8881
m_size++;
89-
m_kvs[m_size].key = key;
90-
m_kvs[m_size].value = value;
91-
(*m_idx)[value] = m_size;
92-
93-
// Adjust its position
94-
int now = m_size;
95-
while(m_kvs[now/2].key > key) {
96-
m_kvs[now] = m_kvs[now/2];
97-
(*m_idx)[m_kvs[now/2].value] = now;
98-
now /= 2;
99-
}
100-
101-
m_kvs[now].key = key;
102-
m_kvs[now].value = value;
103-
(*m_idx)[value] = now;
10482
}
10583

10684
/**
@@ -113,84 +91,94 @@ namespace alg {
11391
*/
11492
inline void clear() { m_size = 0; }
11593

94+
bool contains(const T & data) {
95+
for(int i=1;i<=m_size;i++) {
96+
if(m_heap[i].data== data) return true;
97+
}
98+
return false;
99+
}
100+
116101
/**
117-
* contains test
102+
* pop the min element
118103
*/
119-
bool contains(const T & value) {
120-
for(int32_t i=1;i<=m_size;i++) {
121-
if(m_kvs[i].value == value) return true;
122-
}
104+
elem pop() {
105+
int n = m_size-1;
106+
swap(m_heap[0],m_heap[n]);
107+
down(0, n);
108+
m_size--;
109+
return m_heap[m_size];
110+
}
123111

112+
/**
113+
* remove the given data
114+
*/
115+
bool remove(T data) {
116+
for (int i=0;i<m_size;i++) { // loop finding
117+
if (m_heap[i].data == data) { // found
118+
int n = m_size-1;
119+
if (n != i) {
120+
swap(m_heap[i], m_heap[n]);
121+
down(i, m_size);
122+
up(i);
123+
}
124+
m_size--;
125+
return true;
126+
}
127+
}
124128
return false;
125129
}
126130

127131
/**
128-
* delete the min element --> heap top.
132+
* decrease key
133+
* simpliy implemented as remove then push
129134
*/
130-
void delete_min() {
131-
// heap[1] is the minimum key. So we remove heap[1].
132-
// Size of the heap is decreased. Now heap[1] has to be filled.
133-
// We put the last key in its place and see if it fits. If it
134-
// does not fit, take minimum key among both its children and
135-
// replaces parent with it. Again See if the last key fits
136-
//in that place.
137-
int32_t lastKey;
138-
T lastValue;
139-
int32_t child,now;
140-
141-
// empty heap, just return
142-
if (m_size == 0) return;
143-
144-
lastKey = m_kvs[m_size].key;
145-
lastValue = m_kvs[m_size].value;
146-
m_size--;
135+
void decrease_key(T data, int newkey) {
136+
if (remove(data)) {
137+
push(newkey, data);
138+
}
139+
}
147140

148-
// now refers to the index at which we are now
149-
for(now = 1; now*2 <= m_size ;now = child) {
150-
// child is the index of the key which is minimum among
151-
// both the children, Indexes of children are i*2 and i*2 + 1
152-
child = now*2;
153-
// child!=heapSize beacuse heap[heapSize+1] does not exist,
154-
// which means it has only one child
155-
if(child != m_size && m_kvs[child+1].key < m_kvs[child].key) {
156-
child++; // choose the minium one.
141+
void up(int j) {
142+
for (;;) {
143+
int i = (j-1)/2; // parent
144+
if (i==j || !less(j,i)) { // j not smaller than i
145+
break;
157146
}
158-
// To check if the last key fits or not it suffices to check
159-
// if the last key is less than the minimum key among both the children
160-
if(lastKey > m_kvs[child].key) {
161-
m_kvs[now] = m_kvs[child];
162-
(*m_idx)[m_kvs[now].value] = now; // record index
147+
swap(m_heap[i], m_heap[j]);
148+
j=i;
149+
}
150+
}
151+
152+
void down(int i, int n) {
153+
for(;;) {
154+
int j1 = 2*i+1; // left child
155+
if (j1 >=n || j1 < 0) { // j1 < 0 after int overflow
156+
break;
157+
}
158+
159+
int j = j1;
160+
int j2 = j1+1; // left child
161+
if (j2 < n && !less(j1,j2)) {
162+
j = j2; // choose the minium one.
163163
}
164-
else { // It fits there
164+
165+
if (!less(j,i)) {
165166
break;
166167
}
168+
swap(m_heap[i], m_heap[j]);
169+
i=j;
167170
}
168-
169-
m_kvs[now].key = lastKey;
170-
m_kvs[now].value= lastValue;
171-
(*m_idx)[lastValue] = now; // record index
172171
}
173172

174-
/**
175-
* so called DECREASE KEY operation.
176-
* step 1. find the value
177-
* step 2. decrease the key to the newkey
178-
*/
179-
void decrease_key(T value, int32_t newkey) {
180-
int32_t index = (*m_idx)[value];
181-
if (index > m_size || index == 0) return; // value not found
182-
if (newkey >= m_kvs[index].key) return; // violate DECREASE meanning.
183-
T oldvalue = m_kvs[index].value;
184-
185-
int now = index;
186-
while(m_kvs[now/2].key > newkey) {
187-
m_kvs[now] = m_kvs[now/2];
188-
(*m_idx)[m_kvs[now].value] = now; // record index
189-
now /= 2;
173+
void print_heap() {
174+
for (int i=0;i<m_size;i++) {
175+
printf("key:%d value:%d ", m_heap[i].key, m_heap[i].data);
190176
}
177+
printf("\n");
178+
}
191179

192-
m_kvs[now].key = newkey;
193-
m_kvs[now].value = oldvalue;
180+
bool less(int i, int j) {
181+
return m_heap[i].key < m_heap[j].key;
194182
}
195183
};
196184
}

0 commit comments

Comments
 (0)