java 快速排序

快速排序

算法思想:

1:基于分治的思想,是冒泡排序的改进型。首先在数组中选择一个基准点(该基准点的选取可能影响快速排序的效率,后面讲解选取的方法)

2:然后分别从数组的两端扫描数组,设两个指示标志(lo指向起始位置,hi指向末尾),首先从后半部分开始,如果发现有元素比该基准点的值小,就交换lo和hi位置的值,然后从前半部分开始扫秒,发现有元素大于基准点的值,就交换lo和hi位置的值,如此往复循环,直到lo>=hi,然后把基准点的值放到hi这个位置。一次排序就完成了。

快速排序的基本思想就是从一个数组中任意挑选一个元素(通常来说会选择最左边的元素)作为中轴元素,将剩下的元素以中轴元素作为比较的标准,将小于等于中轴元素的放到中轴元素的左边,将大于中轴元素的放到中轴元素的右边。

2:以后采用递归的方式分别对前半部分和后半部分排序,当前半部分和后半部分均有序时该数组就自然有序了。

排序过程:

          

 

举例2:

经过一次排序后,可能有如下情况:

/**
 * 此时第一次循环比较结束,关键值的位置已经确定了。而且此时start和end指针重合
 * 指向的都是我们初始设置的key,此时的顺序分为以下2种情况:
 * 1:经过第一次排序 已经排好{1,5,9,12,15,16,20,23,30,45}
 * 2:经过第一次排序 前一半和后一半已经排好 但前一半是乱序的和后一半是乱序的
 * {1,9,5,12,16,15,20,23,30,45}
 * 3:经过第一次排序 前一半和后一半已经排好 前一半是正序递增的和但后一半是乱序的
 * {1,5,9,12,16,15,20,23,30,45}
 * 4:经过第一次排序 前一半和后一半已经排好 前一半是乱序的和但后一半是正序递增的
 * {1,9,5,12,15,16,20,23,30,45}
 * 那么针对以上情况,我们进行如下方式处理:
 * 下面采用递归的方式分别对前半部分(head--start)和后半部分排序(end---tail)的方式
 * 对 从head--key的前一位 和 key的后一位---tail 这2段进行递归性的调用
 */

 

错误的写法: 如果数组里有重复元素 是不起作用的,

/**
 * 快速排序的基本思想就是从一个数组中任意挑选一个元素(通常来说会选择最左边的元素)作为中轴元素,
 * 将剩下的元素以中轴元素作为比较的标准,
 * 将小于等于中轴元素的放到中轴元素的左边,
 * 将大于中轴元素的放到中轴元素的右边。
 */
public class Fast {
    public static void main(String[] args) {
        int[] a = {12,20,5,16,15,1,30,45,23,9,9,15,16};
        quickSort(a,0,a.length-1);
        for(int i = 0; i<a.length; i++){
            System.out.println(a[i]);
        }
    }

    public static void quickSort(int[] a,int head,int tail){
        int start = head;
        int end = tail;
        //拿第一个元素 当做快排的比较值
        int key = a[head];

        //直到start>=end,然后把基准点的值放到hi这个位置。一次排序就完成了
        while (start < end){
            //先从数组后面的元素 逆序的形式 和比较值key 做比较
            /**
             * 当最后的那个元素 < key元素时 数组元素不移动
             * 如果最后的那个元素 >= key元素时 移动到Key元素的左边
             * 继续比较key和倒数第二个元素 以此类推
             * (start < end):防止 比如执行到此处 数组是{1,2,2} key=1 a[2]>=1 a[1]>=1 a[0]>=1 此时再执行end--的话 数组会越界
             */
            while (a[end] > key){
                //移动end下标 让其变成倒数第二个元素 倒数第三个元素 以此类推
                end--;
            }

            /**
             * 当最后的那个元素 >= key 数组元素移动到key的左边
             * a[start]元素和a[end]元素调换位置 以此类推
             */
            if(a[end] < key){
                int temp = a[start];
                a[start] = a[end];
                a[end] = temp;
            }

            //再从数组前面的元素 正序的形式 和比较值key 做比较
            /**
             * 当最前面的那个元素 <= key时 数组元素不移动
             * 继续比较第二个元素和key 以此类推
             * (start < end):防止 比如执行到此处 数组是{1,2,2} key=2 a[0]<2 a[1]<=2 a[2]<=2 此时再执行start++的话 数组会越界
             */
            while(a[start] < key ){
                //移动start下标 让其变成正数第二个元素 正数第三个元素 以此类推
                start++;
            }

            /**
             * 如果最前面的那个元素 > key 数组元素移动 将大于key的元素 移动到key的右边 不需要判断等于
             * 因为上面 已经将=key的 移动到key的左边了 所以此处不需要再判断=key的元素
             * a[start]元素和a[end]元素调换位置 以此类推
             */
            if(a[start] > key){
                int temp = a[start];
                a[start] = a[end];
                a[end] = temp;
            }
        }

        /**
         * 此时第一次循环比较结束,关键值的位置已经确定了。而且此时start和end指针重合
         * 指向的都是我们初始设置的key,此时的顺序分为以下2种情况:
         * 1:经过第一次排序 已经排好{1,5,9,12,15,16,20,23,30,45}
         * 2:经过第一次排序 前一半和后一半已经排好 但前一半是乱序的和后一半是乱序的
         * {1,9,5,12,16,15,20,23,30,45}
         * 3:经过第一次排序 前一半和后一半已经排好 前一半是正序递增的和但后一半是乱序的
         * {1,5,9,12,16,15,20,23,30,45}
         * 4:经过第一次排序 前一半和后一半已经排好 前一半是乱序的和但后一半是正序递增的
         * {1,9,5,12,15,16,20,23,30,45}
         * 那么针对以上情况,我们进行如下方式处理:
         * 下面采用递归的方式分别对前半部分(head--start)和后半部分排序(end---tail)的方式
         * 对 从头--key的前一位 和 key的后一位---tail 这2段进行递归性的调用
         */
        //直到start>=end,然后把基准点的值放到hi这个位置。一次排序就完成了
        if(head < start-1){
            quickSort(a,head,start-1);
        }

        //直到start>=end,然后把基准点的值放到hi这个位置。一次排序就完成了
        if(end+1 < tail){
            quickSort(a,end+1,tail);
        }
    }
}

 打印结果:死循环

