1. 程式人生 > >java演算法例項_排序&&查詢&&遞迴

java演算法例項_排序&&查詢&&遞迴

目錄:

一、常見的排序

    1、簡單的桶排序

    2、氣泡排序

    3、選擇排序

    4、 插入排序

    5、希爾排序

    6、快速排序

    7、堆排序

二、二分查詢和折半插入

    1、二分查詢

    2、折半插入

三、遞迴演算法

    1、案例1:遍歷資料夾下的所有指定字尾名的檔案,返回List集合

    2、案例2:獲取json 中所有的key和value,返回map<key,value>

一、常見的排序

1、簡單的桶排序:

    假設有5個學生,得分在0--10之間,現在分數分別為5 3 5 2 8 。。

    想辦法使得從大到小或者從小到大排序輸出? 

public static void main(String[] args){
    int[] arr = {5,3,5,2,8};
    //new 一個數組,每個元素代表一種成績,,11個元素代表0-10
    int[] duiArr = new int[11];//初始化為0,即沒有成績,,一次為1,兩次為2....
    for (int i = 0;i<arr.length;i++){
        //duiArr[arr[i]] += 1;
        duiArr[arr[i]]++;
    }

    //遍歷duiArr,,按照每個元素的數值列印幾次,,如果是2,列印兩次
    for(int j = 0;j<duiArr.length;j++){ // j代表的是元素的值  duiArr代表的是元素的個數
        if(duiArr[j] == 0){
            continue;
        }
        for(int k = 0;k<duiArr[j];k++){
            System.out.println("從小到大排序:" + j);
        }
    }
}
運算結果:

2、氣泡排序

      時間複雜度:o(n^2)

      在上面簡單版的堆排序中,有很多問題,比如:太浪費空間,如果排序的元素範圍很大,就需要0-很大這麼多個桶來儲存!再比如:如果比較的是小數,也不行!氣泡排序則不涉及這麼多問題

      基本思想:每次比較相鄰的元素,如果它們的順序錯誤,就把它們交換過來。。(畢竟順序要麼a-b要麼b-a)每一趟的末尾元素一定是一定是最小的或者最大的。

      演算法步驟:

      1)比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。

      2)對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數。

      3)針對所有的元素重複以上的步驟,除了最後一個。

      4)持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。

      假如,我們要從大到小排列35 12 99 18 76個數。。基於此思想:

第一趟:

     第一次:比較第一位和第二位的數:35和12,35 > 12,所以交換,得到

        12 35 99 18 76

     第二次:比較第二位和第三位的數: 35和99,35 < 99,所以不交換,得到

        12 35 99 18 76

     第三次: 比較第三位和第四位的數:99和18,99 > 18,所以交換,得到

        12 35 18 99 76

     第四次:比較第四位和第五位的數:99和76,99 > 76,所以交換,得到

        12 35 18 76 99     

     可以發現,最大的數99,已經排到最後了!!到這裡,就已經將一個數字的位置確定了,我們稱之為歸位。

     也稱之為一趟。。

第二趟:也是從第一個數開始,將最大的數往後排!不難推斷,5個數的排列,需要遍歷(5-1)趟。。每一趟需要從第一個數比較到最後一個尚未歸位的數。根據你設定的換位條件。

      程式碼:

/**
 * 氣泡排序
 *
 * @param arr 陣列(亂序)
 * @return
 */
