Skip to content

Commit f6e63ab

Browse files
committed
Suggested changes
1 parent 5ec6fb0 commit f6e63ab

File tree

1 file changed

+75
-64
lines changed

1 file changed

+75
-64
lines changed

src/greedy/stable_matching.rs

Lines changed: 75 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,95 @@
11
use std::collections::{HashMap, VecDeque};
22

3-
pub fn stable_matching(
4-
men_preferences: &HashMap<String, Vec<String>>,
5-
women_preferences: &HashMap<String, Vec<String>>,
6-
) -> HashMap<String, String> {
7-
let (mut free_men, mut current_partner, mut man_engaged, mut next_proposal) =
8-
initialize_data_structures(men_preferences, women_preferences);
9-
10-
while let Some(man) = free_men.pop_front() {
11-
handle_proposal(
12-
&man,
13-
&mut free_men,
14-
&mut current_partner,
15-
&mut man_engaged,
16-
&mut next_proposal,
17-
men_preferences,
18-
women_preferences,
19-
);
20-
}
21-
22-
extract_stable_matches(man_engaged)
23-
}
24-
25-
fn initialize_data_structures(
26-
men_preferences: &HashMap<String, Vec<String>>,
27-
women_preferences: &HashMap<String, Vec<String>>,
28-
) -> (
29-
VecDeque<String>,
30-
HashMap<String, Option<String>>,
31-
HashMap<String, Option<String>>,
32-
HashMap<String, usize>,
33-
) {
34-
let mut free_men: VecDeque<String> = VecDeque::new();
35-
let mut current_partner: HashMap<String, Option<String>> = HashMap::new();
36-
let mut man_engaged: HashMap<String, Option<String>> = HashMap::new();
37-
let mut next_proposal: HashMap<String, usize> = HashMap::new();
3+
fn initialize_men(men_preferences: &HashMap<String, Vec<String>>) -> (VecDeque<String>, HashMap<String, usize>) {
4+
let mut free_men = VecDeque::new();
5+
let mut next_proposal = HashMap::new();
386

397
for man in men_preferences.keys() {
408
free_men.push_back(man.clone());
419
next_proposal.insert(man.clone(), 0);
4210
}
4311

12+
(free_men, next_proposal)
13+
}
14+
15+
fn initialize_women(women_preferences: &HashMap<String, Vec<String>>) -> HashMap<String, Option<String>> {
16+
let mut current_partner = HashMap::new();
4417
for woman in women_preferences.keys() {
4518
current_partner.insert(woman.clone(), None);
4619
}
20+
current_partner
21+
}
4722

48-
(free_men, current_partner, man_engaged, next_proposal)
23+
fn precompute_woman_ranks(women_preferences: &HashMap<String, Vec<String>>) -> HashMap<String, HashMap<String, usize>> {
24+
let mut woman_ranks = HashMap::new();
25+
for (woman, preferences) in women_preferences {
26+
let mut rank_map = HashMap::new();
27+
for (rank, man) in preferences.iter().enumerate() {
28+
rank_map.insert(man.clone(), rank);
29+
}
30+
woman_ranks.insert(woman.clone(), rank_map);
31+
}
32+
woman_ranks
4933
}
5034

51-
fn handle_proposal(
35+
fn process_proposal(
5236
man: &str,
5337
free_men: &mut VecDeque<String>,
5438
current_partner: &mut HashMap<String, Option<String>>,
5539
man_engaged: &mut HashMap<String, Option<String>>,
5640
next_proposal: &mut HashMap<String, usize>,
5741
men_preferences: &HashMap<String, Vec<String>>,
58-
women_preferences: &HashMap<String, Vec<String>>,
42+
woman_ranks: &HashMap<String, HashMap<String, usize>>,
5943
) {
6044
let man_pref_list = &men_preferences[man];
61-
let next_woman_idx = *next_proposal.get(man).unwrap();
45+
let next_woman_idx = next_proposal[man];
6246
let woman = &man_pref_list[next_woman_idx];
6347

48+
// Update man's next proposal index
6449
next_proposal.insert(man.to_string(), next_woman_idx + 1);
6550

6651
if let Some(current_man) = current_partner[woman].clone() {
67-
if woman_prefers_new_man(woman, man, &current_man, women_preferences) {
68-
update_engagement(
69-
man,
70-
woman,
71-
current_man,
72-
free_men,
73-
current_partner,
74-
man_engaged,
75-
);
52+
// Woman is currently engaged, check if she prefers the new man
53+
if woman_prefers_new_man(woman, man, &current_man, woman_ranks) {
54+
engage_man(man, woman, free_men, current_partner, man_engaged, Some(current_man));
7655
} else {
56+
// Woman rejects the proposal, so the man remains free
7757
free_men.push_back(man.to_string());
7858
}
7959
} else {
80-
man_engaged.insert(man.to_string(), Some(woman.to_string()));
81-
current_partner.insert(woman.to_string(), Some(man.to_string()));
60+
// Woman is not engaged, so engage her with this man
61+
engage_man(man, woman, free_men, current_partner, man_engaged, None);
8262
}
8363
}
8464

85-
fn update_engagement(
65+
fn woman_prefers_new_man(
66+
woman: &str,
67+
man1: &str,
68+
man2: &str,
69+
woman_ranks: &HashMap<String, HashMap<String, usize>>,
70+
) -> bool {
71+
let ranks = &woman_ranks[woman];
72+
ranks[man1] < ranks[man2]
73+
}
74+
75+
fn engage_man(
8676
man: &str,
8777
woman: &str,
88-
current_man: String,
8978
free_men: &mut VecDeque<String>,
9079
current_partner: &mut HashMap<String, Option<String>>,
9180
man_engaged: &mut HashMap<String, Option<String>>,
81+
current_man: Option<String>,
9282
) {
9383
man_engaged.insert(man.to_string(), Some(woman.to_string()));
9484
current_partner.insert(woman.to_string(), Some(man.to_string()));
95-
free_men.push_back(current_man);
96-
}
9785

98-
fn woman_prefers_new_man(
99-
woman: &str,
100-
man1: &str,
101-
man2: &str,
102-
preferences: &HashMap<String, Vec<String>>,
103-
) -> bool {
104-
let woman_preferences = &preferences[woman];
105-
woman_preferences.iter().position(|m| m == man1).unwrap()
106-
< woman_preferences.iter().position(|m| m == man2).unwrap()
86+
if let Some(current_man) = current_man {
87+
// The current man is now free
88+
free_men.push_back(current_man);
89+
}
10790
}
10891

109-
fn extract_stable_matches(man_engaged: HashMap<String, Option<String>>) -> HashMap<String, String> {
92+
fn finalize_matches(man_engaged: HashMap<String, Option<String>>) -> HashMap<String, String> {
11093
let mut stable_matches = HashMap::new();
11194
for (man, woman_option) in man_engaged {
11295
if let Some(woman) = woman_option {
@@ -115,6 +98,34 @@ fn extract_stable_matches(man_engaged: HashMap<String, Option<String>>) -> HashM
11598
}
11699
stable_matches
117100
}
101+
102+
pub fn stable_matching(
103+
men_preferences: &HashMap<String, Vec<String>>,
104+
women_preferences: &HashMap<String, Vec<String>>,
105+
) -> HashMap<String, String> {
106+
let (mut free_men, mut next_proposal) = initialize_men(men_preferences);
107+
let mut current_partner = initialize_women(women_preferences);
108+
let mut man_engaged = HashMap::new();
109+
110+
let woman_ranks = precompute_woman_ranks(women_preferences);
111+
112+
while let Some(man) = free_men.pop_front() {
113+
process_proposal(
114+
&man,
115+
&mut free_men,
116+
&mut current_partner,
117+
&mut man_engaged,
118+
&mut next_proposal,
119+
men_preferences,
120+
&woman_ranks,
121+
);
122+
}
123+
124+
finalize_matches(man_engaged)
125+
}
126+
127+
128+
118129
#[cfg(test)]
119130
mod tests {
120131
use super::*;

0 commit comments

Comments
 (0)