-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathrandom_generator_lib.cpp
276 lines (238 loc) · 7.34 KB
/
random_generator_lib.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#include "random_generator_lib.h"
/**
* @brief generate random integer(int)
*
* @param low, high the generated number will be in range [low, high] inclusive
* @return int
*/
int random32(int low, int high)
{
if (low > high)
throw std::invalid_argument("random32 parameters is invalid");
std::uniform_int_distribution<int> dist(low, high);
return dist(random_seed);
}
/**
* @brief generate random integer(long long)
*
* @param low, high the generated number will be in range [low, high] inclusive
* @return long long
*/
long long random64(long long low, long long high)
{
if (low > high)
throw std::invalid_argument("random64 parameters is invalid");
std::uniform_int_distribution<long long> dist(low, high);
return dist(random_seed);
}
/**
* @brief generate random number of (length) digit in O(length)
*
* @param length
* @return std::string
*/
std::string random_huge_number(int length)
{
std::string str(length, ' ');
for (int i = 0; i < length; ++i)
str[i] = '0' + random32(!i, 9);
return str;
}
/**
* @brief generate random string or lower case characters in O(length)
*
* @param length
* @return std::string
*/
std::string random_string(int length)
{
std::string str(length, ' ');
for (int i = 0; i < length; ++i)
str[i] = 'a' + random32(0, 25);
return str;
}
/**
* @brief pick random item from vector of items
*
* @tparam T the data type of vector
* @param vec the container
* @return T the data type of vector is same as the returned data type
*/
template <typename T>
T pick_random(std::vector<T> &vec)
{
if (vec.empty())
throw std::invalid_argument("can not pick from empty vector");
int index = random32(0, vec.size() - 1);
return vec[index];
}
/**
* @brief pick random item from vector of items then remove it from the vector
*
* @tparam T the data type of vector
* @param vec the container
* @return T the data type of vector is same as the returned data type
*/
template <typename T>
T pick_random_and_remove(std::vector<T> &vec)
{
if (vec.empty())
throw std::invalid_argument("can not pick from empty vector");
int index = random32(0, vec.size() - 1);
std::swap(vec[index], vec.back());
T value = vec.back();
vec.pop_back();
return value;
}
/**
* @brief generates random tree in O(number_of_nodes)
*
* @param number_of_nodes
* @param root optional paramater. if it is not given the root will be random node
* @param height optional paramater. if it is not given it will be random
* and if it was incorrect it will be set to the nearest valid height
* @return std::vector<std::pair<int, int>>. every pair represents an edge in the tree means that
* pair.first have direct edge to pair.second. the vector will have size = number of nodes - 1
*/
std::vector<std::pair<int, int>> random_tree(int number_of_nodes = -1, int root = -1, int height = -1)
{
if (!~number_of_nodes)
number_of_nodes = random32(1, 100000);
if (number_of_nodes <= 1)
return {};
// pick random root if not given or given and not valid
if (root > number_of_nodes or root < 1)
root = random32(1, number_of_nodes);
// pick random height if not given
if (!~height)
height = random32(1, number_of_nodes - 1);
// if height is too small set it to 1
if (height < 1)
height = 1;
// if height is too tall set it to max
if (height > number_of_nodes - 1)
height = number_of_nodes - 1;
std::vector<std::pair<int, int>> edges;
int depth[number_of_nodes];
std::vector<int> nodes_to_connect, disconnected_nodes(number_of_nodes);
iota(disconnected_nodes.begin(), disconnected_nodes.end(), 1);
depth[root - 1] = 0;
nodes_to_connect.emplace_back(root);
for (int h = 1; h <= height; ++h)
{
int random_disconnected_node = pick_random_and_remove(disconnected_nodes);
if (random_disconnected_node == root)
{
--h;
continue;
}
if (edges.empty())
{
depth[random_disconnected_node - 1] = 1 + depth[root - 1];
edges.push_back({root, random_disconnected_node});
}
else
{
depth[random_disconnected_node - 1] = 1 + depth[edges.back().second - 1];
edges.push_back({edges.back().second, random_disconnected_node});
}
if (depth[random_disconnected_node - 1] != height)
nodes_to_connect.emplace_back(random_disconnected_node);
}
while (!disconnected_nodes.empty())
{
int random_disconnected_node = pick_random_and_remove(disconnected_nodes);
if (random_disconnected_node == root)
continue;
int random_connected_node = pick_random(nodes_to_connect);
depth[random_disconnected_node - 1] = 1 + depth[random_connected_node - 1];
edges.push_back({random_connected_node, random_disconnected_node});
if (depth[random_disconnected_node - 1] != height)
nodes_to_connect.emplace_back(random_disconnected_node);
}
std::shuffle(edges.begin(), edges.end(), random_seed);
return edges;
}
/**
* @brief generates a random permutation in O(length)
*
* @param length
* @return std::vector<int>
*/
std::vector<int> random_permutation(int length)
{
if (length < 0)
throw std::invalid_argument("can not generate negative size for permutation");
std::vector<int> vec(length);
std::iota(vec.begin(), vec.end(), 1);
std::vector<int> randomized_vec;
while (length--)
randomized_vec.push_back(pick_random_and_remove(vec));
return randomized_vec;
}
/**
* @brief generates a random binary string in O(length)
*
* @param length
* @return std::string
*/
std::string random_binary_string(int length)
{
if (length < 0)
throw std::invalid_argument("can not generate negative size for string");
std::string str;
while (length--)
str.push_back('0' + random32(0, 1));
return str;
}
/**
* @brief return a random Boolean Value True/False in O(1)
*
* @return bool
*/
bool random_flag()
{
return random32(0, 1);
}
/**
* @brief returns a random vowel character
*
* @param isUpper optoinal(bool). In case not given or pass `false` function will return lower vowel character
* otherwise function will return upper vowel character
* @return char
*/
char random_vowel(bool isUpper=false)
{
std::vector<char> vowels{'a', 'e', 'i', 'o', 'u'};
char chosen = pick_random(vowels);
return isUpper ? toupper(chosen) : chosen;
}
/**
* @brief returns a matrix with 'row' rows and 'col' columns and the values in the matrix are in range [low, high]
*
* @param row - number of rows in the matrix
* @param col - number of columns in the matrix
* @param low - starting range
* @param high - ending range
* @return std::vector<std::vector<long long>>
*/
std::vector<std::vector<long long>> random_matrix(int row, int col, long long low, long long high)
{
if (low > high)
{
throw std::invalid_argument("range is invalid");
}
if (row == 0 || col == 0)
{
throw std::invalid_argument("row or column can't be empty");
}
std::vector<std::vector<long long>> matrix(row, std::vector<long long>(col, 0));
for (int i = 0; i < row; ++i)
{
for (int j = 0; j < col; ++j)
{
matrix[i][j] = random64(low, high);
}
}
return matrix;
}