public static int[] bubbleSort(int[] arr) {
    int n = arr.length;
    for (int i = 0; i < n - 1; i++) { //0 1 2 3,四趟
        for (int j = 0; j < n - i - 1; j++) { //i=0時,比較4次;i=1時,比較3次.....i=3時,比較1次
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
        System.out.println(Arrays.toString(arr));
    }
    return arr;
}

      測試:

public static void main(String[] args) {
    int[] arr = {35, 12, 99, 18, 76};
    System.out.println("排序中:");
    int[] bubbleSort = bubbleSort(arr);
    System.out.println("排序後:");
    System.out.println(Arrays.toString(bubbleSort));
}

      執行結果:

不難看出,冒泡迴圈巢狀迴圈,有人嘗試改進,很可惜冒泡除了名字以及有趣的現象外,效率並不怎麼理想~

3、選擇排序

      時間複雜度:O(N^2)

      在亂序陣列中,假設第一位數最小,依次讓後面的數與之比較,若遇到比它小/大的數就交換位置,一趟下來第一個數就是序列中最小/最大的數,然後從第二個數開始重複操作。

     演算法步驟:

      1)首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置

      2)再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。

      3)重複第二步,直到所有元素均排序完畢。

      程式碼:

/**
 * 選擇排序演算法
 *
 * @param arr 陣列(亂序)
 * @return
 */
public static int[] selectSort(int[] arr) {
    int length = arr.length;
    for (int i = 0; i < length; i++) {
        int j = i + 1;
        for (; j < length; j++) {
            if (arr[j] < arr[i]) {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
    return arr;
}

      測試:

public static void main(String[] args) {
    int[] arr = {9, 1, 12, 5, 3, 11, 7, 8};
    System.out.println(Arrays.toString(selectSort(arr)));
}

      執行結果:

接下來,介紹最常用的排序方法:快速排序。。

4、插入排序

     時間複雜度:o(n^2)

     演算法步驟:

     1)將第一待排序序列第一個元素看做一個有序序列,把第二個元素到最後一個元素當成是未排序序列。

     2)從頭到尾依次掃描未排序序列,將掃描到的每個元素插入有序序列的適當位置。(如果待插入的元素與有序序列中的某個元素相等,則將待插入元素插入到相等元素的後面。)

     程式碼:

/**
 * 插入排序
 *
 * @param arr
 * @return
 */
public static int[] insertSort(int[] arr) {
    int length = arr.length;
    for (int i = 1; i < length; i++) {
        int temp = arr[i];
        int j = i - 1;
        for (; j >= 0 && arr[j] > temp; j--) { //j >=0 是為了排序插入的第一個元素,如果如果寫>0就會掠過第一個元素
            if (arr[j] > temp) {

            }
            arr[j + 1] = arr[j];
        }
        arr[j + 1] = temp;
    }
    return arr;
}

     測試:

public static void main(String[] args) {
    int[] arr = {9, 1, 12, 5, 3, 11, 7, 8};
    System.out.println(Arrays.toString(insertSort(arr)));
}

     執行結果:

5、希爾排序

     時間複雜度:O(n^(1+§))排序,§是介於0和1之間的常數,下界是n*log2n 

     希爾演算法在最壞的情況下和平均情況下執行效率相差不是很多,與此同時快速排序在最壞的情況下執行的效率會非常差。

     希爾排序是基於插入排序的以下兩點性質而提出改進方法的:1、插入排序在對幾乎已經排好序的資料操作時,效率高,即可以達到線性排序的效率。2、但插入排序一般來說是低效的,因為插入排序每次只能將資料移動一位。 本質上講,希爾排序演算法是直接插入排序演算法的一種改進,減少了其複製的次數,速度要快很多。 原因是,當n值很大時資料項每一趟排序需要移動的個數很少,但資料項的距離很長。當n值減小時每一趟需要移動的資料增多,此時已經接近於它們排序後的最終位置。 正是這兩種情況的結合才使希爾排序效率比插入排序高很多。

     先取一個小於n的整數d1作為第一個增量,把全部記錄分組。所有距離為d1的倍數的記錄放在同一個組中。先在各組內進行直接插入排序;然後,取第二個增量d2<d1重複上述的分組和排序,直至所取的增量。一般的初次取序列的一半為增量,以後每次減半,直到增量為1,即所有記錄放在同一組中進行直接插入排序為止。(摘自百度百科)。

     演算法步驟:

     1)選擇一個增量序列t1,t2,…,tk,其中ti>tj,tk=1;

     2)按增量序列個數k,對序列進行k 趟排序;

     3)每趟排序,根據對應的增量ti,將待排序列分割成若干長度為m 的子序列,分別對各子表進行直接插入排序。僅增量因子為1 時,整個序列作為一個表來處理,表長度即為整個序列的長度。

   程式碼:

