使用java實現快速排序(挖坑填數法和指針交換法)


快速排序:通過一趟排序,將數據分為兩部分,其中一部分中的所有數據比另外一部分的所有數據要小,然后按照此方法,分別對這兩部分進行排序,達到最終的排序結果。

每趟排序選取基准元素,比該基准元素大的數據放在一邊,比該基准元素小的數據放在另一邊,這種處理方式稱為分治法。

數據的移動是基准元素中比較重要的點,有兩種方式實現,挖坑填數法和指針交換法

挖坑填數法

(下圖中單詞有兩處拼寫錯誤,pviot和pvoit應該為pivot)

如下為代碼實現

import java.util.Arrays;

public class QuickSort {
    public static void main(String[] args) {
        int[] arr = { 12, 45, 23, 67, 7, 1, 5, 21 };
        quickSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }

    public static void quickSort(int[] arr, int startIndex, int endIndex) {
        if (startIndex >= endIndex) {
            return;
        }

        int partitionIndex = getPartitionIndex(arr, startIndex, endIndex);

        quickSort(arr, startIndex, partitionIndex - 1);
        quickSort(arr, partitionIndex + 1, endIndex);

    }

    public static int getPartitionIndex(int[] arr, int startIndex, int endIndex) {
        int index = startIndex;
        int left = startIndex;
        int right = endIndex;
        int pivot = arr[startIndex];

        while (left < right) {
            while (left < right) {
                if (arr[right] < pivot) {
                    arr[index] = arr[right]; // 找到所需值,將值填充到坑位
                    index = right; // 此時right位置為index新坑位
                    left++; // 右側找到了數據,則left右移一位,准備進行比對
                    break; // 找到數據之后,跳出內循環,准備從左側開始對比
                }
                // 沒有匹配的數據,則right左移一位,繼續對比
                right--;
            }

            while (left < right) {
                if (arr[left] > pivot) {
                    arr[index] = arr[left]; // 找到所需的值,將值填充到坑位
                    index = left; // 此時left位置為index新坑位
                    right--; // 左側找到了數據之后,right向左移動一位,准備進行比較
                    break; // 找到數據之后,跳出內循環,准備從左側開始對比
                }
                // 沒有匹配的數據,則left右移一位,繼續對比
                left++;
            }
        }

        // 最后將pivot放入index位置
        arr[index] = pivot;
        return index;
    }

}

指針交換法

代碼實現如下

import java.util.Arrays;
public class QuickSort {
    public static void main(String[] args) {
        int[] arr = { 12, 45, 23, 67, 7, 1, 5, 21 };
        quickSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }

    public static void quickSort(int[] arr, int startIndex, int endIndex) {
        if (startIndex >= endIndex) {
            return;
        }

        int partitionIndex = getPartitionIndex(arr, startIndex, endIndex);

        quickSort(arr, startIndex, partitionIndex - 1);
        quickSort(arr, partitionIndex + 1, endIndex);

    }

    public static int getPartitionIndex(int[] arr, int startIndex, int endIndex) {
        int left = startIndex;
        int right = endIndex;
        int pivot = arr[startIndex];

        while (left != right) {

            // 左側索引必須小於右側索引,當右側數據大於基准元素,則將右側元素向左移動一位,繼續判斷,直到找到比基准元素小的數據
            while (left < right && arr[right] > pivot) {
                right--;
            }

            // 左側索引必須小於右側索引,當左側數據小於等於基准元素,則將左側元素右移一位,繼續判斷,直到找到比基准元素大的數據位置
            while (left < right && arr[left] <= pivot) { // 此處必須是左側元素“小於等於”基准元素
                left++;
            }

            if (left < right) {
                // 通過以上兩輪while循環,已經找到左側大於基准元素的數據和右側小於基准元素的數據,交換它們
                int tmp = arr[left];
                arr[left] = arr[right];
                arr[right] = tmp;
            }
        }

        // 此時right和left值是相同的,將基准元素與重合位置元素交換
        arr[startIndex] = arr[left];
        arr[left] = pivot;
        return left;
    }
}

 

討論

1、以上兩種方式只有在獲取分區索引的代碼不一樣,其他都一樣

2、指針交換法中,第二個內層while循環為什么必須要小於等於基准元素才行?

     假設去掉等於,那么我們從左側取的第一個值是12,pivot為12,則arr[left]<pivot條件不成立,那么則left的值就不會變化,此時在下面的交換中,arr[left]的值始終不變,最終的排序結果也將是錯誤的,所以需要是小於等於基准元素

3、以上兩種方式是否有優化空間

    在兩種處理方式的getPartitionIndex方法返回值前添加打印數組語句,輸出結果分別為

挖坑填數法輸出

[5, 1, 7, 12, 67, 23, 45, 21]
[1, 5, 7, 12, 67, 23, 45, 21]
[1, 5, 7, 12, 21, 23, 45, 67]
[1, 5, 7, 12, 21, 23, 45, 67]
[1, 5, 7, 12, 21, 23, 45, 67]
[1, 5, 7, 12, 21, 23, 45, 67]

指針交換法輸出

[7, 5, 1, 12, 67, 23, 45, 21]
[1, 5, 7, 12, 67, 23, 45, 21]
[1, 5, 7, 12, 67, 23, 45, 21]
[1, 5, 7, 12, 21, 23, 45, 67]
[1, 5, 7, 12, 21, 23, 45, 67]
[1, 5, 7, 12, 21, 23, 45, 67]
[1, 5, 7, 12, 21, 23, 45, 67]

可以發現,挖坑填數法,在第三次輸出時已經是一個有序集合了,指針交換法在第四次輸出后也是一個有序集合,所以上述兩種代碼可以進行優化處理

優化,待添加。。。。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM