Javaで学ぶアルゴリズム -選択ソート

# 選択ソート

> 選択ソート（英: selection sort）は、ソートのアルゴリズムの一つ。 配列から最小値を探し、配列の先頭要素と入れ替えていくことで並べ替える。

https://ja.wikipedia.org/wiki/%E9%81%B8%E6%8A%9E%E3%82%BD%E3%83%BC%E3%83%88

# 実行環境

- JUnit 5
- Java 8

# テストコード

```java:
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class SelectionSortTest {

	@DisplayName("配列を渡すとソートされた配列が返ること")
	@Test
	void testStraightExchange() {
		int[] array = { 5, 12, 7, 0, 1, 14, 6, 9, 8, 3, 2, 11, 4, 13, 10 };
		int[] expected = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };

		int[] actual = SelectionSort.selectionSort(array);
		assertThat(actual, is(expected));
	}

	@DisplayName("要素が1つしかない配列を渡すと要素が1つしかない配列が返ること")
	@Test
	void testStraightExchangeOneElement() {
		int[] array = { 5 };
		int[] expected = { 5 };

		int[] actual = SelectionSort.selectionSort(array);
		assertThat(actual, is(expected));
	}

	@DisplayName("空の配列を渡すと空の配列が返ること")
	@Test
	void testStraightExchangeEmpty() {
		int[] array = {};
		int[] expected = {};

		int[] actual = SelectionSort.selectionSort(array);
		assertThat(actual, is(expected));
	}

	@DisplayName("すでに昇順でソートされた配列を渡すとソートされた配列が返ること")
	@Test
	void testStraightExchangeAlreadySorted() {
		int[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
		int[] expected = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };

		int[] actual = SelectionSort.selectionSort(array);
		assertThat(actual, is(expected));
	}

	@DisplayName("要素が重複した配列を渡すとソートされた配列が返ること")
	@Test
	void testStraightExchangeDuplicateElement() {
		int[] array = { 5, 3, 5, 2, 1, 5, 3, 2, 5, 3, 5 };
		int[] expected = { 1, 2, 2, 3, 3, 3, 5, 5, 5, 5, 5 };

		int[] actual = SelectionSort.selectionSort(array);
		assertThat(actual, is(expected));
	}
}
```

# 単純選択ソートアルゴリズム

```java:
public class SelectionSort {

	/**
	 * 選択ソート
	 * 配列の中から最小値を見つけて先頭に持ってくる、を繰り返す
	 * @param array
	 * @return sortedArray
	 */
	public static int[] selectionSort(int[] array) {
		int[] sortedArray = array.clone();
		for (int i = 0; i < sortedArray.length; i++) {
			int min = i;
			for (int j = i + 1; j < sortedArray.length; j++) {
				if (sortedArray[j] < sortedArray[min]) {
					min = j;
				}
			}
			int tmp = sortedArray[i];
			sortedArray[i] = sortedArray[min];
			sortedArray[min] = tmp;
		}
		return sortedArray;
	}
}
```

# 選択ソートは安定ではない

安定ではないとはつまり、ソートの前後で「同一のキーを持つ要素の順番が維持されない」ということです。

```java:SelectionSort.java（選択ソートが安定ではないことを示すプログラム）
public class SelectionSort {

	public static void main(String[] args) {
		Element[] array = {
				new Element(1, "0"),
				new Element(1, "1"),
				new Element(1, "2"),
				new Element(2, "3"),
				new Element(1, "4"),
				new Element(1, "5"),
				new Element(1, "6"),
				new Element(1, "7"),
				new Element(2, "8"),
				new Element(1, "9")
		};

		printArray("Before Sorting:", array);
		selectionSort(array);
		printArray("After Sorting:", array);
	}

	/**
	 * 選択ソート
	 * 配列の中から最小値を見つけて先頭に持ってくる、を繰り返す
	 * @param array
	 */
	public static void selectionSort(Element[] array) {
		for (int i = 0; i < array.length; i++) {
			int min = i;
			for (int j = i + 1; j < array.length; j++) {
				if (array[j].key < array[min].key) {
					min = j;
				}
			}
			Element tmp = array[i];
			array[i] = array[min];
			array[min] = tmp;
		}
	}

	private static void printArray(String message, Element[] array) {
		StringBuilder keys = new StringBuilder();
		StringBuilder values = new StringBuilder();

		for (Element e : array) {
			keys.append("[").append(e.key).append("]");
			values.append("[").append(e.value).append("]");
		}

		System.out.println(message);
		System.out.println("-------------------------------");
		System.out.println(keys);
		System.out.println(values);
		System.out.println("-------------------------------\n");
	}
}
```

```java:Element.java
class Element {

	int key;
	String value;

	Element(int key, String value) {
		this.key = key;
		this.value = value;
	}
}
```

ソート前後をキャプチャしているのが以下の出力なのですが、キーが2の要素に着目すると、valueの順番が入れ替わっちゃってます！

```terminal:実行結果
Before Sorting:
-------------------------------
[1][1][1][2][1][1][1][1][2][1]
[0][1][2][3][4][5][6][7][8][9]
-------------------------------

After Sorting:
-------------------------------
[1][1][1][1][1][1][1][1][2][2]
[0][1][2][4][5][6][7][9][8][3]
-------------------------------
```