Java/JS冒泡排序再优化,快速排序7种方式,折半查找

版权声明:版权没有,转载随意 https://blog.csdn.net/MAOZEXIJR/article/details/81986785

一、冒泡排序优化、再优化

1、简单冒泡排序

    /**
     * 冒泡排序
     */
    public static void bubbleSort() {
        int[] array = {6, 5, 4, 3, 2, 1};
        int end = array.length - 1;

        for (int i = 0; i < end; i++) {
            for (int j = 0; j < end - i; j++) {
                if (array[j] >= array[j + 1]) {//逐位比较
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                    //↑实现一次位置交换
                }
            }
            //↑冒出一个最大数
        }
    }

示例图:

 

2、冒泡排序优化

    /**
     * 冒泡排序优化
     */
    public static void bubbleSort() {
        int[] array = {-2, -1, 0, 6, 5, 4, 3, 2, 1};
        int end = array.length - 1;

        for (int i = 0; i < end; i++) {
            boolean ordered = true;//前段数字已排序

            for (int j = 0; j < end - i; j++) {
                if (array[j] >= array[j + 1]) {//逐位比较
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                    //↑实现一次位置交换

                    ordered = false;//发生位置交换,即前段数字未排序
                }
            }
            //↑冒出一个最大数

            if (ordered) {//前段数字已排序
                break;
            }
        }
    }

3、冒泡排序再优化

/**
     * 冒泡排序再优化
     */
    public static void bubbleSort() {
        int[] array = {6, 5, 4, 3, 2, 1, 7, 8, 9};
        int end = array.length - 1;

        for (int i = 0; i < array.length - 1; i++) {

            boolean ordered = true;//前段数字已排序
            int index = 0;//后段数字已排序的下标

            for (int j = 0; j < end; j++) {
                if (array[j] >= array[j + 1]) {//逐位比较
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                    //↑实现一次位置交换

                    ordered = false;//发生位置交换,即前段数字未排序
                    index = j + 1;
                }
            }
            //↑冒出一个最大数

            if (ordered) {//前段数字已排序
                break;
            }
            end = index;
        }
    }

二、快速排序7种实现方式

1、挖坑填坑法

(1)思维模型:

(2)执行流程:

1)取数组第一个数作为基准数 pivot

2)数组从右向左遍历查找 ≤pivot 的值,将找到的数与基准数对调位置

3)数组从左往右遍历查找 >pivot 的值,将找到的数与基准数对调位置

4)循环2、3步骤,当所有数字都遍历一遍后,数组被划分为3个区间:小于等于区、基准数、大于区

5)分别对小于等于区、大于区执行如上流程,直至全部排序完成

(3)代码实现: 

    /**
     * 快速排序 — 挖坑填坑法
     * 速度排名:2/6
     *
     * @param array
     * @param begin
     * @param end
     */
    public static void digAndFill(int array[], int begin, int end) {
        if (null == array || array.length < 2 || begin >= end) {
            return;
        }

        int left = begin;
        int right = end;
        int pivot = array[begin];//基准数

        while (left < right) {
            while (left < right && pivot < array[right]) {
                //从右往左遍历,在 "未知区" 筛选出一组 "大于区" 的数
                right--;
            }
            if (left < right) {
                //在 "未知区" 筛选出一个 "小于等于区" 的数
                int temp = array[right];
                array[right] = array[left];
                array[left] = temp;

                left++;
            }

            while (left < right && array[left] <= pivot) {
                //从左往右遍历,在 "未知区" 筛选出一组 "小于等于区" 的数
                left++;
            }
            if (left < right) {
                //在 "未知区" 筛选出一个 "大于区" 的数
                int temp = array[right];
                array[right] = array[left];
                array[left] = temp;

                right--;
            }
        }

        if (begin < left) {
            digAndFill(array, begin, left - 1);//排序 "小于等于区"
        }
        if (right < end) {
            digAndFill(array, left + 1, end);//排序 "大于区"
        }
    }

2、一端挖坑一端填

(1)思维模型:

(2)执行流程:

1)取数组第一个数作为基准数 pivot,数组首位作坑("左坑")

2)数组从右向左遍历查找 ≤pivot 的值,将找到的数值填入前一步的 "左坑",并在当前位置作新坑("右坑")

3)数组从左往右遍历查找 >pivot 的值,将找到的数值填入前一步的 "右坑",并在当前位置作新坑("左坑")

