データ構造とアルゴリズム17.並べ替えアルゴリズム

まず、交換注文

1.バブルソート

        バブルソートアルゴリズムは、すべてのソートアルゴリズムの中で最も単純で最も基本的なものです。バブルソートアルゴリズムのアイデアは、ソートを交換し、隣接するデータの交換を通じてソートの目的を達成することです。

        平均速度はO(n2)、最悪の場合の速度はO(n2)です。

        バブルソートアルゴリズムは、複数の比較と交換によるソートを実装します。ソートプロセスは次のとおりです。

        (1)配列内のデータごとに、隣接する2つの要素のサイズを順番に比較します。

        (2)前のデータが後者のデータよりも大きい場合は、2つのデータを交換します。多重比較と並べ替えの最初のラウンドの後、最小のデータを並べ替えることができます。

        (3)同じ方法で残りのデータを1つずつ比較し、最後に配列のデータを小さいものから大きいものの順に並べます。

public static <T extends Comparable<T>> T[] bubble_sort(T[] array) {
    for (int i = 1, size = array.length; i < size; ++i) {
        boolean swapped = false;
        for (int j = 0; j < size - i; ++j) {
            //判断大小
            if (greater(array[j], array[j + 1])) {
                //交换位置
                swap(array, j, j + 1);
                swapped = true;
            }
        }
        if (!swapped) {
            break;
        }
    }
    return array;
}

2.クイックソート

        クイックソートアルゴリズムはバブルソートアルゴリズムに似ており、交換ソートの考え方に基づいています。クイックソートアルゴリズムはバブルソートアルゴリズムを改善し、実行効率を高めます。クイックソートは分割統治アルゴリズムです。要素を軸として選択し、選択した軸の周りに指定された配列を分割します。さまざまな方法で軸を選択するquickSortにはさまざまなバージョンがあります。 

        平均速度はO(nlogn)、最悪の場合の速度はO(n2)です。

        クイックソートアルゴリズムは、複数の比較と交換によるソートを実装します。ソートプロセスは次のとおりです。

        (1)まず境界値を設定し、この境界値で配列を左右に分割します。

        (2)カットオフ値以上のデータを配列の右側に配置し、カットオフ値未満のデータを配列の左側に配置します。このとき、左側の各要素はカットオフ値以下であり、右側の各要素はカットオフ値以上です。

        (3)これにより、左右のデータを個別に並べ替えることができます。左側の配列データについては、別の境界値を取得し、データの一部を左右に分割し、小さい方の値を左側に、大きい方の値を右側に配置することができます。右側の配列データも同様に処理できます。

        (4)上記のプロセスを繰り返すと、これは再帰的定義であることがわかります。左側の部分が再帰的にソートされた後、右側の部分が再帰的にソートされます。左右のデータの並べ替えが完了すると、配列全体の並べ替えが完了します。

package com.algorithm.demo.algorithms;

import static com.algorithm.demo.algorithms.SortUtils.*;

public class QuickSortAlgorithm {

    /**
     * 对外的方法
     *
     * @param array 要排序的数组,按升序对数组进行排序
     */
    public static <T extends Comparable<T>> T[] sort(T[] array) {
        doSort(array, 0, array.length - 1);
        return array;
    }

    /**
     * 排序方法
     *
     * @param left The first index of an array
     * @param right The last index of an array
     * @param array The array to be sorted
     */
    private static <T extends Comparable<T>> void doSort(T[] array, int left, int right) {
        if (left < right) {
            int pivot = randomPartition(array, left, right);
            doSort(array, left, pivot - 1);
            doSort(array, pivot, right);
        }
    }

    /**
     * 随机化数组以避免基本有序的序列
     * Ramdomize the array to avoid the basically ordered sequences
     *
     * @param array The array to be sorted
     * @param left The first index of an array
     * @param right The last index of an array
     * @return the partition index of the array
     */
    private static <T extends Comparable<T>> int randomPartition(T[] array, int left, int right) {
        int randomIndex = left + (int) (Math.random() * (right - left + 1));
        swap(array, randomIndex, right);
        return partition(array, left, right);
    }

    /**
     * 此方法查找数组的分区索引
     * This method finds the partition index for an array
     *
     * @param array The array to be sorted
     * @param left The first index of an array
     * @param right The last index of an array Finds the partition index of an
     * array
     */
    private static <T extends Comparable<T>> int partition(T[] array, int left, int right) {
        int mid = (left + right) >>> 1;
        T pivot = array[mid];

        while (left <= right) {
            while (less(array[left], pivot)) {
                ++left;
            }
            while (less(pivot, array[right])) {
                --right;
            }
            if (left <= right) {
                swap(array, left, right);
                ++left;
                --right;
            }
        }
        return left;
    }
}

 第二に、選択ソート

        選択ソートアルゴリズムも比較的単純なソートアルゴリズムであり、その考え方はより直感的です。選択ソートアルゴリズムは、ソートの目的を達成するために、再配置する各ステップで最小値を選択します。

        平均速度O(n2)、最悪の場合の速度O(n2)

        選択ソートアルゴリズムは、選択と交換によるソートを実現し、ソートプロセスは次のとおりです。

        (1)まず、元の配列から最小の1データを選択し、1番目の位置のデータと交換します。

        (2)次に、残りのn-1データから次に小さいデータを選択し、2番目の位置のデータと交換します。

        (3)次に、最後の2つのデータが交換されるまで、上記のプロセスを繰り返します。この時点で、元の配列の小さいものから大きいものへのソートが完了します。

         挿入ソートアルゴリズムがn個のデータをソートする場合、元のデータが正しいかどうかに関係なく、n-1ステップの中間ソートを実行する必要があります。この並べ替え方法のアイデアはシンプルで直感的であり、データに特定の順序がある場合、並べ替えの効率が向上します。ただし、データが不規則な場合は、大量のデータを移動する必要があり、ソート効率は高くありません。

