高度なクイックソート:問題のインタビューを解決TOPK

       上のK大きな数を計算するクイックソート、私たちは、その後も発散的思考小さな最初の質問のK計算をK-位の多数の迅速な計算を使用する方法について説明します。これに基づき、我々はすぐにTOPKを排出し、問題を解決する方法を考える必要があります。TOPKは、顔の質問には、多くの場合、確かにそれを聞いたことも求められることなく、インタビューの中で出くわす非常に古典的です。名前が示唆TOPKがあるデータのセットにおけるプレKランキングの数例の3、2、3、1、7、45、5、6、評価3の前TOP3の多数のグループ(デフォルトはフロント多数のKである)、すなわち数である7,6,5

 前の私たちが最初にこの考えに基づいて、ちょうどソートライン上の1-K間の数に、TOPKを取得し続けるためには、K大規模な数を計算し、我々はTOPKの最初のバージョンに来ます。

 1.0

public class TopK {
    public static int k = 3;

    public static void main(String[] args) {
        int arr[] = {3, 2, 3, 1, 7, 4, 5, 5, 6};
        topKSort(arr);
        StringBuilder topK = new StringBuilder();
        for (int i = 0; i < k; i++) {
            topK.append(arr[i]);
        }
        System.out.println("TopK=" + topK);
    }


    public static int topKSort(int arr[]) {
        int length = arr.length;
        if (k <= 0 || k > length) throw new RuntimeException("K值不合理");
        int left = 0, right = length - 1;
        int p = -1;
        while (k != p + 1) {
            if (k < p + 1) {
                right = p - 1;
            } else if (k > p + 1) {
                left = p + 1;
            }
            p = partition(arr, left, right);
        }
        quickSort(arr, 0, k - 1);
        return arr[p];
    }

    public static void quickSort(int arr[], int left, int right) {
        if (left >= right) return;
        int q = partition(arr, left, right);
        quickSort(arr, left, q - 1);
        quickSort(arr, q + 1, right);

    }

    public static int partition(int[] arr, int left, int right) {
        int pivot = arr[right];
        int sortIndex = left;
        for (int arrIndex = sortIndex; arrIndex < right; arrIndex++) {
            if (arr[arrIndex] > pivot) {
                swap(arr, arrIndex, sortIndex);
                sortIndex++;
            }
        }
        swap(arr, sortIndex, right);
        return sortIndex;
    }

    public static void swap(int[] arr, int i, int j) {
        if (i == j) return;
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }


}

添字1-Kの数は左の境界は、パス0をソートするときだから、0-K-1の間であるので、K-1の右境界が通過することができます

2.0

   ここでは、バージョン2.0を見て続行します。

public class TopK {
    public static int k = 3;

    public static void main(String[] args) {
        int arr[] = {3, 2, 3, 1, 7, 4, 5, 5, 6};
        topKSort(arr);
        StringBuilder topK = new StringBuilder();
        for (int i = 0; i < k; i++) {
            topK.append(arr[i]);
        }
        System.out.println("TopK=" + topK);
    }


    public static int topKSort(int arr[]) {
        int length = arr.length;
        if (k <= 0 || k > length) throw new RuntimeException("K值不合理");
        int left = 0, right = length - 1;
        int p = -1;
        while (k != p + 1) {
            if (k < p + 1) {
                right = p - 1;
            } else if (k > p + 1) {
                left = p + 1;
            }
            p = partition(arr, left, right);
        }
        quickSort(arr, 0, k - 2);
        return arr[p];
    }

    public static void quickSort(int arr[], int left, int right) {
        if (left >= right) return;
        int q = partition(arr, left, right);
        quickSort(arr, left, q - 1);
        quickSort(arr, q + 1, right);

    }

    public static int partition(int[] arr, int left, int right) {
        int pivot = arr[right];
        int sortIndex = left;
        for (int arrIndex = sortIndex; arrIndex < right; arrIndex++) {
            if (arr[arrIndex] > pivot) {
                swap(arr, arrIndex, sortIndex);
                sortIndex++;
            }
        }
        swap(arr, sortIndex, right);
        return sortIndex;
    }

    public static void swap(int[] arr, int i, int j) {
        if (i == j) return;
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }


}

       このバージョンは、バージョン1.0のために少しだけ変化する最適化されています。これは、K-2への右境界のtopKSort方法クイックソートです。ここでのアイデアは、高速行の特性に基づいており、この位置におけるKの数は、ソートに参加しないようにKに残されている位置の数は、Kよりも大きいですこうして位置をソートするK-2に0となります。

2.0概要:

これまでは、基本的な問題が解決されるTOPK。しかし、実際には、我々はまだ0の左余白と右の境界クイックソートのk-2、ここでの主なポイントの最適化のための部屋、最適化を持っています。あなたがにすばやくソートし、特にプロセス全体のK多数の要件に精通している必要がありますこれは、最適化のアイデア:まず、コードのK値を求める過程で、実際の並べ替えです。だから、K-2から0に、この範囲は、おそらく特定の数は、我々は、それによってソート時間を短縮することが、この範囲をソートするために、K-2 0を減らすことができるように、注文することです。この考えに基づき、我々は3番目のバージョンを得ました。

3.0:

public class TopK {
    public static int k = 8;

    public static void main(String[] args) {
        int arr[] = {3, 2, 3, 1, 7, 4, 5, 5, 6};
        topKSort(arr);
        StringBuilder topK = new StringBuilder();
        for (int i = 0; i < k; i++) {
            topK.append(arr[i]);
        }
        System.out.println("TopK=" + topK);
    }


