快排

时间复杂度:平均时间复杂度O(nlogn),最坏时间复杂度O(n*n)
空间复杂度:O(nlogn)
参考链接https://blog.csdn.net/qq_28081081/article/details/80597455

方法一:挖坑法
原文链接:https://www.cnblogs.com/qq931399960/p/9550026.html
(下图中单词有两处拼写错误,pviot和pvoit应该为pivot)

在这里插入图片描述

public class QuickSort {
        public static void main(String[] args) {
            int[] arr = {12, 45, 23, 67, 7, 1, 5, 21};
            quickSort(arr, 0, arr.length - 1);
            System.out.println(Arrays.toString(arr));
        }

        public static void quickSort(int[] numbers, int low, int high) {
            if (low >= high) {
                return;
            }
            int middle = getMiddle(numbers, low, high); // 将numbers数组进行一分为二
            quickSort(numbers, low, middle - 1); // 对低字段表进行递归排序
            quickSort(numbers, middle + 1, high); // 对高字段表进行递归排序
        }

        /**
         * 查找出中轴(默认是最低位low)的在numbers数组排序后所在位置
         *
         * @param numbers 带查找数组
         * @param low     开始位置
         * @param high    结束位置
         * @return 中轴所在位置
         */
        public static int getMiddle(int[] numbers, int low, int high) {
            int temp = numbers[low]; // 数组的第一个作为中轴
            while (low < high) {
                while (low < high && numbers[high] >= temp) {
                    high--;
                }
                numbers[low] = numbers[high];// 比中轴小的记录移到低端
                while (low < high && numbers[low] <= temp) {
                    low++;
                }
                numbers[high] = numbers[low]; // 比中轴大的记录移到高端
            }
            numbers[low] = temp; // 中轴记录到尾
            return low; // 返回中轴的位置
        }
    }

在这里插入图片描述
方法二:左右指针法:
原文链接:https://www.cnblogs.com/qq931399960/p/9550026.html
在这里插入图片描述

import java.util.Arrays;
public class QuickSort {
    public static void main(String[] args) {
        int[] arr = { 12, 45, 23, 67, 7, 1, 5, 21 };
        quickSortChange(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }

    public static void quickSortChange(int[] arr, int startIndex, int endIndex) {
        if (startIndex >= endIndex) {
            return;
        }

        int partitionIndex = getPartitionIndex(arr, startIndex, endIndex);
        printNumber("quickSortChange", arr);//打印
        quickSortChange(arr, startIndex, partitionIndex - 1);
        quickSortChange(arr, partitionIndex + 1, endIndex);

    }

    public static int getPartitionIndex(int[] arr, int startIndex, int endIndex) {
        int left = startIndex;
        int right = endIndex;
        int pivot = arr[startIndex];

        while (left != right) {

            // 左侧索引必须小于右侧索引,当右侧数据大于基准元素,则将右侧元素向左移动一位,继续判断,直到找到比基准元素小的数据
            while (left < right && arr[right] > pivot) {
                right--;
            }

            // 左侧索引必须小于右侧索引,当左侧数据小于等于基准元素,则将左侧元素右移一位,继续判断,直到找到比基准元素大的数据位置
            while (left < right && arr[left] <= pivot) { // 此处必须是左侧元素“小于等于”基准元素
                left++;
            }

            if (left < right) {
                // 通过以上两轮while循环,已经找到左侧大于基准元素的数据和右侧小于基准元素的数据,交换它们
                int tmp = arr[left];
                arr[left] = arr[right];
                arr[right] = tmp;
            }
        }

        // 此时right和left值是相同的,将基准元素与重合位置元素交换
        arr[startIndex] = arr[left];
        arr[left] = pivot;
        return left;
    }
}

在这里插入图片描述

第二种方法的另一种形式:
原文链接:https://winner.blog.csdn.net/article/details/47379295

数组int[] array = {12, 45, 23, 67, 7, 1, 5, 21};

首先将第一个元素选为基准点,从右端第一个元素开始扫描,找到第一个比12小的元素(5)时停止,两者交换位置{5, 45, 23, 67, 7, 1, 12, 21},然后从左端开始扫描,找到第一个比12大的元素(45)时停止,两者交换位置
{5, 12, 23, 67, 7, 1, 45, 21},周而复始,直到12找不到可交换的元素为止,至此一轮快速排序结束。
在这里插入图片描述

public class QuickSort {
        int[] array = {12, 45, 23, 67, 7, 1, 5, 21};

        public static void main(String[] args) {
            recursiveQuikSort(0, array.length - 1);
        }


        /**
         * 递归的快速排序
         *
         * @param low  数组的最小下标
         * @param high 数组的最大下标
         */
        private void recursiveQuikSort(int low, int high) {
            if (low >= high) {
                return;
            } else {
                int pivot = array[low];  //以第一个元素为基准
                int partition = partition(low, high, pivot);  //对数组进行划分,比pivot小的元素在低位段,比pivot大的元素在高位段

                printNumber("recursiveQuikSort", array);  //打印

                recursiveQuikSort(low, partition - 1);  //对划分后的低位段进行快速排序
                recursiveQuikSort(partition + 1, high);  //对划分后的高位段进行快速排序
            }
        }

        private int partition(int low, int high, int pivot) {

            while (low < high) {

                while (low < high && array[high] >= pivot) {  //从右端开始扫描,定位到第一个比pivot小的元素
                    high--;
                }
                swap(low, high);

                while (low < high && array[low] <= pivot) {  //从左端开始扫描,定位到第一个比pivot大的元素
                    low++;
                }
                swap(low, high);

            }
            return low;

        }

        /**
         * 交换数组中两个元素的数据
         *
         * @param low  欲交换元素的低位下标
         * @param high 欲交换元素的高位下标
         */
        private void swap(int low, int high) {
            int temp = array[high];
            array[high] = array[low];
            array[low] = temp;
        }
    }

算法分析
在归并排序中,我们详细推算了时间复杂度,快速排序与归并排序一样采取了分治算法,它的时间复杂度也是O(N*log2N)。

对于分治算法一般都是如此,用递归的方法把数据项分为两组,然后调用自身来分别处理每一组数据。算法实际上是以2为底,运行时间与N*log2N成正比。

对于快速排序来说,最理想的状态是随机分布的数据,即我们任意选定的枢纽处于中间位置,有一半元素小于它,有一半元素大于它。当数据时由小到大排列或者由大到小排列时,快速排序的效率最低,时间复杂度扩大为O(N2)。

选定第一个元素为枢纽实现起来确实很简单,但是当它为最大值或最小值时,快速排序的效率会严重降低。假如选中的元素为数组的中值,自然是最好的选择,但是却要遍历整个数组来确定中值,这个过程可能比排序花费的时间还长,得不偿失。折衷的方法是找到数组中的第一个、最后一个以及处于中间位置的元素,选出三者的中值作为枢纽,既避免了枢纽是最值的情况,也不会像在全部元素中寻找中值那样费时间。这种方法被称为“三项取中法”(median-of-three)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值