排序

一、選擇排序

1.堆排序

定義:堆排序是利用堆這種數(shù)據(jù)結構而設計的一種排序算法,堆排序是一種選擇排序
可參考https://www.cnblogs.com/chengxiao/p/6129630
http://www.itdecent.cn/p/938789fde325

public class HeapSort {
    public static void main(String[] args) {

        /**
         * 堆排序,利用二叉樹左右節(jié)點的模式來比較
         */
        int[] a = {19, 8, 27, 6, 35, 14, 3, 12, 1, 0, 9, 10, 7};

        HeapSort heapSort = new HeapSort();
        heapSort.heapSort(a);
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }

    public void heapSort(int[] a) {
        if (a == null || a.length <= 1) {
            return;
        }

        buildMaxHeap(a);
        for (int i = a.length - 1; i > 0; i--) {
            //最大的在0位置,那么開始沉降,這樣每交換一次最大的值就丟到最后了
            exchangeElement(a, 0, i);
            //繼續(xù)獲取0位置最大值
            maxHeap(a, i, 0);

        }

    }

    /**
     * 創(chuàng)建最大堆
     *
     * @param a
     */
    private void buildMaxHeap(int[] a) {
        if (a == null || a.length <= 1) {
            return;
        }
        int half = (a.length ) / 2-1;
        for (int i = half; i >= 0; i--) {
            maxHeap(a, a.length, i);
        }

    }

    /**
     * 利用二叉樹跟、左、右節(jié)點的值進行比較,不斷的更換最大值對應的小標largest,
     * 當當前傳過來的下標與最大值的小標不想等時,兩者交換相應的位置,然后再用遞歸的方式進行查找最大,
     * 但是此時是以前面所找的最大值的小標為標準
     * @param a
     * @param length
     * @param index
     */
    private void maxHeap(int[] a, int length, int index) {
        int left = index * 2 + 1;
        int right = index * 2 + 2;
        int largest = index;
        if (left < length  && a[left] > a[index]) {
            largest = left;
        }
        if (right < length  && a[right] > a[largest]) {
            largest = right;
        }
        if (index != largest) {
            exchangeElement(a, index, largest);

            maxHeap(a, length, largest);
        }
    }

    private void exchangeElement(int[] a, int index, int largest) {
        int temp = a[index];
        a[index] = a[largest];
        a[largest] = temp;
    }

}

2,

定義:首先,找到數(shù)組中最小的那個元素,其次,將它和數(shù)組的第一個元素交換位置(如果第一個元素就是最小元素那么它就和自己交換)。再次,在剩下的元素中找到最小的元素,將它與數(shù)組的第二個元素交換位置。如此往復,直到將整個數(shù)組排序。這種方法叫做選擇排序,因為它在不斷地選擇剩余元素之中的最小者。

 public static void main(String[] args) {

       int[] a = {3, 7, 1, 5, 6, 2, 4};
        for (int i = 0; i < a.length; i++) {
            for (int j = i + 1; j < a.length; j++) {
                int temp;
                if (a[i] > a[j]) {
                    temp = a[i];
                    a[i] = a[j];
                    a[j] = temp;
                }
            }
            System.out.println(a[i]);
        }



    }

二、插入排序(適合小規(guī)模數(shù)組)

1.直接插入排序

定義:每次將一個待排序的元素與已排序的元素進行逐一比較,直到找到合適的位置按大小插入。
自己的理解:
在一個無序的數(shù)組中,首先將前兩個元素進行對比排序,然后第三個元素和第二個元素進行對比,如果第三個元素大于第二個元素,則進行下一步,將第四個元素和第三個元素對比排序;否則如果第三個元素小于第二個元素,將兩者位置互換后,再將重新排序后的第二個元素和第一個元素進行對比排序.....以此類推即可實現(xiàn)插入排序

public class InsertSort {
    public static void main(String[] args) {

        /**
         * 直接插入排序
         */
        int[] a = {9, 3, 8, 23, 86, 33, 54, 0, 1, 65, 10, -1};
        //從數(shù)組中下標為1的元素開始
        for (int i = 1; i < a.length; i++) {
            //用temp記錄當前遍歷的元素值
            int temp = a[i];
            //外部定義j,為了在break的情況下記錄j的值
            int j;
            for (j = i - 1; j >= 0; j--) {
                //如果a[j]大于當前的值,則最后一個元素需要往后移動一位,所以將a[j]的值賦值給a[j+1],
                //否則,就結束循環(huán),記錄j的值
                if (a[j] > temp) {
                    a[j + 1] = a[j];
                } else {
                    break;
                }
            }
            //break下的小標為j,值比temp小,所以temp的值需要賦值給a[j+1]
            a[j + 1] = temp;
        }

        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }
}

