排序算法筆記

以下代碼均整理自互聯網。

快排:// 見筆記本 10頁快排的思路
public class Code_04_QuickSort {

    public static void quickSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        quickSort(arr, 0, arr.length - 1);
    }

    public static void quickSort(int[] arr, int l, int r) {
        if (l < r) {
            //隨機選一個位置的數與最後位置交換,形成隨機快排。
            //  l + (int) (Math.random() * (r - l + 1)) 表示在l和r之間隨機選一個數
            swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
            //不要上一行就是經典快排
            int[] p = partition(arr, l, r); //partiton劃分的意思,這個是荷蘭國旗問題
            quickSort(arr, l, p[0]);
            quickSort(arr, p[1], r);
            //進來一組數據,分成左邊一坨小於它,右邊一坨大於它,然後對左邊一坨,中間等於的一坨
            //左邊分出的一坨又重新這樣做(因爲同樣的問題,所以調用自己),右邊分出來的一坨也這樣做,
            // 所以遞歸多了後面那兩個quikSort
            //後面再本程序開頭加上遞歸終止條件即可。歸併排序也是這樣的,只不過後面多了歸併的部分。
        }
    }

    public static int[] partition(int[] arr, int l, int r) {
        int less = l - 1;
        int more = r;//因爲是用最後一個數作爲基準數的,所以這裏是r,後面記得把這個基準數
            // 放到中間相等的部分,且more是中間相等部分的上一個數,自己可以找兩個數想一想。
        while (l < more) {   //因爲l有時候找到比他大的數是不走的,所以只能用while。
            if (arr[l] < arr[r]) {  //l後續不會交換,所以用來做遍歷下標
                swap(arr, ++less, l++); //這裏一定要小心
            } else if (arr[l] > arr[r]) {
                swap(arr, --more, l);//這裏一定要小心,l是不動的
            } else {
                l++;
            }
        }
        swap(arr, more, r); //最後一位還是與中間相等的數,所以要交換到中間去。
        //more就是相等數的最後一位,但是less是中間相等數的前一位,下一步返回邊界要小心
        return new int[] { less, more+1 };  //返回中間相等的上下邊界,返回回去後面直接對左右部分同樣處理。
    }

    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    public static void main(String [] args) {
        System.out.println("hello");
        int [] arr = new int [] {5,6,8,31,2};
        quikSort(arr,0,arr.length-1);
        for (int i = 0; i<arr.length; i++) {
            System.out.print(arr[i]);
            System.out.print(" ");
        }
    }

}
插入排序:筆記本第4public class insertSort {
    public static void insertSort(int[] arr) {
        if(arr.length<2||arr==null) return ;
        for(int i = 1; i<arr.length; i++) {
            for(int j = i-1; j>-1 && arr[j+1]<arr[j]; j--)//關鍵的地方在於這兒
//              核心思路和打牌一樣,當前元素和前一個比,小就交換,交換後還要比較,所以j和j+1比,這裏是關鍵
                swap(arr,j+1,j);

        }
    }
    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    public static void main(String[] args) {
        int[] p = new int [] {1,5,9,3,66,8,4,3};
        insertSort(p);
        for(int i = 0; i<p.length;i++) {
            System.out.print(p[i]);
            System.out.print(" ");
        }
    }
}
歸併排序:筆記本第6頁
import java.util.Arrays;
public class mergeSort {
    public static void mergeSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        mergeSort(arr, 0, arr.length - 1);
    }

    public static void mergeSort(int[] arr, int l, int r) {
        if (l == r) {
            return;
        }
        int mid = l + ((r - l) >> 1);//l,r中點的位置,這樣寫是爲了防止溢出。
        mergeSort(arr, l, mid);
        mergeSort(arr, mid + 1, r);  //左右兩邊排好序
        merge(arr, l, mid, r);    //對進來的數組進行前後半部分進行重組 
        // 這一步必須寫在最後,因爲從底部開始合併,然後合併上一步,即對數組的兩半部分進行類似樹的後續遍歷一樣
        // 這樣做的原因是,本層進行合併的時候,在merge前是要保證左半部分和右半部分是排好序的,所以是後續遍歷
        // 這一步也是劍指offer有道題是將兩個排序好的鏈表合併爲一個鏈表。


        // 和剛剛快排很類似,進來一個數組,切成左邊一組,右邊一組,只要還可以切,
        // 就繼續切(所以有了後兩步mergesort),直到不能切返回,後面多了merge步驟。
    }  

    public static void merge(int[] arr, int l, int m, int r) {
        int[] help = new int[r - l + 1];//如{3,2,4},l是0,r是2進來,長度是2-0+1=3,所以長度要分好
        int i = 0;
        int p1 = l;
        int p2 = m + 1; //用兩個指針去掃描數組的前後部分
        while (p1 <= m && p2 <= r) {
            help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
        }
        // 下面兩個循環表示誰走完後,另一個數組直接複製後面的內容。
        while (p1 <= m) {   
        // 這裏和下面的循環自己寫的時候沒寫等號,錯了想了很久。因爲上面截止後,還會自加,所以會超出原邊界,依次作爲判斷條件。
            help[i++] = arr[p1++];
        }
        while (p2 <= r) {
            help[i++] = arr[p2++];
        }
        // 複製回去
        for (i = 0; i < help.length; i++) {
            arr[l + i] = help[i];   //一定注意下標要對應原始數組的下標
        }
    }
    public static void main(String[] args) {
        int[] p = new int [] {1,5,9,3,66,8,4,3};
        mergeSort(p);
        for(int i = 0; i<p.length;i++) {
            System.out.print(p[i]);
            System.out.print(" ");
        }
    }
}
冒泡排序:
public class maopao {
    public static void bubbleSort(int[] arr) {
        if(arr==null||arr.length<2) return ;
        for(int i = 0; i<arr.length;i++) {
            //每一趟將最大的數放到最後,且下一趟會比上一趟少一個數比較(其實最後一趟沒有必要,因爲就他一個人)
            for(int j = 0;j<arr.length-1-i;j++) {
                if (arr[j]>arr[j+1])
                    swap(arr,j+1,j);
            }
        }
    }
    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    public static void main(String[] args) {
        int[] p = new int [] {1,5,9,3,66,8,4,3};
        bubbleSort(p);//bubble冒泡
        for(int i = 0; i<p.length;i++) {
            System.out.print(p[i]);
            System.out.print(" ");
        }
    }

}
選擇排序:
import java.util.Arrays;