4)循环2、3步骤,当所有数字都遍历一遍后,数组被划分为3个区间:小于等于区、坑、大于区

5)将基准数填入最后的坑里

6)分别对小于等于区、大于区执行如上流程,直至全部排序完成

(3)代码实现:

    /**
     * 快速排序 — 一端挖坑一端填
     * 速度排名:6/6
     *
     * @param array
     * @param begin
     * @param end
     */
    public static void sideDigSideFill(int[] array, int begin, int end) {
        if (null == array || array.length < 2 || begin >= end) {
            return;
        }

        int left = begin;//坑所在下标 或 "未知区" 首位下标
        int right = end;//"未知区" 末位下标 或 坑所在下标
        int pivot = array[begin];//基准数,开始挖 "左坑"

        while (left < right) {
            while (left < right && pivot < array[right]) {
                //从右往左遍历,在 "未知区" 筛选出一组 "大于区" 的数
                right--;
            }
            //此时 array[right] ≤pivot
            array[left] = array[right];//用 "右值" 填 "左坑",并挖 "右坑"
            left++;

            while (left < right && array[left] <= pivot) {
                //从左往右遍历,在 "未知区" 筛选出一组 "小于等于区" 的数
                left++;
            }
            //此时 array[left]>pivot
            array[right] = array[left];//用 "左值" 填 "右坑",并挖新 "左坑"
            right--;
        }

        //此时 left = right = 坑所在下标
        array[left] = pivot;//用 基准数 填 "左坑",结束挖坑

        if (begin < left) {
            sideDigSideFill(array, begin, left - 1);//排序 "小于等于区"
        }
        if (right < end) {
            sideDigSideFill(array, left + 1, end);//排序 "大于区"
        }
    }

3、两端收缩法

    /**
     * 快速排序 — 两端收缩法
     * 速度排名:3/6
     *
     * @param array
     * @param begin
     * @param end
     */
    public static void twoSideShrink(int[] array, int begin, int end) {
        if (null == array || array.length < 2 || begin >= end) {
            return;
        }

        int left = begin + 1;
        int right = end;

        int pivot = array[begin];//中枢,参考值
        while (left < right) {
            while (left < right && array[left] <= pivot) {
                left++;
            }
            while (left < right && pivot <= array[right]) {
                right--;
            }

            if (left < right) {
                int temp = array[left];
                array[left] = array[right];
                array[right] = temp;

                left++;
                right--;
            }
        }

        if (pivot <= array[right]) {
            right--;
        }
        array[begin] = array[right];//中枢调换位置
        array[right] = pivot;

        if (begin < right - 1) {
            twoSideShrink(array, begin, right - 1);//左半切片
        }
        if (right + 1 < end) {
            twoSideShrink(array, right + 1, end);//右半切片
        }

    }

4、单端二切法

    /**
     * 快速排序 — 单端二切法
     * 速度排名:5/6
     *
     * @param array
     * @param begin
     * @param end
     */
    public static void oneSide2Cut(int[] array, int begin, int end) {
        if (null == array || array.length < 2 || begin >= end) {
            return;
        }

        int left = begin;// "小于等于区" 末位下标
        int right = begin + 1;// "未知区" 首位下标

        int pivot = array[begin];//中枢,参考值
        while (right <= end) {
            if (pivot >= array[right]) {
                int temp = array[left + 1];
                array[left + 1] = array[right];
                array[right] = temp;

                left++;
                right++;
            } else {
                right++;
            }
        }

        int temp = array[begin];
        array[begin] = array[left];
        array[left] = temp;

        if (begin < left - 1) {
            oneSide2Cut(array, begin, left - 1);
        }
        if (left + 1 < end) {
            oneSide2Cut(array, left + 1, end);
        }
    }

