6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaAdvent Calendar 2024

Day 5

Javaで学ぶアルゴリズム -シャッフル(Fisher-Yates)

Posted at

Fisher-Yatesのシャッフルアルゴリズム

  • リストや配列の要素をランダムに並べ替えるための効率的で均等なシャッフルアルゴリズム
  • リストの各要素を順番に見て、その要素とそれ以降にあるランダムに選んだ要素を入れ替える
  • 各要素が均等な確率で任意の位置に配置され、完全にランダムなシャッフルを実現する

ソートされた配列をランダムな順序に並べ替えるには、シャッフルアルゴリズムを使用するのが一般的です。以下に、配列をランダムに並べ替える方法を示します。これはJavaのコードで、Fisher-Yatesアルゴリズムを用いています。

実行環境

  • JUnit 5
  • Java 8

テストコード

  • 確認観点
    • サイズが同一
    • 要素が同一
    • 要素の順番が同一でない
FisherYatesShuffleTest.java
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;

public class FisherYatesShuffleTest {

	private final List<Integer> list = Arrays.asList(1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29);

	@DisplayName("サイズが同一であることを確認")
	@Test
	void testSameSize() {
		List<Integer> actual = FisherYatesShuffle.shuffle(list);
		assertThat(actual.size(), is(list.size()));
	}

	@DisplayName("要素が同一であることを確認")
	@Test
	void testContainsInAnyOrder() {
		List<Integer> actual = FisherYatesShuffle.shuffle(list);
		assertThat(actual, containsInAnyOrder(list.toArray()));
	}

	@DisplayName("要素の順番が同一でないことを確認")
	@Test
	void testDifferentOrder() {
		List<Integer> actual = FisherYatesShuffle.shuffle(list);
		assertThat(actual, not(contains(list)));
	}

	@DisplayName("要素が存在しない場合はそのまま返すことを確認")
	@Test
	void testEmptyList() {
		List<Integer> list = Arrays.asList();
		List<Integer> actual = FisherYatesShuffle.shuffle(list);
		assertThat(actual, is(list));
	}

	@DisplayName("リストがnullの場合はNPEがスローされることを確認")
	@Test
	void testThrowsNullPointerException() {
		assertThrows(NullPointerException.class, () -> {
			FisherYatesShuffle.shuffle(null);
		});
	}

シャッフルアルゴリズム(Fisher-Yates)

FisherYatesShuffle.java
import java.util.Random;

public class FisherYatesShuffle {

	public static List<Integer> shuffle(List<Integer> list) {
		Random random = new Random();
		for (int i = list.size() - 1; i > 0; i--) {
			int index = random.nextInt(i + 1);
			// リストの要素をスワップ
			Integer temp = list.get(index);
			list.set(index, list.get(i));
			list.set(i, temp);
		}
		return list;
	}
}
Collections.shuffle を使えば2行
public class FisherYatesShuffle {

	public static List<Integer> shuffle(List<Integer> list) {
		Collections.shuffle(list);
		return list;
	}
}

参考

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?