基本的なアルゴリズムのトップ 10

1. 選択ソート

プロセスの簡単な説明:
まず、配列内の最小の要素を見つけ、次にそれを配列の最初の要素と交換します (最初の要素が最小の要素の場合は、それ自体が交換されます)。次に、残りの要素の中から最小の要素を見つけて、それを配列の 2 番目の要素と交換します。配列全体がソートされるまで続きます。このメソッドを選択ソートと呼びます

理解を容易にするために、アニメーションも用意しました。

public class SelectionSort {

    public static void main(String[] args) {
        int[] arr = {5, 3, 6, 8, 1, 7, 9, 4, 2};
        //定义内外两层循环,从最外层循环第一个值开始匹配,内层循环从外层循环加以开始向后匹配
        //如果遇到小的值就进行交换
        //外层循环到倒数第二为止,内层循环到倒数第一为止
        for (int i = 0; i < arr.length-1; i++) {
            int min = i;
            for (int j = i+1; j < arr.length; j++) {
                if(arr[i]>=arr[j]){
                    min = j;
                    int temp = arr[i];
                    arr[i] = arr[min];
                    arr[j] = temp;
                }
            }
        }
        CommonUtils.print(arr);
    }
}

プロパティ: 1. 時間計算量: O(n2) 2. 空間計算量: O(1) 3. 不安定な並べ替え 4. インプレース並べ替え

2. 挿入ソート

私たちがポーカーをするとき、どうやってカードを整理しましたか? これを行う簡単な方法は、すでに注文されている他のカードの適切な場所に各カードを 1 枚ずつ挿入することです。順序なし配列をソートする場合、要素を挿入するには、挿入する前にスペースを確保し、残りの要素をすべて右に移動する必要があります。このアルゴリズムは、挿入ソートと呼ばれます

プロセスの簡単な説明:

1. 配列の 2 番目の要素から要素を抽出します。

2. 左側の最初の要素と比較します。左側の最初の要素がそれより大きい場合は、それより大きくない要素が見つかるまで左側の 2 番目の要素との比較を続け、その後挿入します。この要素の右側にあります。

3. 引き続き 3 番目、4 番目、... n 個の要素を選択し、手順 2 を繰り返し、挿入する適切な位置を選択します。

理解を容易にするために、アニメーションも用意しました。

public class InsertionSort {
    public static void main(String[] args) {
        int[] a = { 9, 3, 1, 4, 6, 8, 7, 5, 2 };
        for (int i = 1; i < a.length; i++) {
            //内层比较是从外层的赋值为起始点
            //该值会和它前面的值比较,如果比前面的值小就交换
            for (int j = i;j>0; j--) {
                if(a[j]<a[j-1]){
                    CommonUtils.swap(a,j,j-1);
                }
            }
        }
        CommonUtils.print(a);
    }
}

3. バブルソート

1. 最初の要素と 2 番目の要素を比較し、最初の要素が 2 番目の要素より大きい場合は、それらの位置を交換します。次に、2 番目と 3 番目の要素の比較を続け、2 番目が 3 番目よりも大きい場合は、それらの位置を交換します。

隣接する要素の各ペアに対して、最初の最初のペアから最後の最後のペアまで同じことを行います。これにより、比較と交換の後、右端の要素が最大の数値になります。

右端の要素を削除し、残りの要素に対して同じことを繰り返し、並べ替えが完了するまで繰り返します。

理解を容易にするために、アニメーションも用意しました。

public class BubbleSort {
    public static void main(String[] args) {
        int[] arr = {5, 3, 6, 8, 1, 7, 9, 4, 2};
        for (int i = 0; i < arr.length; i++) {
            //内层循环像指针一样指导着程序运行
            for (int j = 0; j < arr.length-i-1; j++) {

                if(arr[j]>arr[j+1]){
                    CommonUtils.swap(arr,j,j+1);
                }
            }
        }

        CommonUtils.print(arr);
    }
}

4. ヒルソート