正确的写法:

/**
 * 快速排序的基本思想就是从一个数组中任意挑选一个元素(通常来说会选择最左边的元素)作为中轴元素,
 * 将剩下的元素以中轴元素作为比较的标准,
 * 将小于等于中轴元素的放到中轴元素的左边,
 * 将大于中轴元素的放到中轴元素的右边。
 */
public class Fast {
    public static void main(String[] args) {
        int[] a = {12,20,5,16,15,1,30,45,23,9,9,15,16};
        quickSort(a,0,a.length-1);
        for(int i = 0; i<a.length; i++){
            System.out.println(a[i]);
        }
    }

    public static void quickSort(int[] a,int head,int tail){
        int start = head;
        int end = tail;
        //拿第一个元素 当做快排的比较值
        int key = a[head];

        //直到start>=end,然后把基准点的值放到hi这个位置。一次排序就完成了
        while (start < end){
            //先从数组后面的元素 逆序的形式 和比较值key 做比较
            /**
             * 当最后的那个元素 < key元素时 数组元素不移动 
             * 如果最后的那个元素 >= key元素时 移动到Key元素的左边
             * 继续比较key和倒数第二个元素 以此类推
             * (start < end):防止 比如执行到此处 数组是{1,2,2} key=1 a[2]>=1 a[1]>=1 a[0]>=1 此时再执行end--的话 数组会越界
             */
            while (a[end] > key && (start < end)){
                //移动end下标 让其变成倒数第二个元素 倒数第三个元素 以此类推
                end--;
            }

            /**
             * 当最后的那个元素 >= key 数组元素移动到key的左边
             * a[start]元素和a[end]元素调换位置 以此类推
             */
            if(a[end] <= key){
                int temp = a[start];
                a[start] = a[end];
                a[end] = temp;
            }

            //再从数组前面的元素 正序的形式 和比较值key 做比较
            /**
             * 当最前面的那个元素 <= key时 数组元素不移动
             * 继续比较第二个元素和key 以此类推
             * (start < end):防止 比如执行到此处 数组是{1,2,2} key=2 a[0]<2 a[1]<=2 a[2]<=2 此时再执行start++的话 数组会越界
             */
            while(a[start] <= key && (start < end)){
                //移动start下标 让其变成正数第二个元素 正数第三个元素 以此类推
                start++;
            }

            /**
             * 如果最前面的那个元素 > key 数组元素移动 将大于key的元素 移动到key的右边 不需要判断等于
             * 因为上面 已经将=key的 移动到key的左边了 所以此处不需要再判断=key的元素
             * a[start]元素和a[end]元素调换位置 以此类推
             */
            if(a[start] > key){
                int temp = a[start];
                a[start] = a[end];
                a[end] = temp;
            }
        }

        /**
         * 此时第一次循环比较结束,关键值的位置已经确定了。而且此时start和end指针重合
         * 指向的都是我们初始设置的key,此时的顺序分为以下2种情况:
         * 1:经过第一次排序 已经排好{1,5,9,12,15,16,20,23,30,45}
         * 2:经过第一次排序 前一半和后一半已经排好 但前一半是乱序的和后一半是乱序的
         * {1,9,5,12,16,15,20,23,30,45}
         * 3:经过第一次排序 前一半和后一半已经排好 前一半是正序递增的和但后一半是乱序的
         * {1,5,9,12,16,15,20,23,30,45}
         * 4:经过第一次排序 前一半和后一半已经排好 前一半是乱序的和但后一半是正序递增的
         * {1,9,5,12,15,16,20,23,30,45}
         * 那么针对以上情况,我们进行如下方式处理:
         * 下面采用递归的方式分别对前半部分(head--start)和后半部分排序(end---tail)的方式
         * 对 从头--key的前一位 和 key的后一位---tail 这2段进行递归性的调用
         */
        //直到start>=end,然后把基准点的值放到hi这个位置。一次排序就完成了
        if(head < start-1){
            quickSort(a,head,start-1);
        }

        //直到start>=end,然后把基准点的值放到hi这个位置。一次排序就完成了
        if(end+1 < tail){
            quickSort(a,end+1,tail);
        }
    }
}

 输出结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值