/**
 * 希爾排序
 *
 * @param arr 陣列(亂序)
 * @return
 */
public static int[] hillSort(int[] arr) {
    int d = arr.length;//d為增量
    while (true) {
        d = d / 2;
        for (int x = 0; x < d; x++) {
            for (int i = x + d; i < arr.length; i = i + d) {
                int temp = arr[i];
                int j;
                for (j = i - d; j >= 0 && arr[j] > temp; j = j - d) {
                    arr[j + d] = arr[j];
                }
                arr[j + d] = temp;
            }
        }
        System.out.println(Arrays.toString(arr));
        if (d == 1) {
            break;
        }
    }
    return arr;
}

   測試:

public static void main(String[] args) {
    int[] arr = {9, 1, 12, 5, 3, 11, 7, 8};
    System.out.println("排序中:");
    int[] hillSort = hillSort(arr);
    System.out.println("排序後:");
    System.out.println(Arrays.toString(hillSort));
}

   執行結果:

6、快速排序(效率不錯,但是不穩定)

     時間複雜度:平均為O(nlogn),最好為O(nlogn),最差為O(logn2)

     演算法步驟:

     1 )從數列中挑出一個元素,稱為 “基準”(pivot),

     2 )重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)在這個分割槽退出之後,該基準就處於數列的中間位置。這個稱為分割槽(partition)操作。

     3) 遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。遞迴的最底部情形,是數列的大小是零或一,也就是永遠都已經被排序好了。雖然一直遞迴下去,但是這個演算法總會退出,因為在每次的迭代(iteration)中,它至少會把一個元素擺到它最後的位置去。

     這裡我們使用陣列的方式(即下標移動),至於連結串列方式,有機會補充。假如,我們要對6 1 2 7 9 3 4 5 10 8 進行從大到小排序。首先在這個序列中選擇一個基準數(做參照用),為了解釋方便,我們娶一個最左邊的數:6,作為基準數把。接下來,將比6小的放在6的右邊,將比6大的放在6的左邊。怎麼做,才能效率高呢?

    方法其實很簡單,從陣列兩端開始,先從右往左找一個比6大的數,從左往右找一個比6小的數,然後這兩個數交換。。可以用兩個變數i,j分別指向陣列的最左邊和最右邊,我們為它們分別起個名字“哨兵i”和“哨兵j”,剛開始,讓哨兵i指向陣列最左邊(i=0)的位置,指向的值為6,哨兵j指向陣列最右邊的位置(j=n-1),指向的值為8。。現在,哨兵j從右往左找比6大的數(注意,必須是哨兵j先走,即j--,這是因為我們的基準值設在左邊,原因自己體會),滿足要求後,停下,,接下來,哨兵i從右往左找比6小的數,滿足要求,停下來,,此時兩者的值進行交換。。當哨兵j與哨兵i相遇時,一輪結束,,什麼情況下相遇呢?比如哨兵j一直j--,指到了3,然後停下,,哨兵i找啊找,找到3後,還是沒有找到比6大的,此時,一輪探測就結束了,,需要將最左側的6與3互換位置。。。

    第一次交換7 5 交換,得到:

        6 1 2 5 9 3 4 7 10 8

    第二次9 4 交換,得到:

        6 1 2 5 4 3 9 7 10 8

    第三次:沒有第三次了,,哨兵j指向3,但是哨兵i已經沒有指向了,,會與哨兵j相撞!之後,將6 和 3 互換,得到:

        3 1 2 5 4 6 9 7 10 8

    然後,在6的左側,取3為基準,重複上面的操作,,在6的右側,以8為基準,重複上面的操作。。細心的同學可能已經發現,快速排序的每一輪處理,其實就是將這一輪的基準值歸位,直到所有的值都歸位為止,排序就結束了!