ヒル ソートは、挿入ソートの変形であると言えます。挿入ソートでもバブルソートでも、配列の最大値がたまたま最初の位置にある場合、それを正しい位置に移動するには n - 1 回の移動が必要です。つまり、元の配列の要素が正しい位置から遠く離れている場合、正しい位置に到達するまでに何度も隣接する要素と交換する必要があり、比較的時間がかかります。

ヒル ソートは単に挿入ソートの速度を向上させ、隣接しない要素を交換して配列の一部をソートします。

ヒル ソートの考え方は、挿入ソートの方法を採用することです。まず、配列内の任意の間隔 h の要素を並べ替えます。最初は h のサイズを h = n / 2 にすることができ、次に h = n とします。 / 4、 h = 1 のとき、つまり、この時点の配列内の任意の間隔 1 の要素が順番にあり、この時点の配列が順番になっているとします。

わかりやすいように、画像も用意しました。

public class ShellSort {
    public static void main(String[] args) {
        int[] arr = {5, 3, 6, 8, 1, 7, 9, 4, 2};
        int h = arr.length/2;
        for (int gap = h; gap > 0; gap--) {//间隔的循环
            for (int j = 0; j < arr.length-gap; j++) {
                if(arr[j]>arr[j+gap]){
                    CommonUtils.swap(arr,j,j+gap);
                }
            }

        }

        CommonUtils.print(arr);
    }
}

5. マージソート

大きな順序なし配列を順序付けするには、大きな配列を 2 つに分割し、2 つの配列を別々に並べ替えてから、2 つの配列を結合して順序付き配列にします。2 つの小さな配列がソートされるため、マージが高速になります。

配列のサイズが 1 になるまで、大きな配列を再帰的に分割します。この時点では、要素が 1 つだけなので、配列は順番に並んでいます。次に、サイズ 1 の 2 つの配列をサイズ 2 の 1 つにマージします。次に、すべての小さな配列がマージされるまで、2 つのサイズを 4 にマージします。

理解を容易にするために、アニメーションも用意しました。

public class MergeSort {

    public static void main(String[] args) {
        int[] arr = {1,4,7,8,3,6,9};
        sort(arr, 0, arr.length-1);

        CommonUtils.print(arr);
    }
    static void sort(int[] arr, int left, int right) {
        if(left==right){
            return;
        }
        int mid = left + (right-left)/2;
        sort(arr,left,mid);
        sort(arr,mid+1,right);
        merge(arr,left,mid+1,right);
    }


    //先定义合并的方法
    static void merge(int[] arr, int leftPtr, int rightPtr, int rightBound) {
        int i = leftPtr;
        int j = rightPtr;
        int mid = rightPtr -1;
        int[] temp = new int[rightBound - leftPtr + 1];
        int tempPtr = 0;

        //进行比较赋值
        while (i<=mid&&j<=rightBound){
            if(arr[i]>arr[j]){
                temp[tempPtr]=arr[j];
                j++;
                tempPtr++;
            }else {
                temp[tempPtr]=arr[i];
                i++;
                tempPtr++;
            }
        }

        //将未放入临时数组的数放入临时数组
        while(i<=mid) temp[tempPtr++] = arr[i++];
        while(j<=rightBound) temp[tempPtr++] = arr[j++];

        //数组复制
        for (int i1 = 0; i1 < temp.length; i1++) {
            arr[leftPtr+i1]=temp[i1];
        }
    }
}

6、クイックソート

配列から要素を選択し、この要素をaxis 要素と呼びます。次に、配列内の左側の axis 要素より小さいすべての要素と、axis 要素以上のすべての要素を配置します。明らかに、この時点で中心軸要素の位置は整っています。つまり、軸要素の位置を移動する必要がなくなりました。

中心軸要素から開始して、大きな配列を 2 つの小さな配列 (どちらの配列にも中心軸要素が含まれていません) に分割し、中心軸要素の左右の配列に再帰的に同じ操作を繰り返すようにします。配列のサイズは 1 で、この時点で各要素は順序付けられた位置にあります。

理解を容易にするために、アニメーションも用意しました。

public class QuickSort {

    public static void main(String[] args) {
        int[] arr = {1,5,7,6,4};
        sort(arr,0,arr.length-1);

        CommonUtils.print(arr);
    }