2.二分法插入排序

先要知道數(shù)組中的左邊、右邊以及中間的下標,然后當坐標下標小于等于右邊下標時,將要插入的數(shù)字與中間下標對應的數(shù)字進行比較,做變換左、中、右下標的循環(huán),最后以左下標為標準,將左及左后邊全部后移,當左下標的值不等于i時,左位置插入該數(shù)據(jù)。

public class BinaryInsertSort {
    public static void main(String[] args) {
        int[] a = {3, 0, 1, 90, 56, 34, 23, 76, 46, -1, 77};
        BinaryInsertSort b = new BinaryInsertSort();
        b.sort(a);
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }

    /**
     * 二分法插入排序
     *
     * @param a
     */
    public void sort(int[] a) {
        for (int i = 1; i < a.length; i++) {
            //記錄當前遍歷到的數(shù)值
            int temp = a[i];
            //定義左邊的下標
            int left = 0;
            //定義右邊的下標
            int right = i - 1;
            //初始化中間的下標
            int mid = 0;
            //循環(huán):當左邊下標小于等于右邊下標時
            while (left <= right) {
                //計算中間下標
                mid = (left + right) / 2;
                //當當前遍歷的值?大于中間小標對應的值時,變動左邊下標
                if (temp > a[mid]) {
                    left = mid + 1;
                } else {
                    //當當前遍歷的值小于中間小標對應的值時,變動右邊下標
                    right = mid - 1;
                }
            }

            //遍歷數(shù)組,以左下標為標準,讓大于等于左邊下標對應的所有的值都往后移動一位
            for (int j = i - 1; j >= left; j--) {
                if (temp < a[j]) {
                    a[j + 1] = a[j];
                }

            }

            //當左邊下標不等于遍歷的小標時(即要插入的那個數(shù)在當前排序數(shù)字中不是最大時),給左邊下標對應的數(shù)賦值
            //要插入的那個數(shù)在當前排序數(shù)字中是最大時,直接插入,不做任何操作
            if (left != i) {
                a[left] = temp;
            }
        }


    }
}

3.希爾排序

定義:希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序算法排序;隨著增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,算法便終止


希爾排序過程
public class HeerSort {
    public static void main(String[] args) {
        /**
         * 希爾排序
         */
        int[] a = {49, 38, 65, 97, 76, 13, 27, 49, 78, 34, 12, 64, 1, 33, 85, 29};
        int d = a.length / 2;   //默認增量,總長度除以2
        while (true) {
            for (int i = 0; i < d; i++) {//注意i的值是小于增量的
                for (int j = i; j + d < a.length; j += d) {//以增加作為間距
                    int temp;
                    if (a[j] > a[j + d]) {
                        temp = a[j];
                        a[j] = a[j + d];
                        a[j + d] = temp;
                    }
                }
            }
            //增量為1時結束
            if (d == 1) {
                break;
            }
            d--;
        }

        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }
}

三、快速排序

定義:是對冒泡排序的一種改進。它的基本思想是:通過一趟排序將要排序的數(shù)據(jù)分割成獨立的兩部分,其中一部分的所有數(shù)據(jù)都比另外一部分的所有數(shù)據(jù)都要小,然后再按此方法對這兩部分數(shù)據(jù)分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數(shù)據(jù)變成有序序列

public class QuickSort {
    public static void main(String[] args) {
        QuickSort quickSort = new QuickSort();
        int[] a = {19, 2, 6, 90, 67, 33, -7, 24, 3, 56, 34, 5};
        quickSort.quick(a);
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }

    public void quick(int[] a) {
        if (a.length < 0) {
            return;
        }
        quickSort(a, 0, a.length - 1);

    }

    /**
     * 快速排序
     *
     * @param a
     * @param low
     * @param high
     */
    private void quickSort(int[] a, int low, int high) {
        //獲取下標后,以該下標為基準,用迭代的方法左右兩邊都做相同的操作
         if (low < high) {
            int middle = getMiddle(a, low, high);
            quickSort(a, 0, middle - 1);
            quickSort(a, middle + 1, high);
        }
    }