程式碼:

/**
 * 快速排序
 *
 * @param arr 陣列(亂序)
 * @param left 陣列左端下標
 * @param right 陣列右端下標
 * @return
 */
public static int[] quickSort(int[] arr, int left, int right) {
    int i, j, t, temp;
    if (left > right) {
        return arr;
    }
    System.out.println(Arrays.toString(arr));
    temp = arr[left];//temp即基準數
    i = left;
    j = right;
    while (i != j) {
        //順序很重要,先從右往左找
        while (arr[j] >= temp && i < j) {
            j--;
        }
        while (arr[i] <= temp && i < j) {
            i++;
        }
        if (i < j) {//哨兵i與j沒有相遇時
            t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;
        }
    }
    //基數歸位
    // temp = arr[left];
    arr[left] = arr[i];
    arr[i] = temp;

    //遞迴
    quickSort(arr, left, i - 1);
    quickSort(arr, i + 1, right);
    return arr;
}

測試:

public static void main(String[] args) {
    int[] arr = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8};
    System.out.println("排序中:");
    int[] quickSort = quickSort(arr, 0, 9);
    System.out.println("排序後:");
    System.out.println(Arrays.toString(quickSort));
}

執行結果:

7、堆排序

      時間複雜度:平均時間複雜度為Ο(nlogn)

      演算法步驟:

      1)建立一個堆H[0..n-1]

      2)把堆首(最大值)和堆尾互換

      3)把堆的尺寸縮小1,並呼叫shift_down(0),目的是把新的陣列頂端資料調整到相應位置

      4) 重複步驟2,直到堆的尺寸為1

      這裡的堆是一種資料結構,它可以被視為一種完全二叉樹,即樹裡面除了最後一層其他層都是填滿的。值得注意的是,這裡的左子節點不需要一定小於右子節點,因為我們只需要保證子節點的父節點一直是三者中的最大值就可以了。在這個類似完全二叉樹的結構裡,裡面每個節點的子女和雙親節點的序號都可以根據當前節點的序號直接求出。Parent(i)=i/2;Left(i)=2*i;Right(i)=2*i+1堆排序裡有最大堆和最小堆的概念,即根節點是最大值或者是最小值。。如果想要的是升序那就使用最大堆,反之使用最小堆。

這裡分析最大堆的方式,關鍵地方為兩部分,一是構建最大堆、二是進行堆排序。

(1)構建最大堆

      現在有一個數組A,大小是n,假設其中元素按照完全二叉樹的方式排列。
      首先我們知道最大堆的每個子樹都符合最大堆的性質(根節點值大於所有子節點)。同時序號為[(n/2+1),n]的元素都是葉子節點,由於葉子節點沒有子節點,所以葉子節點一定是裡三者之間的最大值(已滿足最大堆性質)。因此我們構建最大堆的操作就在序號為[1,n/2]的元素內進行。

      我們定義如下操作MaxNode(i):將以i位置節點為根的子樹改造成最大堆。對於每個節點i,如果他比某個子女節點小,則將他與子女節點中最大的那個互換位置,然後在相應的子女節點位置重複操作,直到到達堆的葉子節點或者考察的位置比子女節點的值都要大為止。由此可知我們構造最大堆buildmaxheap的過程就是在每個非葉子節點上呼叫MaxNode過程,依次到樹的根部,此時其左右子樹都是最大堆,即完成了最大堆的構造。

(2)堆排序:

      從根節點開始操作,因為在構造最大堆完成後根節點是這個陣列中最大的元素,因此我們將其於陣列中最後一個元素對換(排序後,最大元素應該在最後)將heapsize減1,然後再在根節點出呼叫maxify過程將新的堆重新最大堆化。依次迴圈n,我們每次都能將現有堆中最大的元素放到堆末尾。最後就完成了整個排序過程。

