激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務(wù)器之家 - 編程語言 - JAVA教程 - Java編程實(shí)現(xiàn)快速排序及優(yōu)化代碼詳解

Java編程實(shí)現(xiàn)快速排序及優(yōu)化代碼詳解

2021-02-27 14:19GoldArowana JAVA教程

這篇文章主要介紹了Java編程實(shí)現(xiàn)快速排序及優(yōu)化代碼詳解,具有一定借鑒價值,需要的朋友可以了解下。

普通快速排序

找一個基準(zhǔn)值base,然后一趟排序后讓base左邊的數(shù)都小于base,base右邊的數(shù)都大于等于base。再分為兩個子數(shù)組的排序。如此遞歸下去。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class quicksort {
    public static <t extends comparable<? super t>> void sort(t[] arr) {
        sort(arr, 0, arr.length - 1);
    }
    public static <t extends comparable<? super t>> void sort(t[] arr, int left, int right) {
        if (left >= right) return;
        int p = partition(arr, left, right);
        sort(arr, left, p - 1);
        sort(arr, p + 1, right);
    }
    private static <t extends comparable<? super t>> int partition(t[] arr, int left, int right) {
        t base = arr[left];
        int j = left;
        for (int i = left + 1; i <= right; i++) {
            if (base.compareto(arr[i]) > 0) {
                j++;
                swap(arr, j, i);
            }
        }
        swap(arr, left, j);
        return j;
        //返回一躺排序后基準(zhǔn)值的下角標(biāo)
    }
    public static void swap(object[] arr, int i, int j) {
        if (i != j) {
            object temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    private static void printarr(object[] arr) {
        for (object o : arr) {
            system.out.print(o);
            system.out.print("\t");
        }
        system.out.println();
    }
    public static void main(string args[]) {
        integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
        printarr(arr);
        //3  5  1  7  2  9  8  0  4  6
        sort(arr);
        printarr(arr);
        //0  1  2  3  4  5  6  7  8  9
    }
}

快速排序優(yōu)化:隨機(jī)選取基準(zhǔn)值base

在數(shù)組幾乎有序時,快排性能不好(因?yàn)槊刻伺判蚝?,左右兩個子遞歸規(guī)模相差懸殊,大的那部分最后很可能會達(dá)到o(n^2))。

解決:基準(zhǔn)值隨機(jī)地選取,而不是每次都取第一個數(shù)。這樣就不會受“幾乎有序的數(shù)組”的干擾了。但是對“幾乎亂序的數(shù)組”的排序性能可能會稍微下降,至少多了排序前交換的那部分,亂序時這個交換沒有意義...有很多“運(yùn)氣”成分..

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class quicksort {
    public static <t extends comparable<? super t>> void sort(t[] arr) {
        sort(arr, 0, arr.length - 1);
    }
    public static <t extends comparable<? super t>> void sort(t[] arr, int left, int right) {
        if (left >= right) return;
        int p = partition(arr, left, right);
        sort(arr, left, p - 1);
        sort(arr, p + 1, right);
    }
    private static <t extends comparable<? super t>> int partition(t[] arr, int left, int right) {
        //排序前,先讓基準(zhǔn)值和隨機(jī)的一個數(shù)進(jìn)行交換。這樣,基準(zhǔn)值就有隨機(jī)性。
        //就不至于在數(shù)組相對有序時,導(dǎo)致左右兩邊的遞歸規(guī)模不一致,產(chǎn)生最壞時間復(fù)雜度
        swap(arr,left,(int)(math.random()*(right - left + 1)+left));
        t base = arr[left];
        int j = left;
        for (int i = left + 1; i <= right; i++) {
            if (base.compareto(arr[i]) > 0) {
                j++;
                swap(arr, j, i);
            }
        }
        swap(arr, left, j);
        return j;
        //返回一躺排序后,基準(zhǔn)值的下角標(biāo)
    }
    public static void swap(object[] arr, int i, int j) {
        if (i != j) {
            object temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    private static void printarr(object[] arr) {
        for (object o : arr) {
            system.out.print(o);
            system.out.print("\t");
        }
        system.out.println();
    }
    public static void main(string args[]) {
        integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
        printarr(arr);
        //3  5  1  7  2  9  8  0  4  6
        sort(arr);
        printarr(arr);
        //0  1  2  3  4  5  6  7  8  9
    }
}

快速排序繼續(xù)優(yōu)化:配合著使用插入排序

快排是不斷減小問題規(guī)模來解決子問題的,需要不斷遞歸。但是遞歸到規(guī)模足夠小時,如果繼續(xù)采用這種 不穩(wěn)定+遞歸 的方式執(zhí)行下去,效率不見得會很好。

所以當(dāng)問題規(guī)模較小時,近乎有序時,插入排序表現(xiàn)的很好。java自帶的arrays.sort()里經(jīng)常能看到這樣的注釋:“use insertion sort on tiny arrays”,“insertion sort on smallest arrays”

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public class quicksort {
    public static <t extends comparable<? super t>> void sort(t[] arr) {
        sort(arr, 0, arr.length - 1, 16);
    }
    /**
   * @param arr  待排序的數(shù)組
   * @param left 左閉
   * @param right 右閉
   * @param k   當(dāng)快排遞歸到子問題的規(guī)模 <= k 時,采用插入排序優(yōu)化
   * @param <t>  泛型,待排序可比較類型
   */
    public static <t extends comparable<? super t>> void sort(t[] arr, int left, int right, int k) {
        // 規(guī)模小時采用插入排序
        if (right - left <= k) {
            insertionsort(arr, left, right);
            return;
        }
        int p = partition(arr, left, right);
        sort(arr, left, p - 1, k);
        sort(arr, p + 1, right, k);
    }
    public static <t extends comparable<? super t>> void insertionsort(t[] arr, int l, int r) {
        for (int i = l + 1; i <= r; i++) {
            t cur = arr[i];
            int j = i - 1;
            for (; j >= 0 && cur.compareto(arr[j]) < 0; j--) {
                arr[j + 1] = arr[j];
            }
            arr[j + 1] = cur;
        }
    }
    private static <t extends comparable<? super t>> int partition(t[] arr, int left, int right) {
        //排序前,先讓基準(zhǔn)值和隨機(jī)的一個數(shù)進(jìn)行交換。這樣,基準(zhǔn)值就有隨機(jī)性。
        //就不至于在數(shù)組相對有序時,導(dǎo)致左右兩邊的遞歸規(guī)模不一致,產(chǎn)生最壞時間復(fù)雜度
        swap(arr, left, (int) (math.random() * (right - left + 1) + left));
        t base = arr[left];
        int j = left;
        for (int i = left + 1; i <= right; i++) {
            if (base.compareto(arr[i]) > 0) {
                j++;
                swap(arr, j, i);
            }
        }
        swap(arr, left, j);
        return j;
        //返回一躺排序后,基準(zhǔn)值的下角標(biāo)
    }
    public static void swap(object[] arr, int i, int j) {
        if (i != j) {
            object temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    private static void printarr(object[] arr) {
        for (object o : arr) {
            system.out.print(o);
            system.out.print("\t");
        }
        system.out.println();
    }
    public static void main(string args[]) {
        integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
        printarr(arr);
        //3  5  1  7  2  9  8  0  4  6
        sort(arr);
        printarr(arr);
        //0  1  2  3  4  5  6  7  8  9
    }
}

快速排序繼續(xù)優(yōu)化:兩路快排

在最開始的普通快速排序說過,讓基準(zhǔn)值base左邊的都比base小,而base右邊的都大于等于base。等于base的這些會聚集到右側(cè)(或者稍微改改大小關(guān)系就會聚集到左側(cè))??傊蜁奂揭贿叀_@樣在數(shù)組中重復(fù)數(shù)字很多的時候,就又會導(dǎo)致兩邊子遞歸規(guī)模差距懸殊的情況。這時想把等于base的那些數(shù)分派到base兩邊,而不是讓他們聚集到一起。

(注:測試代碼的時候,最好把插入排序那部分注視掉,向我下面代碼中那樣...不然數(shù)據(jù)量小于k=16的時候執(zhí)行的是插入排序.....)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public class quicksort {
    public static <t extends comparable<? super t>> void sort(t[] arr) {
        sort(arr, 0, arr.length - 1, 16);
    }
    /**
   * @param arr  待排序的數(shù)組
   * @param left 左閉
   * @param right 右閉
   * @param k   當(dāng)快排遞歸到子問題的規(guī)模 <= k 時,采用插入排序優(yōu)化
   * @param <t>  泛型,待排序可比較類型
   */
    public static <t extends comparable<? super t>> void sort(t[] arr, int left, int right, int k) {
        // 規(guī)模小時采用插入排序
        //    if (right - left <= k) {
        //      insertionsort(arr, left, right);
        //      return;
        //    }
        if (left >= right) return;
        int p = partition(arr, left, right);
        sort(arr, left, p - 1, k);
        sort(arr, p + 1, right, k);
    }
    public static <t extends comparable<? super t>> void insertionsort(t[] arr, int l, int r) {
        for (int i = l + 1; i <= r; i++) {
            t cur = arr[i];
            int j = i - 1;
            for (; j >= 0 && cur.compareto(arr[j]) < 0; j--) {
                arr[j + 1] = arr[j];
            }
            arr[j + 1] = cur;
        }
    }
    private static <t extends comparable<? super t>> int partition(t[] arr, int left, int right) {
        //排序前,先讓基準(zhǔn)值和隨機(jī)的一個數(shù)進(jìn)行交換。這樣,基準(zhǔn)值就有隨機(jī)性。
        //就不至于在數(shù)組相對有序時,導(dǎo)致左右兩邊的遞歸規(guī)模不一致,產(chǎn)生最壞時間復(fù)雜度
        swap(arr, left, (int) (math.random() * (right - left + 1) + left));
        t base = arr[left];
        //基準(zhǔn)值,每次都把這個基準(zhǔn)值拋出去,看成[left+1.....right]左閉右閉區(qū)間的排序
        int i = left + 1;
        //對于上一行提到的[left+1.....right]區(qū)間,i表示 [left+1......i)左閉右開區(qū)間的值都小于等于base。
        int j = right;
        //對于上二行提到的[left+1.....right]區(qū)間,j表示 (j......right]左開右閉區(qū)間的值都大于等于base。
        while (true) {
            //從左到右掃描,掃描出第一個比base大的元素,然后i停在那里。
            while (i <= right && arr[i].compareto(base) < 0) i++;
            //從右到左掃描,掃描出第一個比base小的元素,然后j停在那里。
            while (j >= left && arr[j].compareto(base) > 0) j--;
            if (i > j) {
                //雖說是i>j,但其實(shí)都是以j=i-1為條件結(jié)束的
                break;
            }
            swap(arr, i++, j--);
        }
        swap(arr, left, j);
        return j;
        //返回一躺排序后,基準(zhǔn)值的下角標(biāo)
    }
    public static void swap(object[] arr, int i, int j) {
        if (i != j) {
            object temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    private static void printarr(object[] arr) {
        for (object o : arr) {
            system.out.print(o);
            system.out.print("\t");
        }
        system.out.println();
    }
    public static void main(string args[]) {
        integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
        printarr(arr);
        //3  5  1  7  2  9  8  0  4  6
        sort(arr);
        printarr(arr);
        //0  1  2  3  4  5  6  7  8  9
    }
}

快速排序繼續(xù)優(yōu)化:兩路快排 不用swap,用交換

上面的兩路在找到大于base的值和小于base的值時,用的是swap()方法來進(jìn)行交換。兩數(shù)交換涉及到第三個變量temp的操作,多了讀寫操作。接下來用直接賦值的方法,把小于的放到右邊,大于的放到左邊,當(dāng)i和j相遇時,那個位置就是base該放的地方。至此一趟完成。遞歸即可。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public class quicksort {
    public static <t extends comparable<? super t>> void sort(t[] arr) {
        sort(arr, 0, arr.length - 1, 16);
    }
    /**
   * @param arr  待排序的數(shù)組
   * @param left 左閉
   * @param right 右閉
   * @param k   當(dāng)快排遞歸到子問題的規(guī)模 <= k 時,采用插入排序優(yōu)化
   * @param <t>  泛型,待排序可比較類型
   */
    public static <t extends comparable<? super t>> void sort(t[] arr, int left, int right, int k) {
        // 規(guī)模小時采用插入排序
        //    if (right - left <= k) {
        //      insertionsort(arr, left, right);
        //      return;
        //    }
        if (left >= right) return;
        int p = partition(arr, left, right);
        sort(arr, left, p - 1, k);
        sort(arr, p + 1, right, k);
    }
    public static <t extends comparable<? super t>> void insertionsort(t[] arr, int l, int r) {
        for (int i = l + 1; i <= r; i++) {
            t cur = arr[i];
            int j = i - 1;
            for (; j >= 0 && cur.compareto(arr[j]) < 0; j--) {
                arr[j + 1] = arr[j];
            }
            arr[j + 1] = cur;
        }
    }
    private static <t extends comparable<? super t>> int partition(t[] arr, int left, int right) {
        //排序前,先讓基準(zhǔn)值和隨機(jī)的一個數(shù)進(jìn)行交換。這樣,基準(zhǔn)值就有隨機(jī)性。
        //就不至于在數(shù)組相對有序時,導(dǎo)致左右兩邊的遞歸規(guī)模不一致,產(chǎn)生最壞時間復(fù)雜度
        swap(arr, left, (int) (math.random() * (right - left + 1) + left));
        t base = arr[left];
        //基準(zhǔn)值,每次都把這個基準(zhǔn)值拋出去,看成[left+1.....right]左閉右閉區(qū)間的排序
        int i = left;
        //對于上一行提到的[left+1.....right]區(qū)間,i表示 [left+1......i)左閉右開區(qū)間的值都小于等于base。
        int j = right;
        //對于上二行提到的[left+1.....right]區(qū)間,j表示 (j......right]左開右閉區(qū)間的值都大于等于base。
        while (i < j) {
            //從右到左掃描,掃描出第一個比base小的元素,然后j停在那里。
            while (j > i && arr[j].compareto(base) > 0) j--;
            arr[i] = arr[j];
            //從左到右掃描,掃描出第一個比base大的元素,然后i停在那里。
            while (i < j && arr[i].compareto(base) < 0) i++;
            arr[j] = arr[i];
        }
        arr[j] = base;
        return j;
        //返回一躺排序后,基準(zhǔn)值的下角標(biāo)
    }
    public static void swap(object[] arr, int i, int j) {
        if (i != j) {
            object temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    private static void printarr(object[] arr) {
        for (object o : arr) {
            system.out.print(o);
            system.out.print("\t");
        }
        system.out.println();
    }
    public static void main(string args[]) {
        integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
        printarr(arr);
        //3  5  1  7  2  9  8  0  4  6
        sort(arr);
        printarr(arr);
        //0  1  2  3  4  5  6  7  8  9
    }
}

快速排序繼續(xù)優(yōu)化:當(dāng)大量數(shù)據(jù),且重復(fù)數(shù)多時,用三路快排

把數(shù)組分為三路,第一路都比base小,第二路都等于base,第三路都大于base。

用指針從前到后掃描,如果:

1.cur指向的數(shù)小于base,那么:交換arr[cur]和arr[i]的值,然后i++,cur++。

2.cur指向的數(shù)等于base,那么:cur++

3.cur指向的數(shù)大于base,那么:交換arr[cur]和arr[j]的值,然后j--。

當(dāng)cur>j的時候說明三路都已經(jīng)完成。

Java編程實(shí)現(xiàn)快速排序及優(yōu)化代碼詳解

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
public class quicksort {
    public static <t extends comparable<? super t>> void sort(t[] arr) {
        sort(arr, 0, arr.length - 1, 16);
    }
    /**
   * @param arr  待排序的數(shù)組
   * @param left 左閉
   * @param right 右閉
   * @param k   當(dāng)快排遞歸到子問題的規(guī)模 <= k 時,采用插入排序優(yōu)化
   * @param <t>  泛型,待排序可比較類型
   */
    public static <t extends comparable<? super t>> void sort(t[] arr, int left, int right, int k) {
        // 規(guī)模小時采用插入排序
        //    if (right - left <= k) {
        //      insertionsort(arr, left, right);
        //      return;
        //    }
        if (left >= right) return;
        int[] ret = partition(arr, left, right);
        sort(arr, left, ret[0], k);
        sort(arr, ret[1], right, k);
    }
    public static <t extends comparable<? super t>> void insertionsort(t[] arr, int l, int r) {
        for (int i = l + 1; i <= r; i++) {
            t cur = arr[i];
            int j = i - 1;
            for (; j >= 0 && cur.compareto(arr[j]) < 0; j--) {
                arr[j + 1] = arr[j];
            }
            arr[j + 1] = cur;
        }
    }
    /**
   * @param arr  待排序的數(shù)組
   * @param left 待排序數(shù)組的左邊界
   * @param right 待排序數(shù)組的右邊界
   * @param <t>  泛型
   * @return
   */
    private static <t extends comparable<? super t>> int[] partition(t[] arr, int left, int right) {
        //排序前,先讓基準(zhǔn)值和隨機(jī)的一個數(shù)進(jìn)行交換。這樣,基準(zhǔn)值就有隨機(jī)性。
        //就不至于在數(shù)組相對有序時,導(dǎo)致左右兩邊的遞歸規(guī)模不一致,產(chǎn)生最壞時間復(fù)雜度
        swap(arr, left, (int) (math.random() * (right - left + 1) + left));
        t base = arr[left];
        //基準(zhǔn)值,每次都把這個基準(zhǔn)值拋出去,看成[left+1.....right]左閉右閉區(qū)間的排序
        //三路快排分為下面這三個路(區(qū)間)
        int i = left;
        // left表示,[lleft...left) 左閉右開區(qū)間里的數(shù)都比base小
        int j = right;
        // left表示,(rright...right] 左開右閉區(qū)間里的數(shù)都比base大
        int cur = i;
        //用cur來遍歷數(shù)組。[left...cur)左閉右開區(qū)間里的數(shù)都等于base
        while (cur <= j) {
            if (arr[cur].compareto(base) == 0) {
                cur++;
            } else if (arr[cur].compareto(base) < 0) {
                swap(arr, cur++, i++);
            } else {
                swap(arr, cur, j--);
            }
        }
        return new int[]{i - 1, j + 1};
        //[i...j]都等于base,子問題就只需要解決i左邊和j右邊就行了
    }
    public static void swap(object[] arr, int i, int j) {
        if (i != j) {
            object temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    private static void printarr(object[] arr) {
        for (object o : arr) {
            system.out.print(o);
            system.out.print("\t");
        }
        system.out.println();
    }
    public static void main(string args[]) {
        integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
        printarr(arr);
        //3  5  1  7  2  9  8  0  4  6
        sort(arr);
        printarr(arr);
        //0  1  2  3  4  5  6  7  8  9
    }
}

總結(jié)

以上就是本文關(guān)于java編程實(shí)現(xiàn)快速排序及優(yōu)化代碼詳解的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!

原文鏈接:http://www.cnblogs.com/noKing/p/7922397.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美黄色一级片在线观看 | 性欧美极品xxxx欧美一区二区 | 午夜精品一区二区三区免费 | 中文字幕在线观看视频www | 国产精品一区二区日韩 | bt 自拍 另类 综合 欧美 | av在线免费观看网 | 欧美精品亚洲人成在线观看 | 日韩激情 | 成人av一二三区 | 色综合久久久久综合99 | 一区二区三区欧洲 | 久久久久中精品中文字幕19 | 国产妇女乱码一区二区三区 | 高清视频91 | 一区二区国产在线 | 欧美一级黄色免费 | av在线免费不卡 | 欧日一级片| 亚洲网站免费 | 久久这里只有精品1 | 欧美视频一区二区 | 国产精品99一区二区 | av电影院在线观看 | 国产婷婷一区二区三区 | 毛片免费视频网站 | h视频免费在线 | 国产小视频在线观看 | 国产中文av在线 | 中国hdxxxx护士爽在线观看 | 有色视频在线观看 | 久久综合网址 | 欧美激情精品久久久久久久久久 | 欧美一级高清片 | 毛片免费观看日本中文 | 久久久免费观看完整版 | 亚洲精品午夜电影 | 亚洲精品一区二区三区免 | 欧美日韩免费在线观看视频 | 久久精品中文字幕一区 | 毛片在线免费视频 |