1. 程式人生 > >JAVA之各種排序演算法(冒泡、選擇、快排、二分法詳細過程)

JAVA之各種排序演算法(冒泡、選擇、快排、二分法詳細過程)

掌握演算法是作為程式設計師的基本必備素質,而排序也是各種演算法的基礎,雖說java幫我們封裝好了各種資料型別的排序方法,可是我們還是要知道他的原理,下面我就說幾種常用的演算法及原理;

氣泡排序:

原理:相鄰元素兩兩比較,大的往後放,每一次完畢,最大值出現在了最大索引處;
下面我們用圖的方式直觀的給大家展示
在這裡插入圖片描述
從上面的圖來看,每一次比較交換的演算法應該是

/for(int i=0;i<arr.length-1;i++){
 		if(arr[i]>arr[i+1]){
    			//值交換
       			 int t=arr[i];
 				 arr[i]
=arr[i+1]; arr[i+1]=t; } }

首次比較五個數我們只需要比較四次;每多一次排序,少比較一次,因此i<arr.length-1;而這個過程我們需要五次的重複,每次我們給迴圈條件 -1;而這也是可以簡化的,所以最後我們優化過後的演算法為:

private static void sort(int[] arr) {
        for(int j=0;j<arr.length;j++){
            for (int i = 0; i <  arr.length - 1 -j ; i++) {
                if
(arr[i] > arr[i + 1]) { //值交換 int t = arr[i]; arr[i] = arr[i + 1]; arr[i + 1] = t; } } } }

選擇排序:

原理:每一次那一個元素,和剩餘的元素挨個去比較,經過第一遍比較,那麼最小的元素,或移動到最前面去;
在這裡插入圖片描述

 for (int i = index + 1
; i < arr.length; i++) { if (arr[index] > arr[i]) { //值交換 int t = arr[index]; arr[index] = arr[i]; arr[i] = t; } }

選擇排序就是每次選擇一個數和其餘的數一一進行比較,比他大的不動,比他小的兩者交換;第一次我們就是選擇第一個數為基準,它作為index和其餘的比較,而我們第一個比較的數就是第二個數,應為自己和自己比較並沒有意義;然後迴圈比較,每次變數 +1;以上的只是第一次比較,當比較完後,我們換第二個數為基準,即index+1;所以我們將其優化為:

private static void sort2(int[] arr) {
        for (int index = 0; index < arr.length - 1; index++) {
            for (int i = index + 1; i < arr.length; i++) {
                if (arr[index] > arr[i]) {
                    int t = arr[index];
                    arr[index] = arr[i];
                    arr[i] = t;
                }
            }
        }
    }

在外圍再加一層迴圈,它起到的作用就是每次比較過後index自加;


快速排序:

原理:快速排序的原理就是分治法;即先比大小,再分割槽,然後分而治之;
從陣列中取出一個數,作為基準;然後分割槽,選擇出比這個數大的數放到它的右邊,比這個數小的數放到他的左邊;然後分別對左右分割槽進行分割槽,直到每個分割槽只剩一個數;
而他的實現思想可以叫做挖坑填數;什麼意思呢?
1.將基準數挖出,形成坑位一;
2.先從後向前找比基準數小的數,找到後挖出它,形成新坑位,將它填到之前的坑位中;
3.然後由前向後找比基準數大的數,找到後挖出它,將他填到之前的坑位中;
4.分號區後,重複之前的2、3步驟;

第一次分析挖坑填數後的結果如下圖:
在這裡插入圖片描述
程式碼實現:
首先我們需要給序列的起始位置和末尾位置,以此確定每次從前向後和從後向前比較的起點;
int i = start;
int j = end;
然後定義基準位置;
int x =arr[i];
最外圍的迴圈條件為i < j,即起點位置小於終點位置,因為我們最後如果起點位置和終點位置一樣時,每個分割槽就只剩一個數了,這樣就完成了排序;同時我們不知道這個過程需要迴圈多少次,於是用while()迴圈方法;
while(i < j){}
然後我們就分開從左到右和從右到左的兩部分;
從後往前:
while (i<j&&arr[j]>x){
j–;
}
if(i<j){
arr[i]=arr[j];//挖坑填數
i++; //因為接下來我們要從前往後找了,我們順遍讓i遞增一下
}
從前往後:
while (i < j && arr[i] <= x) {
i++;
}
if (i < j) {
arr[j] = arr[i];//挖坑填數
j–; //因為接下來我們要從後往前找了,我們順遍讓j遞減一下
}
最後我們把基準數填到最後的位置:
arr[i]=x;
同時返回基準數的位置,return i;

我們得到分割槽完後,基準數的左邊的數為左分割槽的end,基準數的右邊的數作為右分割槽的start;

因此最後我們得到的程式碼為:

public class QuickSort {

    public static void sort(int[] arr,int start,int end){
        if(start<end){
            //獲取中間索引
            int index=getIndex(arr,start,end);
            //對左右兩部分進行遞迴呼叫
            sort(arr,start,index-1);//排左半邊
            sort(arr,index+1,end);//排右半邊

        }
    }
    //挖坑填數
    private static int getIndex(int[] arr, int start, int end) {
            int i=start;
            int j=end;
            //定義基準數
            int x=arr[i];
            while (i<j){
                //1.從後往前跟基準數進行比較
                while (i<j&&arr[j] >= x){
                    j--;
                }
                if(i<j){
                    arr[i]=arr[j];//挖坑填數
                    i++;//因為接下來我們要從前往後找了,我們順遍讓i遞增一下
                }
                //2.從前往後找
                while (i < j && arr[i] <= x) {
                    i++;
                }
                if (i < j) {
                    arr[j] = arr[i];//挖坑填數
                    j--;//因為接下來我們要從後往前找了,我們順遍讓j遞減一下
                }

            }
            //把基準數填到最後一個坑位
            arr[i]=x;

        return i;
    }
}

二分法查詢:

注:二分法查詢的前提是元素有序;
原理:每次都查中間的那個元素,比較大或者小就能減少一半的元素;
在這裡插入圖片描述
程式碼實現:
首先我們定義三個位置的變數:
int minIndex=0;
int maxIndex=arr.length-1;
int midIndex=(minIndex+maxIndex)/2;
最外圍迴圈則是最小值小於最大值
minIndex < maxIndex;
如果要查的元素,正好等於中間索引所對應的元素 直接返回這個中間索引;
if (ele == arr[midIndex]) {
return midIndex;
}
如果你要查詢的元素比中間索引所對應的元素大 那麼就動最小索引
if (ele > arr[midIndex]) {
minIndex = midIndex + 1;
}
如果你要查詢的元素比中間索引所對應的元素小,那麼你就動最大索引
if (ele < arr[midIndex]) {
maxIndex = midIndex - 1;
}
最後重新計算中間的索引
midIndex = (minIndex + maxIndex) / 2;

所以最後的程式碼就是:

private static int findIndex2(int[] arr, int ele) {
        int minIndex=0;
        int maxIndex=arr.length-1;
        int midIndex=(minIndex+maxIndex)/2;
        while (minIndex < maxIndex){
            //如果要查的元素,正好等於中間索引所對應的元素 直接返回這個中間索引
            if (ele == arr[midIndex]) {
                return midIndex;
                //如果你要查詢的元素比中間索引所對應的元素大 那麼就動最小索引
            } else if (ele > arr[midIndex]) {

                minIndex = midIndex + 1;
                //如果你要查詢的元素比中間索引所對應的元素小,那麼你就動最大索引
            } else if (ele < arr[midIndex]) {
                maxIndex = midIndex - 1;
            }
            //再重新計算中間索引
            midIndex = (minIndex + maxIndex) / 2;
        }
        return -1;
    }