    /**
     * 以數(shù)組中的一個數(shù)為基準元素,然后獲取該元素在此數(shù)組中的排序的下標
     * @param a
     * @param low
     * @param high
     * @return
     */
    private int getMiddle(int[] a, int low, int high) {
        int temp = a[low];//以下標為low的值作為基準元素
        while (low < high) {
            //從右邊開始,一個個與基準元素進行比較,大于基準元素的,high--,小于基準元素的,結束循環(huán)
            while (low < high && temp < a[high]) {
                high--;
            }
            //結束循環(huán)之后,將a[high]的值放到a[low]中,
            a[low] = a[high];

            //在從左邊開始,一個個與基準元素進行比較,小于基準元素的,low++;大于基準元素的,結束循環(huán)
            while (low < high && temp > a[low]) {
                low++;
            }
            //結束循環(huán)之后,將a[low]的值放到a[high]中,
            a[high] = a[low];
        }
        a[low] = temp;
        return low;
    }
}

四、歸并排序

定義:是一類與插入排序、交換排序、選擇排序不同的另一種排序方法。歸并的含義是將兩個或兩個以上的有序表合并成一個新的有序表;
基本思想:分而治之(divide - conquer);每個遞歸過程涉及三個步驟
第一, 分解: 把待排序的 n 個元素的序列分解成兩個子序列, 每個子序列包括 n/2 個元素.
第二, 治理: 對每個子序列分別調用歸并排序MergeSort, 進行遞歸操作
第三, 合并: 合并兩個排好序的子序列,生成排序結果.

image
public class MergeSort {
    public static void main(String[] args) {
        int[] a = new int[]{90, 3, 2, 67, 44, -9, 87, 65, 11, 9, 2, 8};
        MergeSort m = new MergeSort();
        m.mergeSort(a, 0, a.length - 1);
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }

    /**
     * 歸并排序
     * @param a
     * @param left
     * @param right
     */
    public void mergeSort(int[] a, int left, int right) {
        if (left < right) {
            int middle = (left + right) / 2;
            //將數(shù)組拆分成單個元素的多個數(shù)組
            mergeSort(a, left, middle);
            mergeSort(a, middle + 1, right);
            //逐一合并
            merge(a, left, middle, right);
        }

    }

    /**
     * 合并排好序的數(shù)組,定義一個新的數(shù)組,然后兩個數(shù)組從第一個開始進行比較,
     * 誰小就放入新的數(shù)組,同時對應的下標加或者減1,
     * @param a
     * @param left
     * @param middle
     * @param right
     */
    private void merge(int[] a, int left, int middle, int right) {
        int[] tempArray = new int[a.length];
        int rightStart = middle + 1;
        int temp = left;
        int third = left;
        //當左邊小于等于中間;右邊開始下標小于等于右邊
        while (left <= middle && rightStart <= right) {
            //從第一個元素開始逐個比較,如果左邊的值小于右邊的值,將左邊的值放在新的數(shù)組中,否則,將右邊的值放在新的數(shù)組中
            if (a[left] <= a[rightStart]) {
                tempArray[third++] = a[left++];
//                tempArray[third]=a[left];
//                third++;
//                left++;
            } else {
                tempArray[third++] = a[rightStart++];
            }
        }

        //當右邊的數(shù)組全部比較完了,但是左邊的依然還有,則將左邊剩余的元素依次放入新的數(shù)組中
        while (left <= middle) {
            tempArray[third++] = a[left++];
        }
        //當左邊的數(shù)組全部比較完了,但是右邊的依然還有,則將右邊剩余的元素依次放入新的數(shù)組中
        while (rightStart <= right) {
            tempArray[third++] = a[rightStart++];
        }

        while (temp <= right) {
            a[temp] = tempArray[temp];
            temp++;
        }


    }
}

五、基數(shù)排序

基本思路:

  • 第一:獲取數(shù)組中的最大值以及最大值的位數(shù);
  • 第二:創(chuàng)建一個多維數(shù)組,里面有十個數(shù)組,分別存放位數(shù)對應的1-10的數(shù)字;
  • 第三:遍歷原始數(shù)組,分別獲取個位、十位、百位等位對應的值,通過這個值獲取在多維數(shù)組中對應的數(shù)組,
  • 把原始數(shù)組中的這個元素添加到多維數(shù)組中對應的數(shù)組中,
  • 第四:開始收集;遍歷多維數(shù)組中的每個數(shù)組,把每個數(shù)組中的元素一個個賦值給原始數(shù)組元素,賦值一個,移除一個,同時count次數(shù)++