    static void sort(int[] arr, int leftBound, int rightBound) {
        if(leftBound>=rightBound) {
            return;
        }
        int mid = partition(arr, leftBound, rightBound);
        sort(arr,leftBound,mid-1);
        sort(arr,mid+1,rightBound);
    }

    static int partition(int[] arr, int leftBound, int rightBound) {
        int left = leftBound;
        int mid = rightBound;
        int right = rightBound-1;

        while (left<=right){
            //1、这两个指针分别寻找小于标杆和大于标杆的数,找到以后指针停止
            //2、交换两边指针停止位置的数
            //3、将标杆放到中间的位置
            while (left<=right&&arr[left]<=arr[mid]){
                left++;
            }
            while (left<=right&&arr[right]>arr[mid]){
                right--;
            }
            if(left<right){
                CommonUtils.swap(arr,left,right);
            }
        }
        //把标杆放中间
        CommonUtils.swap(arr,left,rightBound);
        return left;
    }
}

7. 数えて仕分けする

カウンティングソートは、最大値と最小値の差が大きくない場合に適したソートの一種です。

基本的な考え方は、配列要素を配列の添字として使用し、一時配列を使用して要素の出現回数をカウントすることです。たとえば、temp[i] = m とすると、要素 i が m 回現れることを示します。合計で。最後に、一時配列統計のデータが小さいものから大きいものまで集計されますが、この時点ではデータは整っています。

理解を容易にするために、アニメーションも用意しました。

public class CountSort {
    public static void main(String[] args) {

        int[] arr = {2, 4, 2, 3, 7, 1, 1, 0, 0, 5, 6, 9, 8, 5, 7, 4, 0, 9};

        int[] result = sort(arr);

        CommonUtils.print(result);

    }
    public static int[] sort(int[] arr) {
        int[] temp = new int[10];
        for (int a : arr) {
            temp[a]++;
        }

        int[] result = new int[arr.length];
        int r = 0;
        for (int i = 0; i < temp.length; i++) {

            while (temp[i]>0){
                result[r]=i;
                r++;
                temp[i]--;
            }
        }
        return result;
    }
}

8、バケットソート

バケットソートとは、最大値と最小値の間の数値を分割することです。たとえば、10個の区間に分割し、10個の区間は10個のバケットに対応します。各要素を対応する区間のバケットに入れて、それぞれをソートします。データはマージソートまたはクイックソートでソートできます。

その後、各バケット内のデータを整理し、マージして集計を行っていきます。

わかりやすいように、画像も用意しました。

public class BucketSort {

    public static void main(String[] args) {

        int[] arr = {2, 4, 2, 3, 7,0};

        int[] result = sort(arr);

        CommonUtils.print(result);

    }

    public static int[] sort(int[] arr) {
        int max = findMax(arr);
        int mini = findMini(arr);
        int group = (max-mini)/5+1;
        List<List<Integer>> totalBucket = new LinkedList<>();

        //初始化桶
        for (int i = 0; i < group; i++) {
            totalBucket.add(new LinkedList<Integer>());
        }

        for (int i = 0; i < arr.length; i++) {
            //得到所在区间
            int i1 = (arr[i] - mini) / (max - mini);
            //向所在区间添加元素
            totalBucket.get(i1).add(arr[i]);
        }

        //复制结果
        for (List<Integer> integers : totalBucket) {
            Collections.sort(integers);
        }




        //复制结果
        int[] result = new int[arr.length];
        int r = 0;
        for (int i = 0; i < totalBucket.size(); i++) {
            for (int i1 = 0; i1 < totalBucket.get(i).size(); i1++) {
                result[r]= totalBucket.get(i).get(i1);
                r++;
            }
        }
        return result;
    }

    public static int findMax(int[] arr) {
        int max = arr[0];
        for (int i : arr) {
            if(i>max){
                max = i;
            }
        }
        return max;
    }

    public static int findMini(int[] arr) {
        int mini = arr[0];
        for (int i : arr) {
            if(i<mini){
                mini = i;
            }
        }
        return mini;
    }
}

