Skip to content

Gale-Shapley Algorithm and Tests #5494

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@
* [ActivitySelection](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/ActivitySelection.java)
* [CoinChange](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java)
* [FractionalKnapsack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/FractionalKnapsack.java)
* [GaleShapley](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/GaleShapley.java)
* [JobSequencing](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/JobSequencing.java)
* [MinimizingLateness](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/MinimizingLateness.java)
* io
Expand Down Expand Up @@ -749,6 +750,7 @@
* [ActivitySelectionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/ActivitySelectionTest.java)
* [CoinChangeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java)
* [FractionalKnapsackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/FractionalKnapsackTest.java)
* [GaleShapleyTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/GaleShapleyTest.java)
* [JobSequencingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/JobSequencingTest.java)
* [MinimizingLatenessTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/MinimizingLatenessTest.java)
* io
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.thealgorithms.greedyalgorithms;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

/**
* Implementation of the Gale-Shapley Algorithm for Stable Matching.
* Problem link: https://en.wikipedia.org/wiki/Stable_marriage_problem
*/
public final class GaleShapley {

private GaleShapley() {
}

/**
* Function to find stable matches between men and women.
*
* @param womenPrefs A map containing women's preferences where each key is a woman and the value is an array of men in order of preference.
* @param menPrefs A map containing men's preferences where each key is a man and the value is an array of women in order of preference.
* @return A map containing stable matches where the key is a woman and the value is her matched man.
*/
public static Map<String, String> stableMatch(Map<String, LinkedList<String>> womenPrefs, Map<String, LinkedList<String>> menPrefs) {
// Initialize all men as free
Map<String, String> engagements = new HashMap<>();
LinkedList<String> freeMen = new LinkedList<>(menPrefs.keySet());

// While there are free men
while (!freeMen.isEmpty()) {
String man = freeMen.poll(); // Get the first free man
LinkedList<String> manPref = menPrefs.get(man); // Get the preferences of the man

// Check if manPref is null or empty
if (manPref == null || manPref.isEmpty()) {
continue; // Skip if no preferences
}

// Propose to the first woman in the man's preference list
String woman = manPref.poll();
String fiance = engagements.get(woman);

// If the woman is not engaged, engage her with the current man
if (fiance == null) {
engagements.put(woman, man);
} else {
// If the woman prefers the current man over her current fiance
LinkedList<String> womanPrefList = womenPrefs.get(woman);

// Check if womanPrefList is null
if (womanPrefList == null) {
continue; // Skip if no preferences for the woman
}

if (womanPrefList.indexOf(man) < womanPrefList.indexOf(fiance)) {
engagements.put(woman, man);
freeMen.add(fiance); // Previous fiance becomes free
} else {
// Woman rejects the new proposal, the man remains free
freeMen.add(man);
}
}
}
return engagements; // Return the stable matches
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.thealgorithms.greedyalgorithms;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;

public class GaleShapleyTest {

@Test
public void testStableMatch() {
Map<String, LinkedList<String>> womenPrefs = new HashMap<>();
womenPrefs.put("A", new LinkedList<>(List.of("X", "Y", "Z")));
womenPrefs.put("B", new LinkedList<>(List.of("Y", "X", "Z")));
womenPrefs.put("C", new LinkedList<>(List.of("X", "Y", "Z")));

Map<String, LinkedList<String>> menPrefs = new HashMap<>();
menPrefs.put("X", new LinkedList<>(List.of("A", "B", "C")));
menPrefs.put("Y", new LinkedList<>(List.of("B", "A", "C")));
menPrefs.put("Z", new LinkedList<>(List.of("A", "B", "C")));

Map<String, String> result = GaleShapley.stableMatch(womenPrefs, menPrefs);

Map<String, String> expected = new HashMap<>();
expected.put("A", "X");
expected.put("B", "Y");
expected.put("C", "Z");

assertEquals(expected, result);
}

@Test
public void testSinglePair() {
Map<String, LinkedList<String>> womenPrefs = new HashMap<>();
womenPrefs.put("A", new LinkedList<>(List.of("X")));

Map<String, LinkedList<String>> menPrefs = new HashMap<>();
menPrefs.put("X", new LinkedList<>(List.of("A")));

Map<String, String> result = GaleShapley.stableMatch(womenPrefs, menPrefs);

Map<String, String> expected = new HashMap<>();
expected.put("A", "X");

assertEquals(expected, result);
}

@Test
public void testEqualPreferences() {
Map<String, LinkedList<String>> womenPrefs = new HashMap<>();
womenPrefs.put("A", new LinkedList<>(List.of("X", "Y", "Z")));
womenPrefs.put("B", new LinkedList<>(List.of("X", "Y", "Z")));
womenPrefs.put("C", new LinkedList<>(List.of("X", "Y", "Z")));

Map<String, LinkedList<String>> menPrefs = new HashMap<>();
menPrefs.put("X", new LinkedList<>(List.of("A", "B", "C")));
menPrefs.put("Y", new LinkedList<>(List.of("A", "B", "C")));
menPrefs.put("Z", new LinkedList<>(List.of("A", "B", "C")));

Map<String, String> result = GaleShapley.stableMatch(womenPrefs, menPrefs);

Map<String, String> expected = new HashMap<>();
expected.put("A", "X");
expected.put("B", "Y");
expected.put("C", "Z");

assertEquals(expected, result);
}
}