    public static int topKSort(int arr[]) {
        int length = arr.length;
        if (k <= 0 || k > length) throw new RuntimeException("K值不合理");
        int left = 0, right = length - 1;
        int p = -1;
        int leftBorder = 0;
        int rightBorder = k - 2;
        while (k != p + 1) {
            if (k < p + 1) {
                right = p - 1;
            } else if (k > p + 1) {
                left = p + 1;
            }
            p = partition(arr, left, right);
            if (p == leftBorder + 1) {
                leftBorder++;
            }
            if (p == rightBorder - 1) {
                rightBorder--;
            }
        }
        quickSort(arr, leftBorder, rightBorder);
        return arr[p];
    }

    public static void quickSort(int arr[], int left, int right) {
        if (left >= right) return;
        int q = partition(arr, left, right);
        quickSort(arr, left, q - 1);
        quickSort(arr, q + 1, right);

    }

    public static int partition(int[] arr, int left, int right) {
        int pivot = arr[right];
        int sortIndex = left;
        for (int arrIndex = sortIndex; arrIndex < right; arrIndex++) {
            if (arr[arrIndex] > pivot) {
                swap(arr, arrIndex, sortIndex);
                sortIndex++;
            }
        }
        swap(arr, sortIndex, right);
        return sortIndex;
    }

    public static void swap(int[] arr, int i, int j) {
        if (i == j) return;
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }


}

ポイントを変更します:

TopKSortループ方法が、次のコードを追加します。

            if (p == leftBorder + 1) {
                leftBorder++;
            }
            if (p == rightBorder - 1) {
                rightBorder--;
            }

そして、代わりに呼び出して変数のleftBorderとrightBorderクイックソートが出て、この方法の右の境界線を使用しました。

最適化分析のアイデア:

まず、我々は3のアレイ、2、3、1、7、4、5、5、6以上のコードを見て:パーティション初めて、基準点である6、7、1、3、6、ソートが完了した後、3、4、5、5、2、添字Pの値は1です私たちは逆の順序であるため、左側の数6以上6つのベーシスポイントであり、6のインデックス値が1であるので、それは、唯一の番号7を左:クイックソートの特性に応じて7,6を注文する必要がありますので、そのインデックス番号0と1が、その後限りP 2,3,4の値として、順序付けられ...そして再び値の出現後、それは左ボーダーできるので、我々は、同じように左マージンを追加することができます値1に加算されます。同様に右の境界は限りP値が1の右の境界よりも小さい表示されたとして、それは右の境界マイナス1することができ、同じ考えです。これは、全体の並べ替え時間の短縮、左右の境界線の種類を減らし、全体TOPKアルゴリズムを最適化します。

最適化の結果は以下の通りでした。

         

                          最適化前                                                                                最適化後

        この図は、TOP1、TOP9の最適化、右の写真のショーについてTOP1-TOP9の最適化の境界値の前に境界値を周りに残っています。TOP3-TOP7で見ることができ、左マージンの変化はまだ大きくなっている、最適化の効果は明ら​​かです。

4.0:

public class TopK {
    public static int k = 8;
    public static boolean topBigK = true;

    public static void main(String[] args) {
        int arr[] = {3, 2, 3, 1, 7, 4, 5, 5, 6};
        topKSort(arr);
        StringBuilder topK = new StringBuilder();
        for (int i = 0; i < k; i++) {
            topK.append(arr[i]);
        }
        System.out.println("TopK=" + topK);
    }


    public static int topKSort(int arr[]) {
        int length = arr.length;
        if (k <= 0 || k > length) throw new RuntimeException("K值不合理");
        int left = 0, right = length - 1;
        int p = -1;
        int leftBorder = 0;
        int rightBorder = k - 2;
        while (k != p + 1) {
            if (k < p + 1) {
                right = p - 1;
            } else if (k > p + 1) {
                left = p + 1;
            }
            p = partition(arr, left, right);
            if (p == leftBorder + 1) {
                leftBorder = p;
            }
            if (p == rightBorder - 1) {
                rightBorder = p;
            }
        }
        quickSort(arr, leftBorder, rightBorder);
        return arr[p];
    }

    public static void quickSort(int arr[], int left, int right) {
        if (left >= right) return;
        int q = partition(arr, left, right);
        quickSort(arr, left, q - 1);
        quickSort(arr, q + 1, right);

    }

    public static int partition(int[] arr, int left, int right) {
        int pivot = arr[right];
        int sortIndex = left;
        for (int arrIndex = sortIndex; arrIndex < right; arrIndex++) {
            if (topBigK ? arr[arrIndex] > pivot : arr[arrIndex] < pivot) {
                swap(arr, arrIndex, sortIndex);
                sortIndex++;
            }
        }
        swap(arr, sortIndex, right);
        return sortIndex;
    }

    public static void swap(int[] arr, int i, int j) {
        if (i == j) return;
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }


}

変化のこのバージョンは非常に簡単であり、追加topBigKようにプレK K数の小規模または大規模な数を求める前に、識別として使用することができます。方法topKSort leftBorder ++及びrightBorder ++ leftBorder = pおよびrightBorder = Pを変更し、効果は同じです。

要約:

K-数が要求数Kの前に必要とされる、と彼らはソート迅速にフィットするかどうか高い、結果は半順序データの場合に得ることができています。具体的には、K-シークの数は、各基準点を受け取る行高速注文、及び基準点は、番号の配列されると、それは言い、かつ迅速に完全な一致を排出することができます。最初のK番号を取得した後、数が事前-Kは比較的簡単ですが、また、いくつかの基本的なアルゴリズムを実行する必要があり模索し続けています。だけで特に馴染みの仕分けのプロセス全体の後に、それは最高の機能の実現、および最適化で達成し、段階的に向上させることができます。

 

公開された25元の記事 ウォン称賛51 ビュー20000 +

おすすめ

転載: blog.csdn.net/Royal_lr/article/details/105268499