Skip to content

Commit 9fbed3e

Browse files
Merge branch 'master' into master
2 parents 760787b + 901f231 commit 9fbed3e

File tree

2 files changed

+242
-0
lines changed

2 files changed

+242
-0
lines changed

bit_manipulation/gray_code.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
* @brief Program to generate n-bit [Gray
3+
* code](https://en.wikipedia.org/wiki/Gray_code)
4+
*
5+
* @details
6+
* Gray code is a binary numeral system
7+
* where consecutive values differ in exactly 1 bit.
8+
* The following code offers one of many possible Gray codes
9+
* given some pre-determined number of bits.
10+
*/
11+
12+
#include <bitset> /// for gray code representation
13+
#include <cassert> /// for assert
14+
#include <iostream> /// for IO operations
15+
#include <vector> /// for vector data structure
16+
17+
/**
18+
* @namespace bit_manipulation
19+
* @brief Bit manipulation algorithms
20+
*/
21+
namespace bit_manipulation {
22+
/**
23+
* @namespace gray_code
24+
* @brief Generate n-bit Gray code
25+
*/
26+
namespace gray_code {
27+
/**
28+
* @brief The main function to generate n-bit Gray code
29+
*
30+
* @param n Number of bits
31+
* @return A vector that stores the n-bit Gray code
32+
*/
33+
std::vector<std::bitset<32>> gray_code_generation(int n) {
34+
std::vector<std::bitset<32>> gray_code = {}; // Initialise empty vector
35+
36+
// No Gray codes for non-positive values of n
37+
if (n <= 0) {
38+
return gray_code;
39+
}
40+
41+
int total_codes = 1 << n; // Number of n-bit gray codes
42+
43+
for (int i = 0; i < total_codes; i++) {
44+
int gray_num = i ^ (i >> 1); // Gray code formula
45+
gray_code.push_back(std::bitset<32>(gray_num)); // Store the value
46+
}
47+
48+
return gray_code;
49+
}
50+
} // namespace gray_code
51+
} // namespace bit_manipulation
52+
53+
/**
54+
* @brief Self-test implementation
55+
*
56+
* @returns void
57+
*/
58+
static void test() {
59+
std::vector<std::bitset<32>> gray_code_negative_1 = {};
60+
61+
std::vector<std::bitset<32>> gray_code_0 = {};
62+
63+
std::vector<std::bitset<32>> gray_code_1 = {
64+
std::bitset<32>(0), std::bitset<32>(1)
65+
};
66+
67+
std::vector<std::bitset<32>> gray_code_2 = {
68+
std::bitset<32>(0), std::bitset<32>(1), std::bitset<32>(3), std::bitset<32>(2)
69+
};
70+
71+
std::vector<std::bitset<32>> gray_code_3 = {
72+
std::bitset<32>(0), std::bitset<32>(1), std::bitset<32>(3), std::bitset<32>(2),
73+
std::bitset<32>(6), std::bitset<32>(7), std::bitset<32>(5), std::bitset<32>(4)
74+
};
75+
76+
std::vector<std::bitset<32>> gray_code_4 = {
77+
std::bitset<32>(0), std::bitset<32>(1), std::bitset<32>(3), std::bitset<32>(2),
78+
std::bitset<32>(6), std::bitset<32>(7), std::bitset<32>(5), std::bitset<32>(4),
79+
std::bitset<32>(12), std::bitset<32>(13), std::bitset<32>(15), std::bitset<32>(14),
80+
std::bitset<32>(10), std::bitset<32>(11), std::bitset<32>(9), std::bitset<32>(8)
81+
};
82+
83+
std::vector<std::bitset<32>> gray_code_5 = {
84+
std::bitset<32>(0), std::bitset<32>(1), std::bitset<32>(3), std::bitset<32>(2),
85+
std::bitset<32>(6), std::bitset<32>(7), std::bitset<32>(5), std::bitset<32>(4),
86+
std::bitset<32>(12), std::bitset<32>(13), std::bitset<32>(15), std::bitset<32>(14),
87+
std::bitset<32>(10), std::bitset<32>(11), std::bitset<32>(9), std::bitset<32>(8),
88+
std::bitset<32>(24), std::bitset<32>(25), std::bitset<32>(27), std::bitset<32>(26),
89+
std::bitset<32>(30), std::bitset<32>(31), std::bitset<32>(29), std::bitset<32>(28),
90+
std::bitset<32>(20), std::bitset<32>(21), std::bitset<32>(23), std::bitset<32>(22),
91+
std::bitset<32>(18), std::bitset<32>(19), std::bitset<32>(17), std::bitset<32>(16)
92+
};
93+
94+
// invalid values for n
95+
assert(bit_manipulation::gray_code::gray_code_generation(-1) == gray_code_negative_1);
96+
assert(bit_manipulation::gray_code::gray_code_generation(0) == gray_code_0);
97+
98+
// valid values for n
99+
assert(bit_manipulation::gray_code::gray_code_generation(1) == gray_code_1);
100+
assert(bit_manipulation::gray_code::gray_code_generation(2) == gray_code_2);
101+
assert(bit_manipulation::gray_code::gray_code_generation(3) == gray_code_3);
102+
assert(bit_manipulation::gray_code::gray_code_generation(4) == gray_code_4);
103+
assert(bit_manipulation::gray_code::gray_code_generation(5) == gray_code_5);
104+
}
105+
106+
/**
107+
* @brief Main function
108+
* @returns 0 on exit
109+
*/
110+
int main() {
111+
test(); //Run self-test implementation
112+
return 0;
113+
}

greedy_algorithms/gale_shapley.cpp

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/**
2+
* @file
3+
* @brief [Gale Shapley Algorithm](https://en.wikipedia.org/wiki/Gale%E2%80%93Shapley_algorithm)
4+
* @details
5+
* This implementation utilizes the Gale-Shapley algorithm to find stable matches.
6+
*
7+
* **Gale Shapley Algorithm** aims to find a stable matching between two equally sized
8+
* sets of elements given an ordinal preference for each element. The algorithm was
9+
* introduced by David Gale and Lloyd Shapley in 1962.
10+
*
11+
* Reference:
12+
* [Wikipedia](https://en.wikipedia.org/wiki/Gale%E2%80%93Shapley_algorithm)
13+
* [Wikipedia](https://en.wikipedia.org/wiki/Stable_matching_problem)
14+
*
15+
* @author [B Karthik](https://github.com/BKarthik7)
16+
*/
17+
18+
#include <iostream> /// for std::u32int_t
19+
#include <vector> /// for std::vector
20+
#include <algorithm> /// for std::find
21+
#include <cassert> /// for assert
22+
23+
/**
24+
* @namespace
25+
* @brief Greedy Algorithms
26+
*/
27+
namespace greedy_algorithms {
28+
/**
29+
* @namespace
30+
* @brief Functions for the Gale-Shapley Algorithm
31+
*/
32+
namespace stable_matching {
33+
/**
34+
* @brief The main function that finds the stable matching between two sets of elements
35+
* using the Gale-Shapley Algorithm.
36+
* @note This doesn't work on negative preferences. the preferences should be continuous integers starting from
37+
* 0 to number of preferences - 1.
38+
* @param primary_preferences the preferences of the primary set should be a 2D vector
39+
* @param secondary_preferences the preferences of the secondary set should be a 2D vector
40+
* @returns matches the stable matching between the two sets
41+
*/
42+
std::vector<std::uint32_t> gale_shapley(const std::vector<std::vector<std::uint32_t>>& secondary_preferences, const std::vector<std::vector<std::uint32_t>>& primary_preferences) {
43+
std::uint32_t num_elements = secondary_preferences.size();
44+
std::vector<std::uint32_t> matches(num_elements, -1);
45+
std::vector<bool> is_free_primary(num_elements, true);
46+
std::vector<std::uint32_t> proposal_index(num_elements, 0); // Tracks the next secondary to propose for each primary
47+
48+
while (true) {
49+
int free_primary_index = -1;
50+
51+
// Find the next free primary
52+
for (std::uint32_t i = 0; i < num_elements; i++) {
53+
if (is_free_primary[i]) {
54+
free_primary_index = i;
55+
break;
56+
}
57+
}
58+
59+
// If no free primary is found, break the loop
60+
if (free_primary_index == -1) break;
61+
62+
// Get the next secondary to propose
63+
std::uint32_t secondary_to_propose = primary_preferences[free_primary_index][proposal_index[free_primary_index]];
64+
proposal_index[free_primary_index]++;
65+
66+
// Get the current match of the secondary
67+
std::uint32_t current_match = matches[secondary_to_propose];
68+
69+
// If the secondary is free, match them
70+
if (current_match == -1) {
71+
matches[secondary_to_propose] = free_primary_index;
72+
is_free_primary[free_primary_index] = false;
73+
} else {
74+
// Determine if the current match should be replaced
75+
auto new_proposer_rank = std::find(secondary_preferences[secondary_to_propose].begin(),
76+
secondary_preferences[secondary_to_propose].end(),
77+
free_primary_index);
78+
auto current_match_rank = std::find(secondary_preferences[secondary_to_propose].begin(),
79+
secondary_preferences[secondary_to_propose].end(),
80+
current_match);
81+
82+
// If the new proposer is preferred over the current match
83+
if (new_proposer_rank < current_match_rank) {
84+
matches[secondary_to_propose] = free_primary_index;
85+
is_free_primary[free_primary_index] = false;
86+
is_free_primary[current_match] = true; // Current match is now free
87+
}
88+
}
89+
}
90+
91+
return matches;
92+
}
93+
} // namespace stable_matching
94+
} // namespace greedy_algorithms
95+
96+
/**
97+
* @brief Self-test implementations
98+
* @returns void
99+
*/
100+
static void tests() {
101+
// Test Case 1
102+
std::vector<std::vector<std::uint32_t>> primary_preferences = {{0, 1, 2, 3}, {2, 1, 3, 0}, {1, 2, 0, 3}, {3, 0, 1, 2}};
103+
std::vector<std::vector<std::uint32_t>> secondary_preferences = {{1, 0, 2, 3}, {3, 0, 1, 2}, {0, 2, 1, 3}, {1, 2, 0, 3}};
104+
assert(greedy_algorithms::stable_matching::gale_shapley(secondary_preferences, primary_preferences) == std::vector<std::uint32_t>({0, 2, 1, 3}));
105+
106+
// Test Case 2
107+
primary_preferences = {{0, 2, 1, 3}, {2, 3, 0, 1}, {3, 1, 2, 0}, {2, 1, 0, 3}};
108+
secondary_preferences = {{1, 0, 2, 3}, {3, 0, 1, 2}, {0, 2, 1, 3}, {1, 2, 0, 3}};
109+
assert(greedy_algorithms::stable_matching::gale_shapley(secondary_preferences, primary_preferences) == std::vector<std::uint32_t>({0, 3, 1, 2}));
110+
111+
// Test Case 3
112+
primary_preferences = {{0, 1, 2}, {2, 1, 0}, {1, 2, 0}};
113+
secondary_preferences = {{1, 0, 2}, {2, 0, 1}, {0, 2, 1}};
114+
assert(greedy_algorithms::stable_matching::gale_shapley(secondary_preferences, primary_preferences) == std::vector<std::uint32_t>({0, 2, 1}));
115+
116+
// Test Case 4
117+
primary_preferences = {};
118+
secondary_preferences = {};
119+
assert(greedy_algorithms::stable_matching::gale_shapley(secondary_preferences, primary_preferences) == std::vector<std::uint32_t>({}));
120+
}
121+
122+
/**
123+
* @brief Main function
124+
* @returns 0 on exit
125+
*/
126+
int main() {
127+
tests(); // Run self-test implementations
128+
return 0;
129+
}

0 commit comments

Comments
 (0)