public class BasicSort {
    public static void main(String[] args) {
        int[] a = {136, 2, 6, 8, 9, 2, 8, 11, 23, 56, 34, 90, 89, 29, 145, 209, 320, 78, 3};
        BasicSort basicSort = new BasicSort();
        basicSort.sort(a);
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }

    /**
     * 基數(shù)排序:
     * 基本思路:
     * 第一:獲取數(shù)組中的最大值以及最大值的位數(shù);
     * 第二:創(chuàng)建一個多維數(shù)組,里面有十個數(shù)組,分別存放位數(shù)對應的1-10的數(shù)字;
     * 第三:遍歷原始數(shù)組,分別獲取個位、十位、百位等位對應的值,通過這個值獲取在多維數(shù)組中對應的數(shù)組,
     * 把原始數(shù)組中的這個元素添加到多維數(shù)組中對應的數(shù)組中,
     * 第四:開始收集;遍歷多維數(shù)組中的每個數(shù)組,把每個數(shù)組中的元素一個個賦值給原始數(shù)組元素,賦值一個,移除一個,
     * 同時count次數(shù)++
     *
     * @param a
     */
    public void sort(int[] a) {
        //獲取數(shù)組中的最大值
        int max = 0;
        for (int i = 0; i < a.length; i++) {
            if (max < a[i]) {
                max = a[i];
            }
        }

        //獲取最大值的位數(shù)
        int times = 0;
        while (max > 0) {
            max = max / 10;
            times++;
        }

        //創(chuàng)建一個多維數(shù)組
        List<ArrayList> queue = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            ArrayList q = new ArrayList();
            queue.add(q);
        }

        for (int i = 0; i < times; i++) {
            for (int j = 0; j < a.length; j++) {
                //獲取對應的位的值(i為0是各位,1是10位,2是百位)
                int x = a[j] % (int) Math.pow(10, i + 1) / (int) Math.pow(10, i);
                //通過得到的位的值獲取多維數(shù)組中對應的數(shù)組,然后將該數(shù)據(jù)添加到對應的數(shù)組中
                ArrayList q = queue.get(x);
                q.add(a[j]);
            }

            //開始收集
            int count = 0;
            //遍歷多維數(shù)組中的每個數(shù)組
            for (int j = 0; j < 10; j++) {
                while (queue.get(j).size() > 0) {
                    ArrayList<Integer> q = queue.get(j);//獲取多維數(shù)組中的單個數(shù)組
                    //將第一個值賦值給原有的數(shù)組,然后移除第一個
                    a[count] = q.get(0);
                    q.remove(0);
                    count++;

                }
            }
        }

    }
}

六、二分查找

public class BinarySearch {
    public static void main(String[] args) {
        int[] array = {10, 23, 4, 3, 2, 5, 1, 2, 623, 92, 23, 23, 234, 2, 34, 234, 234, 2, 10};
        BinarySearch binarySearch = new BinarySearch();
        BasicSort basicSort = new BasicSort();
        basicSort.sort(array);
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + "---");
        }
//        binarySearch.binarySearch(5, array, 0, array.length - 1);
        binarySearch.directBinarySearch(array,5);


    }

    /**
     * 遞歸查找(二分查找)
     *
     * @param elem
     * @param array
     * @param low
     * @param high
     * @return
     */
    public int binarySearch(int elem, int[] array, int low, int high) {
        if (low > high) {
            return -1;
        }
        int middle = (low + high) / 2;
        if (elem < array[middle]) {
            //找左邊
            return binarySearch(elem, array, low, middle - 1);
        } else if (elem > array[middle]) {
            //找右邊
            return binarySearch(elem, array, middle + 1, high);
        } else if (elem == array[middle]) {
            System.out.print("-------" + middle);
            return middle;
        } else {
            return -1;
        }

    }

    /**
     * 非遞歸查找
     * @param array
     * @param elem
     * @return
     */
    public int directBinarySearch(int[] array, int elem) {
        int low = 0;
        int high = array.length - 1;
        while (low <= high) {
            int middle = (low + high) / 2;
            if (elem < array[middle]) {
                high = middle - 1;
            } else if (elem > array[middle]) {
                low = middle + 1;
            } else if (elem == array[middle]) {
                System.out.print("-------" + middle);
                return middle;
            }
        }
        return -1;
    }
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容