public class Code_02_SelectionSort {

    public static void selectionSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        for (int i = 0; i < arr.length - 1; i++) {  //因爲j=i+1
            int minIndex = i;
            // 從0位置開始,每一趟找一個最小的數,放在該趟對應的下標處
            for (int j = i + 1; j < arr.length; j++) {
                minIndex = arr[j] < arr[minIndex] ? j : minIndex; 
                 //記錄最小位置的下標,這樣減少交換次數。
            }
            swap(arr, i, minIndex);  //這一趟走完,才把這一趟對應位置的數換成後半部分最小的數。
        }
    }

    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
        public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    public static void main(String[] args) {
        int[] p = new int [] {1,5,9,3,66,8,4,3};
        selectionSort(p);//bubble冒泡
        for(int i = 0; i<p.length;i++) {
            System.out.print(p[i]);
            System.out.print(" ");
        }
    }
}
堆排序:筆記本11頁
import java.util.Arrays;

public class Code_03_HeapSort {
    // 將數組排序轉換爲二叉樹形式,然後通過大根堆調整得到數組的排序
    public static void heapSort(int[] arr) {
        //第一步判斷數組
        if (arr == null || arr.length < 2) {
            return;
        }
        //第二步建立大根堆:heapInsert
            // 遍歷每一個節點,如果比父節點大,則交換--->建立大根堆
        for (int i = 0; i < arr.length; i++) {
            heapInsert(arr, i);
        }
        // 第三步:大根堆只保證父比子大,無法保證左右,所以通過不斷的讓父節點去堆尾節點,然後調整實現排序
        int size = arr.length;
        swap(arr, 0, --size);  //頭尾交換 (不可以和while合併寫循環第一條?)
        while (size > 0) {
            heapify(arr, 0, size);   //調 大根堆 
            swap(arr, 0, --size);    // 頭尾交換,並尾部往前移
        }
    }

    public static void heapInsert(int[] arr, int index) {
        while (arr[index] > arr[(index - 1) / 2]) {  //若比父節點大則交換,(index - 1) / 2當前節點的父節點
            // 和插入一樣,交換後也許還是大,所以要一直交換,知道不用交換爲止
            swap(arr, index, (index - 1) / 2);
            index = (index - 1) / 2;
        }
    }
    // 每次將大根堆放到尾部後,頭結點是比較小的,然後頭結點和子節點的交換,一直交換到上一步最尾部的上一個數
    public static void heapify(int[] arr, int index, int size) {
        int left = index * 2 + 1;
        while (left < size) {   //看是否越界在葉子節點上
            // left + 1 就是右孩子,下一句是右孩子不越界,且三目運算返回最大孩子的下標
            // 若右節點越界則返回左結點的值(即沒有右節點)
            int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
            // 這一句是我和孩子誰大(上一步找到最大的孩子下標),誰大下標給largest
            largest = arr[largest] > arr[index] ? largest : index;
            // if條件表示,節點變小後但仍然比孩子都大,則不用往下沉
            if (largest == index) {   
                break;
            }
            swap(arr, largest, index);
            index = largest;  //頭結點變大後,交換的節點還要繼續往下沉,讓頭結點=index
            left = index * 2 + 1;
        }
    }

    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    public static void main(String[] args) {
        int[] p = new int [] {1,5,9,3,66,8,4,3};
        heapSort(p);//bubble冒泡
        for(int i = 0; i<p.length;i++) {
            System.out.print(p[i]);
            System.out.print(" ");
    }
}

面試常考的常用數據結構與算法:https://blog.csdn.net/zwj1030711290/article/details/70224852

https://www.cnblogs.com/onepixel/articles/7674659.html 排序算法這個上面總結的很好。
排序算法的一點點應用-海量數據處理,這個總結的好:
https://blog.csdn.net/v_JULY_v/article/details/7382693

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章