11use 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) ]
119130mod tests {
120131 use super :: * ;
0 commit comments