-
Notifications
You must be signed in to change notification settings - Fork 0
/
random_walk_hidden_graph.cpp
125 lines (117 loc) · 3.9 KB
/
random_walk_hidden_graph.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <iostream>
#include <string>
#include <cstdlib>
#include <random>
#include <cassert>
using namespace std;
#ifdef DEBUG
#define PRINT_NODE(v, p, l, r) \
cout << "DEBUG: node = " << v \
<< " parent = " << p \
<< " left child = " << l \
<< " right child = " << r << endl
#define PRINT(expr) \
cout << "DEBUG: " << #expr << " = " << expr << endl
#else
#define PRINT_NODE(v, p, l, r) (void)0
#define PRINT(expr) (void)0
#endif
template <class Generator>
inline
size_t random_choose(Generator& random, size_t x, size_t y)
{
auto r = random();
return (r % 2 == 0) ? x : y;
}
template <class Generator>
inline
size_t random_choose(Generator& random, size_t x, size_t y, size_t z)
{
auto r = random();
switch (r % 3) {
case 0:
return x;
case 1:
return y;
default:
return z;
}
}
template <class Generator>
void random_walk(Generator& random, int level)
{
assert(level >= 1);
size_t const one = 1; // be care of the range overflow
size_t const n = 2 * ((one << (level + 1)) - 1);
size_t const dest = n - 1;
size_t const left_start = (one << level) - 1;
size_t const right_start = (one << (level + 1)) - 1;
size_t const leaves = (one << level);
size_t const left_end = left_start + leaves - 1;
size_t const right_end = right_start + leaves - 1;
PRINT(n);
PRINT(dest);
PRINT(leaves);
PRINT(left_start);
PRINT(left_end);
PRINT(right_start);
PRINT(right_end);
size_t steps = 0;
size_t current = 0;
while (current != dest) {
// PRINT(steps);
// PRINT(current);
size_t next;
if (current == 0) { // the start vertex
next = random_choose(random, 1, 2);
} else if (current < left_start) { // the middle vertex in the left tree
size_t const parent = (current - 1) / 2;
size_t const left_child = 2 * current + 1;
size_t const right_child = left_child + 1;
next = random_choose(random, parent, left_child, right_child);
// PRINT_NODE(current, parent, left_child, right_child);
} else if (current > right_start) { // the middle vertex in the right tree
size_t const parent = dest - (dest - current - 1) / 2;
size_t const left_child = 2 * current - dest - 2;
size_t const right_child = left_child + 1;
next = random_choose(random, parent, left_child, right_child);
// PRINT_NODE(current, parent, left_child, right_child);
} else if ((current >= left_start) && (current <= left_end)) { // the left leaves
size_t const parent = (current - 1) / 2;
size_t const left_child = right_start + (current - left_start);
size_t const right_child = right_start + (current - left_start + 1) % leaves;
next = random_choose(random, parent, left_child, right_child);
// PRINT_NODE(current, parent, left_child, right_child);
} else { // the right leaves
assert((current >= right_start) && (current <= right_end));
size_t const parent = dest - (dest - current - 1) / 2;
size_t const left_child = left_start + (current - right_start - 1 + leaves) % leaves;
size_t const right_child = left_start + (current - right_start);
next = random_choose(random, parent, left_child, right_child);
// PRINT_NODE(current, parent, left_child, right_child);
}
// PRINT(next);
++steps;
current = next;
}
cout << "Level of binary trees: " << level << endl;
cout << "Total number of nodes: " << n << endl;
cout << "Total number of steps: " << steps << endl;
}
int main(int argc, char* argv[])
{
if (argc < 2) {
cerr << "Usage: " << argv[0] << " level" << endl;
return -1;
}
int level = atoi(argv[1]);
if (level < 1) {
cerr << "The level must be greater than 1." << endl;
return -1;
}
random_device rd;
seed_seq seeds{rd(), rd(), rd(), rd(), rd(), rd()};
mt19937 random(seeds);
random_walk(random, level);
return 0;
}