程式碼:

package me.ele;

import java.util.Arrays;

/**
 * @author LZJ
 * @create 2018-09-29 12:58
 **/
public class MaxHeapSort {
    int[] heap;

    private int heapsize;

    public MaxHeapSort(int[] array) {
        this.heap = array;
        this.heapsize = heap.length;
    }

    /**
     * 構造最大堆
     */
    public void BuildMaxHeap() {
        for (int i = heapsize / 2; i > 0; i--) {
            System.out.println("------------");
            System.out.println("非子節點位置:" + (i));
            //從最後一個非葉子節點開始,依次向上將當前子樹最大堆化
            MaxNode(i);
        }
    }

    /**
     * 堆排序
     */
    public void HeapSort() {
        for (int i = 1; i <= heap.length; i++) {
            //執行n次,將每個當前最大的值放到堆末尾
            int tmp = heap[0];
            heap[0] = heap[heapsize - 1];
            heap[heapsize - 1] = tmp;
            heapsize--;
            //從跟節點開始
            MaxNode(1);
        }
    }

    /**
     * 遞迴exchange 最大值和i位置的值
     *
     * @param i 第幾個元素,i-1對應陣列heap裡的下標,比如根節點為i=1 heap對應的是0
     */
    public void MaxNode(int i) {
        System.out.println("根節點位置:" + i + ",值:" + heap[i - 1]);
        int left = getLeftPosition(i);
        System.out.println("左子節點位置:" + (left));
        int right = getRightPosition(i);
        System.out.println("右子節點位置:" + (right));

        int largest_position;
        if (left <= heapsize && heap[left - 1] > heap[i - 1]) {
            largest_position = left;
        } else {
            largest_position = i;
        }
        if (right <= heapsize && heap[right - 1] > heap[largest_position - 1]) {
            largest_position = right;
        }
        if (largest_position == i || largest_position > heapsize) {//如果largest等於i說明i是最大元素 largest超出heap範圍說明不存在比i節點大的子女
            System.out.println(i + "位置,已經不存在比自己值還大的子節點了,最大值就是他自己。。。");
            return;
        } else {
            System.out.println("三個節點中的最大值的位置:" + (largest_position) + ",開始交換位置");
        }
        //交換i與largest對應的元素位置,在largest位置遞迴呼叫MaxNode
        exChange(heap, i - 1, largest_position - 1);

        System.out.println("-------------");
        MaxNode(largest_position);
    }

    /**
     * 獲取 i 節點的副節點位置
     *
     * @param i
     * @return
     */
    private int parent(int i) {
        return (i) / 2;
    }

    /**
     * 獲取 i 節點的左子節點的位置
     *
     * @param i
     * @return
     */
    private int getLeftPosition(int i) {
        return 2 * (i);
    }

    /**
     * 獲取 i 節點的右子節點的位置
     *
     * @param i
     * @return
     */
    private int getRightPosition(int i) {
        return 2 * (i) + 1;
    }

    /**
     * 交換 陣列中元素
     *
     * @param arr
     * @param position1
     * @param position2
     */
    private void exChange(int[] arr, int position1, int position2) {
        int temp = arr[position1];
        arr[position1] = arr[position2];
        arr[position2] = temp;
    }

    /**
     * 列印 樹的結構
     *
     * @param array
     */
    public void printHeapTree(int[] array) {
        int length = array.length;
        for (int i = 1; i < length; i = i * 2) {
            int v = (int) (Math.log(i) / Math.log(2)) + 1;
            for (int k = i - 1; k < 2 * i - 1 && k < length; k++) {
                System.out.print(array[k] + "\t");
            }
            System.out.println();
        }
    }

    public void printHeap(int[] array) {
        System.out.println(Arrays.toString(array));
    }

}

測試:

package me.ele;

/**
 * @author LZJ
 * @create 2018-09-29 14:59
 **/