5、三切4分法

    /**
     * 快速排序 — 三切4分法
     * 速度排名:4/6
     *
     * @param array
     * @param begin
     * @param end
     */
    public static void threeCut4Part(int[] array, int begin, int end) {
        if (null == array || array.length < 2 || begin >= end) {
            return;
        }

        int equal = begin;//"相等区" 首位下标
        int left = begin + 1;//"未知区" 首位下标
        int right = end;//"未知区" 末位下标

        int pivot = array[begin];//中枢,参考值
        while (left <= right) {
            if (pivot > array[left]) {
                int temp = array[equal];
                array[equal] = array[left];
                array[left] = temp;

                equal++;
                left++;
            } else if (pivot == array[left]) {
                left++;
            } else {//left值大于中枢
                boolean stop = false;
                while (pivot < array[right]) {
                    right--;
                    if (right < left) {
                        stop = true;
                        break;
                    }
                }
                if (stop) {
                    break;
                }

                if (pivot == array[right]) {
                    int temp = array[left];
                    array[left] = array[right];
                    array[right] = temp;

                    left++;
                    right--;
                } else {//right值小于pivot
                    array[equal] = array[right];
                    array[right] = array[left];
                    array[left] = pivot;

                    equal++;
                    left++;
                    right--;
                }
            }
        }

        if (begin < equal - 1) {
            threeCut4Part(array, begin, equal - 1);//排序 "小于区"
        }
        if (right + 1 < end) {
            threeCut4Part(array, right + 1, end);//排序 "大于区"
        }
    }

6、双轴4分法

    /**
     * 快速排序 — 双轴4片法
     * 执行速度排名:1/6
     *
     * @param array
     * @param begin
     * @param end
     */
    public static void twoPivot(int[] array, int begin, int end) {
        if (null == array || array.length < 2 || begin >= end) {
            return;
        }

        if (array[begin] > array[end]) {
            int temp = array[begin];
            array[begin] = array[end];
            array[end] = temp;
            //中枢:左小右大
        }

        int pivot1 = array[begin];//小中枢,参考值
        int pivot2 = array[end];//大中枢,参考值

        int left = begin; // "小于区"末位下标
        int middle = begin + 1;// "未知区" 首位下标
        int right = end;// "大于区" 首位下标

        while (middle < right) {
            if (pivot1 > array[middle]) {//小于 "小中枢"
                int temp = array[left + 1];
                array[left + 1] = array[middle];
                array[middle] = temp;

                left++;
                middle++;
            } else if (pivot1 <= array[middle] && array[middle] <= pivot2) {// 大小中枢之间
                middle++;
            } else {//大于"大中枢"
                boolean stop = false;
                while (array[right - 1] > pivot2) {
                    right--;
                    if (right <= middle) {
                        stop = true;
                        break;
                    }
                }
                if (stop) {
                    break;
                }

                if (pivot1 <= array[right - 1] && array[right - 1] <= pivot2) {
                    int temp = array[right - 1];
                    array[right - 1] = array[middle];
                    array[middle] = temp;

                    middle++;
                    right--;
                } else {// "未知区"首位大于pivot2,末位小于pivot1
                    int temp = array[right - 1];
                    array[right - 1] = array[middle];
                    array[middle] = array[left + 1];
                    array[left + 1] = temp;

                    left++;
                    middle++;
                    right--;
                }
            }
        }

        int temp = array[left];
        array[left] = array[begin];
        array[begin] = temp;
        left--;
        //↑ 调整"小中枢"的位置

        temp = array[end];
        array[end] = array[right];
        array[right] = temp;
        right++;
        //↑ 调整"大中枢"的位置

        if (begin < left) {
            twoPivot(array, begin, left);//排序 "小于区"
        }
        if (left + 2 < right - 2) {
            twoPivot(array, left + 2, right - 2);//排序 "中间区"
        }
        if (right < end) {
            twoPivot(array, right, end);//排序 "大于区"
        }
    }

7、二分法(JS)

    /**
     * 二分法
     * @param array
     * @returns
     */
    function binaryQuick(array) {
        if (array.length <= 1) {
            return array;
        }
        var index = Math.floor(array.length / 2);
        var center = array.splice(index, 1)[0];
        var left = [], right = [];
        for (var i = 0; i < array.length; i++) {
            array[i] < center ? left.push(array[i]) : right.push(array[i]);
        }
        return binaryQuick(left).concat([center], binaryQuick(right));
    }

三、折半查找(二分查找)

    /**
     * 二分查找
     * @param array 一维数组
     * @param low 起始index(含)
     * @param high 结束index(含)
     * @param find 查找的值
     * @returns find在数组的下标
     */
    function binarySearch(array, low, high, find) {
        if (low > high) {
            return -1;
        }
        var mid = parseInt((high + low) / 2);
        if (array[mid] == find) {
            return mid;
        } else if (array[mid] > find) {
            high = mid - 1;
            return binarySearch(array, low, high, find);
        } else if (array[mid] < find) {
            low = mid + 1;
            return binarySearch(array, low, high, find);
        }
    }

猜你喜欢

转载自blog.csdn.net/MAOZEXIJR/article/details/81986785