9、基数ソート

基数ソートのソートの考え方は次のとおりです。最初に 1 桁のサイズでデータをソートし、次に 10 の位のサイズで大部分をソートし、次に 100 の位のサイズでソートします。

最終的には、順序付けられた要素のセットになります。ただし、特定の桁数で並べ替える場合は、「バケット」を使用して並べ替えます。

特定の桁 (整数ではなく、単位/十の位....) の範囲は 0 ~ 9 であるため、10 個のバケットが必要です。次に、同じ値の数字を同じバケットに入れてから、その数字をバケットに入れます。バケット 0 からバケット 9 までの順に取り出され、1 トリップ後に一定の桁数に応じてソートされます。

理解を容易にするために、アニメーションも用意しました。

public class RadioSort {
    public static void main(String[] args) {
        int[] arr = {5, 3, 6, 8, 100, 7, 9, 4, 20};
        sort(arr);
        CommonUtils.print(arr);
    }

    public static int[] sort(int[] arr) {
       if(arr==null||arr.length==2) {
           return arr;
       }
       int max = findMax(arr);
       int num = 1;
       while (max/10>0){
           max= max/10;
           num++;
       }

        List<List<Integer>> totalBucket = new LinkedList<>();

        //初始化桶
        for (int i = 0; i < 10; i++) {
            totalBucket.add(new LinkedList<Integer>());
        }
        for (int i = 0; i < num; i++) {
            //放入对应的桶
            for (int j = 0; j < arr.length; j++) {
                int location = (arr[j] / (int)Math.pow(10,i)) % 10;
                totalBucket.get(location).add(arr[j]);
            }


            int k = 0;
            for (List<Integer> integers : totalBucket) {
                for (Integer integer : integers) {
                    arr[k++]=integer;
                }
                integers.clear();
            }


        }



        return arr;
    }


    public static int findMax(int[] arr) {
        int max = arr[0];
        for (int i : arr) {
            if(i>max){
                max = i;
            }
        }
        return max;
    }
}

10. ヒープソート

ヒープの特徴は、ヒープの先頭の要素が最大、大トップヒープの先頭が最大値、小トップヒープの要素が最小値であることです。

ヒープソートとは、ヒープの先頭要素を最後の要素と交換することです。交換後、ヒープの特性は破壊されます。次に、ヒープ内の残りの要素で大きなトップヒープを形成し、先頭要素を次の要素と交換します。最後の 2 番目の要素.... このようにして、残りの要素が 1 つだけになるまで、この時点での配列は整います。

理解を容易にするために、アニメーションも用意しました。

public class HeadSort {
    public static void main(String[] args) {
        int[] arr = {5, 3, 6, 8, 100, 7, 9, 4, 20};
        int n = arr.length;
         //构建大顶堆
         for (int i = (n - 2) / 2; i >= 0; i--) {
             sort(arr, i, n - 1);
         }

         //进行堆排序
        for (int i = n - 1; i >= 1; i--) {
            // 把堆顶元素与最后一个元素交换
            int temp = arr[i];
            arr[i] = arr[0];
            arr[0] = temp;
            // 把打乱的堆进行调整,恢复堆的特性
            sort(arr, 0, i - 1);
         }

        CommonUtils.print(arr);
    }


    public static void sort(int[] arr,int parent, int n) {
        int child = 2*parent+1;

        while (child<n){

            //如果右节点大于左节点这把指针只想左节点
            if(child+1<n&&arr[child]<arr[child+1]){
                child++;
            }
            //比较子节点和父节点的大小
            if(arr[child]>arr[parent]){
                CommonUtils.swap(arr,child,parent);
            }
            parent = child;
            child = 2*parent+1;
        }
    }

}

要約する

画像を使用して、上位 10 個の並べ替えアルゴリズムのプロパティを要約します。

参考記事:

ヒープソートの詳細図(わかりやすい) - 右大臣ブログ - CSDN Blog

https://www.cnblogs.com/itsharehome/p/11058010.html

おすすめ

転載: blog.csdn.net/weixin_55229531/article/details/131264468