public class MaxHeapTest {
    public static void main(String[] args) {
        int[] array = new int[]{70, 60, 12, 40, 30, 8, 10};

        MaxHeapSort heap = new MaxHeapSort(array);
        System.out.println("================== 執行構建最大堆前堆的結構:==================");
        heap.printHeapTree(heap.heap);

        //構造最大堆
        System.out.println("================== 構建最大堆前堆        :==================");
        heap.BuildMaxHeap();
        System.out.println("================== 執行構建最大堆後堆的結構:==================");
        heap.printHeapTree(heap.heap);

        //堆排序
        System.out.println("================== 堆排序               :==================");
        heap.HeapSort();
        System.out.println("================== 執行堆排序後陣列的內容 :==================");
        heap.printHeap(heap.heap);

    }

}

執行結果:

(1)直接列印陣列內容(分層列印)

(2)執行初始化(構造)最大堆

(3)初始化最大堆後,進行堆排序(這裡省略初始化最大堆的log顯示)

二、二分查詢和折半插入

1、二分查詢

      二分查詢又稱折半查詢,它是一種效率較高的查詢方法。但是,折半查詢要求線性表必須採用順序儲存結構,而且表中元素按關鍵字有序排列。演算法複雜度為:最好的情況是當匹配的位置剛好是二分位置即,O(log2n),最壞的情況是O(n)。

      假如一個遞增的int陣列,現在想要確定v alue在陣列中的位置,首先獲取middle下表,再獲取arr[middle]的值,如果value小於中間值,則在前半部分尋找;如果value大雨中間值,則在後半部分尋找。

    (1)while迴圈方式:

/**
 * 二分查詢_while
 * 
 * @param arr 陣列(已經排好序)
 * @param value 目標值
 * @return 目標值在陣列中的下標 -1表示不存在
 */
public static int binarySearch(int[] arr, int value) {
    int start = 0;
    int end = arr.length - 1;
    while (start < end) {
        int middleIndex = (start + end) / 2;
        if (value == arr[middleIndex]) {
            return middleIndex;
        } else if (value < arr[middleIndex]) {
            end = middleIndex - 1;
        } else {
            start = middleIndex + 1;
        }
    }
    return -1;
}

    (2)遞迴巢狀方式:

/**
 *
 * @param arr 陣列(已經排好序)
 * @param value 目標值
 * @param start arr的起始位置
 * @param end 。。。
 * @return 目標值在陣列中的下標 -1表示不存在
 */
public static int binarySearchByRecursive(int[] arr, int value, int start, int end) {
    int middleIndex = (start + end) / 2;
    if (value < arr[start] || value > arr[end] || start > end) {
        return -1;
    }
    if (value == arr[middleIndex]) {
        return middleIndex;
    }
    if (value < arr[middleIndex]) {
        end = middleIndex - 1;
    } else if (value > arr[middleIndex]) {
        start = middleIndex + 1;
    }
    return binarySearchByRecursive(arr, value, start, end);
}

    (3)測試:

public static void main(String[] args) {
    int[] arr = {1, 3, 4, 5, 6, 7, 9, 11};
    System.out.println(binarySearch(arr, 5));
    System.out.println(binarySearch(arr, 2));
    System.out.println("===========");
    System.out.println(binarySearchByRecursive(arr, 5, 0, arr.length - 1));
    System.out.println(binarySearchByRecursive(arr, 2, 0, arr.length - 1));

}

    (4)執行結果:

2、折半插入

      時間複雜度:和二分查詢一樣,最好的情況是O(log2n),最壞的情況是O(n)。

      將i 一個亂序的int陣列進行排序:把n個待排序的元素看成一個有序表和一個無序表,開始時有序表中只有一個元素,無序表中有n-1個元素;排序過程即每次從無序表中取出第一個元素,將它插入到有序表中,使之成為新的有序表,重複n-1次完成整個排序過程。與直接插入演算法的區別在於:在有序表中尋找待排序資料的正確位置時,使用了折半查詢/二分查詢。而傳統的直接插入排序,則是移動,即必須從最後一個記錄開始,向後移動一位,再移動倒數第2位,直到要插入的位置的記錄移後一位。

    (1)程式碼:

