排序算法:交换排序之快速排序

介绍

1.快速排序属于交换排序(如果发现元素次序相反,则交换元素位置),而交换排序是属于内排序一种,内排序即所有数据都存在内存中,与外排序不一样,这个后续文章再说。
2.快速排序采用分而治之的思想,每次找到一个元素,将所有元素与之对比,将小于该元素的元素放在左边,大于则放在右边(方向可以不同,这里只是举个例子),这样再从左边的这堆元素中,按照刚刚同样的方法操作,右边也同样,就这样一直递归下去,这样就能每次固定住一个数的位置,当分不下去的时候,所有元素就变成有序的了

分析

假设有一个数组[6, 1, 2, 7, 9, 3, 4, 5,10,8],我们来看看快速排序如何实现这一过程,我们选择始终第一个元素作为基准数:
[6, 1, 2, 7, 9, 3, 4, 5,10,8]
将元素6归位
[5, 1, 2, 4, 3, 6, 9, 7, 10, 8]
元素6左边的数组序列,将元素5归位
[3, 1, 2, 4, 5]
元素5左边的数组,将元素3归位
[2, 1, 3, 4]
元素3左边的数组,将元素2归位
[1, 2]
这里采用实际上递归(实际上这一步返回后需要归位元素3右边的元素,但是这里只有一个4,因此不会做任何交换,如果不明白,递归需要了解一下,大兄弟),这样,将元素6左边的元素全部归位,即
[1, 2, 3, 4, 5, 6, 9, 7, 10, 8]
接下来对元素6右边的元素进行递归归位,这样最后会获得排好序的数组

代码

接下来就上代码,这里有个问题其实就是基准值得选定,我们这里每次选择第一个作为基准值

public class QuickSort {
    public void quickSort(int[] nums, int start, int end) {
        // 创建两个游标,i,j,初始值分别数组开头下标值,数组结尾下标值
        int i = start;
        int j = end;

        if (start < end) {
            // 保存基准值
            int temp = nums[i]; 
            // 向数组中间扫描,判断是否全部扫描完毕,没有就继续循环
            while (i < j) {
                // 这里的意思就是当nums[j]小于基准值时,将nums[i] 和nums[j]交换,否则减小游标,
                //这里稍微难以理解,其实就是将小于基准值得元素放到左边,
                //由于基准值被保存,所以覆盖基准值不会导致数据丢失
                while (i < j && nums[j] >= temp) j--;
                nums[i] = nums[j];
                // 将大于基准值的元素放到右边,若小于等于基准值则将游标指向下一个,继续判断
                while (i < j && nums[i] <= temp) i++;
                nums[j] = nums[i];
            }
            // 最后将基准值归位,这时基准值左边是小于基准的,右边是大于基准的
            nums[i] = temp;
            // 对基准值左边的数组进行同样操作
            quickSort(nums, start, i - 1);
            // 对基准值右的数组进行同样操作
            quickSort(nums, i + 1, end);
        }
    }
}

算法分析

1.假设每次基准值都被排到中间,这时快速排序的时间复杂度最低,为 O ( l o g 2 n )
2.假设选择了以下情况下最大或者最小的元素作为基准值,会出现最差的时间复杂度 O ( n 2 )
1)数组已经是正序(same order)排过序的。
2)数组已经是倒序排过序的。
3)所有的元素都相同(1、2的特殊情况)

猜你喜欢

转载自blog.csdn.net/blue5945/article/details/80783620