public static <T extends Comparable<T>> T[] selection_sort(T[] arr) {
    int n = arr.length;
    for (int i = 0; i < n - 1; i++) {
        int minIndex = i;
        for (int j = i + 1; j < n; j++) {
            if (arr[minIndex].compareTo(arr[j]) > 0) {
                minIndex = j;
            }
        }
        if (minIndex != i) {
            T temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }
    return arr;
}

3.挿入ソート

        挿入ソートアルゴリズムは、ソートされていないデータを適切な位置に1つずつ挿入することにより、ソート作業を完了します。挿入ソートアルゴリズムのアイデアは比較的単純で、多くのアプリケーションがあります。

        平均速度はO(n2)、最悪の場合の速度はO(n2)です。

        挿入ソートアルゴリズムは、比較と挿入によるソートを実装します。ソートプロセスは次のとおりです。

        (1)まず、配列の最初の2つのデータを小さいものから大きいものへと並べ替えます。

        (2)次に、3番目のデータをソートされた2つのデータと比較し、3番目のデータを適切な位置に挿入します。

        (3)次に、ソートされた最初の3つのデータに4番目のデータを挿入します。

        (4)最後のデータが適切な位置に挿入されるまで、上記のプロセスを繰り返します。最後に、元の配列の小さいものから大きいものへのソートが完了します。

/**
 * 插入排序
 * @param array
 * @return
 */
public static <T extends Comparable<T>> T[] insertion_sort(T[] array) {
    for (int i = 1; i < array.length; i++) {
        T insertValue = array[i];
        int j;
        for (j = i - 1; j >= 0 && less(insertValue, array[j]); j--) {
            array[j + 1] = array[j];
        }
        if (j != i - 1) {
            array[j + 1] = insertValue;
        }
    }
    return array;
}

第四に、マージソート

        マージソートアルゴリズムは、複数の順序付きデータテーブルを1つの順序付きデータテーブルに結合します。マージに関係する順序付きテーブルが2つしかない場合、それは双方向マージと呼ばれます。ソートされる元のシーケンスの場合、多くの場合、除算の方法による多方向マージソートに起因する可能性があります。以下では、マージソートアルゴリズムを紹介する例として、双方向マージを取り上げます。

        平均速度はO(nlogn)であり、最悪の場合の速度はO(nlogn)です。

        並べ替えられる元のデータシーケンスをマージして並べ替える基本的な考え方は、最初に、長さ1のn個の順序付けられたサブリストで構成されるn個のノードを含む並べ替えられるデータシーケンスを考慮し、それらを順番にマージして、いくつかの順序付けされたものを取得することです長さ2のサブリスト;次に、これらのサブリストをペアでマージして、長さ4のいくつかの順序付けられたサブリストを取得します...最後のサブリストの長さがnになるまで上記のプロセスを繰り返し、したがって、並べ替えプロセス。

 

class MergeSort
{

	void merge(int arr[], int l, int m, int r)
	{
		// Find sizes of two subarrays to be merged
		int n1 = m - l + 1;
		int n2 = r - m;

		/* Create temp arrays */
		int L[] = new int[n1];
		int R[] = new int[n2];

		/*Copy data to temp arrays*/
		for (int i = 0; i < n1; ++i)
			L[i] = arr[l + i];
		for (int j = 0; j < n2; ++j)
			R[j] = arr[m + 1 + j];

		/* Merge the temp arrays */

		// Initial indexes of first and second subarrays
		int i = 0, j = 0;

		// Initial index of merged subarray array
		int k = l;
		while (i < n1 && j < n2) {
			if (L[i] <= R[j]) {
				arr[k] = L[i];
				i++;
			}
			else {
				arr[k] = R[j];
				j++;
			}
			k++;
		}

		/* Copy remaining elements of L[] if any */
		while (i < n1) {
			arr[k] = L[i];
			i++;
			k++;
		}

		/* Copy remaining elements of R[] if any */
		while (j < n2) {
			arr[k] = R[j];
			j++;
			k++;
		}
	}

	// Main function that sorts arr[l..r] using
	// merge()
	void sort(int arr[], int l, int r)
	{
		if (l < r) {
			// Find the middle point
			int m =l+ (r-l)/2;

			// Sort first and second halves
			sort(arr, l, m);
			sort(arr, m + 1, r);

			// Merge the sorted halves
			merge(arr, l, m, r);
		}
	}

	/* A utility function to print array of size n */
	static void printArray(int arr[])
	{
		int n = arr.length;
		for (int i = 0; i < n; ++i)
			System.out.print(arr[i] + " ");
		System.out.println();
	}

	// Driver code
	public static void main(String args[])
	{
		int arr[] = { 12, 11, 13, 5, 6, 7 };

		System.out.println("Given Array");
		printArray(arr);

		MergeSort ob = new MergeSort();
		ob.sort(arr, 0, arr.length - 1);

		System.out.println("\nSorted array");
		printArray(arr);
	}
}
/* This code is contributed by Rajat Mishra */

 5.シェルソート

        厳密に言えば、シェルソートアルゴリズムは挿入ソートのアイデアに基づいています。これはヒルソートまたはシュリンクインクリメンタルソートとしても知られています。シェルソートアルゴリズムのソートプロセスは次のとおりです。

        (1)n個の要素を持つ配列をn / 2の数列に分割し、1番目のデータとn / 2+1番目のデータはペアになります...

        (2)ループは、各シーケンスペアを順番に作成します。

        (3)次に、n / 4シーケンスに変更し、再度ソートします。

        (4)上記のプロセスを継続的に繰り返し、シーケンスが減少して最終的に1つになると、ソート全体が完了します。

        平均速度はO(n3 / 2)であり、最悪の場合の速度はO(n2)です。

class ShellSort
{
    //打印
    static void printArray(int arr[])
    {
        int n = arr.length;
        for (int i=0; i<n; ++i)
            System.out.print(arr[i] + " ");
        System.out.println();
    }
    
    //排序方法
    int sort(int arr[])
    {
        int n = arr.length;
 
        // 从大差距开始,然后缩小差距
        for (int gap = n/2; gap > 0; gap /= 2)
        {
            
            for (int i = gap; i < n; i += 1)
            {
                int temp = arr[i];
                int j;
                for (j = i; j >= gap && arr[j - gap] > temp; j -= gap)
                    arr[j] = arr[j - gap];
 
                arr[j] = temp;
            }
        }
        return 0;
    }
 

    public static void main(String args[])
    {
        int arr[] = {12, 34, 54, 2, 3};
        System.out.println("Array before sorting");
        printArray(arr);
 
        ShellSort ob = new ShellSort();
        ob.sort(arr);
 
        System.out.println("Array after sorting");
        printArray(arr);
    }
}

6.バケットソート

        バケットソートは、要素をバケットと呼ばれるグループに分割するソートアルゴリズムです。バケットソートの要素は、最初にバケットと呼ばれるグループに均一に分割され、次に他の並べ替えアルゴリズムによって並べ替えられます。その後、要素はソートされた方法で収集されます。

        バケットソートを実行する基本的なプロセスは次のとおりです。

        まず、範囲を固定数のバケットに分割します。
        次に、各要素を対応するバケットにスローします。
        その後、並べ替えアルゴリズムを適用して、各バケットを個別に並べ替えます。
        最後に、ソートされたすべてのバケットを結合します。

        バケットソートの最良および平均的なケースの複雑さはO(n + k)であり、バケットソートの最悪のケースの複雑さはO(n 2)です。

import java.util.*;
import java.util.Collections;

class BucketSort {

	// Function to sort arr[] of size n
	// using bucket sort
	static void bucketSort(float arr[], int n)
	{
		if (n <= 0)
			return;

		// 1) Create n empty buckets
		@SuppressWarnings("unchecked")
		Vector<Float>[] buckets = new Vector[n];

		for (int i = 0; i < n; i++) {
			buckets[i] = new Vector<Float>();
		}

		// 2) Put array elements in different buckets
		for (int i = 0; i < n; i++) {
			float idx = arr[i] * n;
			buckets[(int)idx].add(arr[i]);
		}

		// 3) Sort individual buckets
		for (int i = 0; i < n; i++) {
			Collections.sort(buckets[i]);
		}

		// 4) Concatenate all buckets into arr[]
		int index = 0;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < buckets[i].size(); j++) {
				arr[index++] = buckets[i].get(j);
			}
		}
	}

	// Driver code
	public static void main(String args[])
	{
		float arr[] = { (float)0.897, (float)0.565,
						(float)0.656, (float)0.1234,
						(float)0.665, (float)0.3434 };

		int n = arr.length;
		bucketSort(arr, n);

		System.out.println("Sorted array is ");
		for (float el : arr) {
			System.out.print(el + " ");
		}
	}
}

7つの多方向マージソート

        一部の大きなファイルの場合、コンピュータのメモリが限られているため、並べ替えのためにそれらをメモリに直接読み取ることができないことがよくあります。このとき、多方向マージソート方式を使用して、ファイルをいくつかの小さな部分に分割し、メモリに読み込んでから、別々に読み取って並べ替えることができます。複数の処理を行った後、大きなファイルの並べ替えを完了することができます。

おすすめ

転載: blog.csdn.net/bashendixie5/article/details/123283951