• 快速排序的基本实现


    基本流程:

    a.选取第一个元素作为pivot
    b0.先处理R处的元素
    b1.R处的元素与pivot比较,如果比pivot元素大,元素覆盖R位置,R左移,直到与L重合
    b2.R处的元素与pivot比较,如果比pivot元素小,元素覆盖L位置,L右移,直到与L重合
    b3.如果处理L和R处的元素没有变化时,继续前移,如果发生了元素覆盖,继续处理另一个方向(R和L)的元素
    c1.用同样的逻辑处理pivot左侧的(经过b处理过的左侧)子序列(递归)
    c2.用同样的逻辑处理pivot右侧的(经过b处理过的右侧)子序列(递归)

    这里用一副图来展示整个过程:

    思考过程中总结的要点:
    1.这个方法是void返回,所以传入的int[] array就是我们处理的对象,返回的也是这个对象,只不过是排序完成的对象。如果说是传入一个局部处理的int[] subArray,使用0,subArray.length-1进行处理的话,其实就完全没必要传入L,R了,但如此一来我们需要对Array进行不停地拼装,且在递归中,这种拼装消耗性能,且处理麻烦;
    2.L,R都是在变化的,在方法体中,排序完成后,需要对左子序列和右子序列的头尾坐标进行标记,并进行后续的处理;
    3.处理的边界就是L与R相等了,此时说明其中只有一个元素,不需要排序了;

     

    代码与一些说明:

    public class QuickSort {
    
        /**
         * 这是一个void方法,不用返回处理完的子序列,所有的操作完成了对子序列的处理与值的覆盖后,整个array自然排序完成
         *
         * @param array 待处理的数组,所有的内部递归调用的都是这个数组本身,不同的只是处理的下标区间
         * @param low   下标低位
         * @param high  下标高位
         */
        public static void quickSort(int[] array, int low, int high) {
            //如果两者相等,说明只有一个元素了。尽可能在外部判断好
            if (low >= high) {
                return;
            }
    
            //选取标定值,一般就选取左边位置的标定值
            int pivotValue = array[low];
    
            //之所以要进行赋值,是因为left与right是动态变化的,而low和high要在最后作为递归的确定边界,不能被覆盖
            int left = low;
            int right = high;
    
            //这里的的left==right其实就是循环的边界条件。达到了相等说明这一轮的处理结束
            while (left < right) {
                //如果右侧的值大于等于标定值,移动R,边界条件是L==R
                while (array[right] >= pivotValue && left < right) {
                    right--;
                }
    
                //到了这一步有两个条件,一个是右值比标定值小了,需要进行值覆盖;另一个是L==R了
                //这里将右侧的这个值付给了左侧,那么需要left++吗?其实不需要,因为天然地这个小于pivot的关系符合下一个循环
                if (array[right] < pivotValue) {
                    array[left] = array[right];
                }
    
                while (array[left] <= pivotValue && left < right) {
                    left++;
                }
                if (array[left] > pivotValue) {
                    array[right] = array[left];
                }
    
                //如果此时L==R,那么pivot就赋给array[left]或者array[right];
    
                //如果此时L<R,那么说明还有一些中间元素需要处理。即没有与pivot比较的元素还存在,
                // 那么上一步已经把大于pivot的元素放到了右侧,这里的位置将会在下一轮被右侧传入的值覆盖,所以设置什么值也无所谓了。
                if (left == right) {
                    array[left] = pivotValue;
                }
            }
    
            quickSort(array, low, left - 1);
            quickSort(array, left + 1, high);
        }
    
        public static void main(String[] args) {
            int[] array = {1, 3, 2, 44, 33, 12, 222, 32, 11, 22, 33, 12, 3, 2, 1};
            quickSort(array, 0, array.length - 1);
            System.out.println(Arrays.toString(array));
        }
    }

     加入了排序的方向:

    public class QuickSort {
    
        private Order order;
    
        /**
         * 排序方向
         */
        enum Order {
            /**
             * 默认,顺序
             */
            ASC,
            /**
             * 可选,逆序
             */
            DES;
    
            Order() {
            }
        }
    
        public QuickSort(Order order) {
            this.order = order;
        }
    
        /**
         * 可设置排序方向
         *
         * @param order
         */
        public void setOrder(Order order) {
            this.order = order;
        }
    
        /**
         * 这是一个void方法,不用返回处理完的子序列,所有的操作完成了对子序列的处理与值的覆盖后,整个array自然排序完成
         *
         * @param array 待处理的数组,所有的内部递归调用的都是这个数组本身,不同的只是处理的下标区间
         * @param low   下标低位
         * @param high  下标高位
         */
        public void quickSort(int[] array, int low, int high) {
            //如果两者相等,说明只有一个元素了。尽可能在外部判断好
            if (low >= high) {
                return;
            }
    
            //选取标定值,一般就选取左边位置的标定值
            int pivotValue = array[low];
    
            //之所以要进行赋值,是因为left与right是动态变化的,而low和high要在最后作为递归的确定边界,不能被覆盖
            int left = low;
            int right = high;
    
            //这里的的相等其实就是循环的边界条件。达到了相等说明这一轮的处理结束
            while (left < right) {
                //如果右侧的值大于等于标定值,移动R,边界条件是L==R
                right = processRights(array, pivotValue, left, right);
                left = processLeft(array, pivotValue, left, right);
    
                //如果此时L==R,那么pivot就赋给array[left]或者array[right];
                //如果此时L<R,那么说明还有一些中间元素需要处理。即没有与pivot比较的元素还存在,
                // 那么上一步已经把大于pivot的元素放到了右侧,这里的位置将会在下一轮被右侧传入的值覆盖,所以设置什么值也无所谓了。
                setPivotIfEqual(array, pivotValue, left, right);
            }
    
            if (low < left - 1) {
                quickSort(array, low, left - 1);
            }
            if (left + 1 < high) {
                quickSort(array, left + 1, high);
            }
        }
    
        private void setPivotIfEqual(int[] array, int pivotValue, int left, int right) {
            if (left == right) {
                array[left] = pivotValue;
            }
        }
    
        private int processLeft(int[] array, int pivotValue, int left, int right) {
            if (order == Order.ASC) {
                while (array[left] <= pivotValue && left < right) {
                    left++;
                }
                if (array[left] > pivotValue) {
                    array[right] = array[left];
                }
                return left;
            } else {
                while (array[left] >= pivotValue && left < right) {
                    left++;
                }
                if (array[left] < pivotValue) {
                    array[right] = array[left];
                }
                return left;
            }
        }
    
        private int processRights(int[] array, int pivotValue, int left, int right) {
            if (order == Order.ASC) {
                while (array[right] >= pivotValue && left < right) {
                    right--;
                }
    
                //到了这一步有两个条件,一个是右值比标定值小了,需要进行值覆盖;另一个是L==R了
                //这里将右侧的这个值付给了左侧,那么需要left++吗?其实不需要,因为天然地这个小于pivot的关系符合下一个循环
                if (array[right] < pivotValue) {
                    array[left] = array[right];
                }
                return right;
            } else {
                while (array[right] <= pivotValue && left < right) {
                    right--;
                }
    
                //到了这一步有两个条件,一个是右值比标定值小了,需要进行值覆盖;另一个是L==R了
                //这里将右侧的这个值付给了左侧,那么需要left++吗?其实不需要,因为天然地这个小于pivot的关系符合下一个循环
                if (array[right] > pivotValue) {
                    array[left] = array[right];
                }
                return right;
            }
        }
    
    
        public static void main(String[] args) {
            int[] array = {1, 3, 2, 44, 33, 12, 222, 32, 11, 22, 33, 12, 3, 2, 1};
            new QuickSort(Order.DES).quickSort(array, 0, array.length - 1);
            System.out.println(Arrays.toString(array));
        }
    }

  • 相关阅读:
    jQuery中.html(“xxx”)和.append("xxx")的区别和不同
    Jquery中对checkbox的各种“全选”或者“取消”功能实现(特别注意1.6+的一定不能使用attr来取属性了!用prop!)
    Jquery 中each循环嵌套的使用示例教程
    关于Jquery中的$.each获取各种返回类型数据的使用方法
    IMEI是什么? 怎样查手机串号IMEI
    linux useradd(adduser)命令参数及用法详解(linux创建新用户命令)
    linux 的useradd 命令的p选项
    Linux SSH远程文件/目录传输命令scp
    C++ 迭代器 基础介绍
    C++中map的一点疑惑...
  • 原文地址:https://www.cnblogs.com/bruceChan0018/p/15209130.html
Copyright © 2020-2023  润新知