/**
 * 折半插入排序
 * 
 * @param arr
 * @return
 */
public static int[] binaryInsertSort(int[] arr) {
    int number = arr.length;
    int i, j;
    for (i = 1; i < number; i++) {
        //temp為本次迴圈待插入有序列表中的數
        int temp = arr[i];
        int low = 0;
        int high = i - 1;
        //使用二分查詢法尋找temp插入有序列表的正確位置
        while (low <= high) {
            //有序陣列的中間座標,此時用於二分查詢,減少查詢次數
            int mid = (low + high) / 2;
            if (arr[mid] > temp) {
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        for (j = i - 1; j >= low; j--) {
            //元素整體後移,為插入temp做準備
            arr[j + 1] = arr[j];
        }
        //插入temp
        arr[low] = temp;
        //列印每次迴圈的結果
        System.out.println(Arrays.toString(arr));
    }
    //列印排序結果
    System.out.println(Arrays.toString(arr));
    return arr;
}

    (2)測試:

public static void main(String[] args) {
    int[] arr1 = {9, 1, 12, 5, 3, 11, 7, 8};
    System.out.println("排序中:");
    int[] binaryInsertSort = binaryInsertSort(arr1);
    System.out.println("排序後:");
    System.out.println(Arrays.toString(binaryInsertSort));
}

    (3)執行結果:

三、遞迴演算法

遞迴演算法的概念就不多說了,雖然效率很低,但是挺常用的

案例1、遍歷資料夾下的所有指定字尾名的檔案,返回List集合

/**
 * 獲取某資料夾下的所有檔案
 * @param file
 * @param allfilelist
 * @return
 */
public static List<File> getAllSubFile(File file, List<File> allfilelist) {
    if (file.exists()) {
        //判斷檔案是否是資料夾,如果是,開始遞迴
        if (file.isDirectory()) {
            File[] listFiles = file.listFiles();
            if (listFiles != null){
                for (File subFile : listFiles) {
                    getAllSubFile(subFile, allfilelist);
                }
            }
        } else {
            allfilelist.add(file);
        }
    }
    return allfilelist;
}
public static void main(String[] args) {
    //test
    List<File> resultFiles = new ArrayList<>();
    List<File> allSubFiles = new ArrayList<>();
    allSubFiles = getAllSubFile(new File("XXX"), allSubFiles); // XXX為資料夾路徑
    allSubFiles.forEach(file -> {
        String absolutePath = file.getAbsolutePath();
        if (absolutePath.endsWith("xx")) {// xx為字尾名
            resultFiles.add(file);
        }
    });
}

案例2、獲取json 中所有的key和value,返回map<key,value>

/**
 * @param jsonStr 字串
 * @return 原生JsonObject 驗證字串是否滿足json格式
 */
public boolean isJsonObject(String jsonStr) { 
    boolean isJson = true;
    try {
        JSONObject jsonObject = JSONObject.fromObject(jsonStr);
        if (jsonObject.isNullObject()) {
            isJson = false;
        }

    } catch (Exception e) {
        isJson = false;
    }
    return isJson;
}
/**
 * 獲取json串,如args中所有的key和value
 * @param jsonObject 獲取json中某個key對應值的集合
 */
public Map<String, String> getKeysAndValues(JSONObject jsonObject, Map<String, String> map) {
    if (isJsonObject(jsonObject.toString())) {
        Iterator<String> keys = jsonObject.keys();
        while (keys.hasNext()) {
            String key = keys.next();
            if (isJsonObject(jsonObject.get(key).toString())) {
                JSONObject innerObject = JSONObject.fromObject(jsonObject.get(key));
                getKeysAndValues(innerObject, map);
            } else {
                String value = jsonObject.get(key).toString();
                map.put(key, value);
            }
        }
    }
    return map;
}