選択ソート
アルゴリズムのアイデア
並べ替えを選択する手順:
1> まず、ソートされていないシーケンス内の最小 (最大) 要素を見つけて、それをソートされたシーケンスの先頭に格納します。
2> 引き続き、ソートされていない残りの要素から最小 (最大) の要素を検索し、それをソートされていないシーケンスの開始位置に置きます。
3> すべての要素が並べ替えられるまで 2 番目のステップを繰り返します。
アニメーション
アルゴリズムコード
public static void selectSort1(int[] a){
for (int i = 0; i < a.length; i++) {
int minIndex = i;
for (int j = i+1 ; j <a.length ; j++) {
if(a[j] <= a[minIndex]){
minIndex = j;
}
}
if(minIndex == i) continue; //说明没找到更小的
int tmp = a[minIndex];
a[minIndex] = a[i];
a[i] = tmp;
}
}
複雑さの分析
時間計算量 O(n^2) 算術シーケンス
空間の複雑さ O(1)
安定性 不安定
選択ソートの最適化
選択ソートの最適化の考え方は、一般に、1 回の走査で最大値と最小値を同時に見つけて、それらを配列の両端に配置することで、走査回数を半分に減らすことができます。初めて最大値と最小値を選択するプロセスは次のとおりです。
アルゴリズムコード
public static void selectSort2(int[] a){
int left = 0;
int right = a.length-1;
while(left<right) {
int minIndex = left;
int maxIndex = right;
for(int i = left+1;i<=right;i++) {
if(a[i] < a[minIndex]) {
minIndex = i;
}
if(a[i] > maxIndex) {
maxIndex = i;
}
}
//交换左边
int tmp1 = a[minIndex];
a[minIndex] = a[left];
a[left] = tmp1;
if(maxIndex == left) { //很重要的一点细节
maxIndex = minIndex;
}
//交换右边
int tmp2 = a[maxIndex];
a[maxIndex] = a[right];
a[right] = tmp2;
left++;
right--;
}
}
時間計算量テスト
次に、大量のデータを使ってテストしてみましょう。
int[] a = new int[10_0000]; //100,000 データのテスト
1. orderArray 関数は、基本的な順序付けされたシーケンス、つまり小さいものから大きいものへと配置されたシーケンスを生成するために実装されています。
public static void orderArray(int[] a) {
for (int i = 0; i < a.length; i++) {
a[i] = i;
}
}
2. notOrderArray 関数は、逆のシーケンス、つまり最大から最小への順序を生成します。
public static void notOrderArray(int[] a) {
for (int i = 0; i < a.length; i++) {
a[i] = a.length-i;
}
}
3.randomArray関数は、順序のないランダムな配列を生成します。
public static void randomArray(int[] a) {
Random random = new Random();
for (int i = 0; i < a.length; i++) {
a[i] = random.nextInt(10_0000);
}
}
4. testInsertSort 関数は、 System.currentTimeMillis() の戻り値をミリ秒単位でテストします。
public static void testInsertSort(int[] a){
int[] tmpArray = Arrays.copyOf(a,a.length);
long startTime = System.currentTimeMillis(); //注意用long接收
shellSort(tmpArray);
long endTime = System.currentTimeMillis(); //返回单位是毫秒
System.out.println("选择排序耗时:"+(endTime-startTime));
}
5. main関数呼び出しの実行
public static void main(String[] args) {
int[] a = new int[10_0000];
//有序
System.out.println("基本有序数列");
orderArray(a);
testInsertSort(a);
//倒序
System.out.println("逆序数列");
notOrderArray(a);
testInsertSort(a);
//随机乱序
System.out.println("无序数列");
randomArray(a);
testInsertSort(a);
}
試験結果
結果から、データ量が多い場合には最適化されたアルゴリズムの方が遅くなりますが、データ量が少ない場合にはこのソートアルゴリズムの方が適していると考えられます。
テスト用に 250 個のデータを入れました。
結果は、消費時間が依然として短縮されていることを示しています。
完全なコード
import java.util.Random;
public class sort {
public static void main(String[] args) {
int[] a = new int[10_0000];
//有序
System.out.println("基本有序数列");
orderArray(a);
testInsertSort(a);
//无序
System.out.println("逆序数列");
notOrderArray(a);
testInsertSort(a);
//乱序
System.out.println("无序数列");
randomArray(a);
testInsertSort(a);
}
public static void selectSort(int[] a){
for (int i = 0; i < a.length; i++) {
int minIndex = i;
for (int j = i+1 ; j <a.length ; j++) {
if(a[j] <= a[minIndex]){
minIndex = j;
}
}
if(minIndex == i) continue; //说明没找到更小的
int tmp = a[minIndex];
a[minIndex] = a[i];
a[i] = tmp;
}
}
//生成有序数组 从小到大排列
public static void orderArray(int[] a) {
for (int i = 0; i < a.length; i++) {
a[i] = i;
}
}
//n无序 其实就是从大到小排列
public static void notOrderArray(int[] a) {
for (int i = 0; i < a.length; i++) {
a[i] = a.length-i;
}
}
//乱序 随机生成序列
public static void randomArray(int[] a) {
Random random = new Random();
for (int i = 0; i < a.length; i++) {
a[i] = random.nextInt(10_0000);
}
}
//大量数据测试
public static void testInsertSort(int[] a){
int[] tmpArray = Arrays.copyOf(a,a.length);
long startTime = System.currentTimeMillis(); //注意用long接收
selectSort(tmpArray);
long endTime = System.currentTimeMillis();
System.out.println("选择排序耗时:"+(endTime-startTime));
}
}