排序算法六:快速排序——冒泡算法2.0

快速排序(Quick Sort)
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,已达到整个序列有序。

算法描述:
快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:

  • 从数列中挑出一个元素,称为“基准”(pivot)
  • 分区(partition)操作:重新排序数列,所以元素比基准小的放在基准前面,所有元素比基准值大的放在基准后面(相同的任意一边)。在这个分区退出之后,该基准就处于数列的中间位置;
  • 递归地(recursive)把小于基准元素的子数列和大于基准元素的子数列排序。

动画演示:在这里插入图片描述
(不知道有没有人和我一样,光看图还是看不懂)
其实很简单,我们不是要按顺序吗?一种思路是把大的放一块,然后小的放另一块,这样这两块自己内部再分,就像以前的分班一样,有普通班和重点班两个班,高考550以上重点班,550以下普通班,这样最终如果要统计排名,肯定重点班自己排好序,普通班排好序后直接加在重点班最后一名后面就好了。

这里的550就是基准,当然在快速排序算法里,我们一般选数组的第一个数字为基准,也可以随机找个基准,或者下面的三数取中选个基准。基准的作用可大可小,但选个好基准能节省时间是真的。你要是选个600就是跟计算机过不去,能让计算机越快跑完越好。时间就是金钱。

选好基准之后我们怎么把基准放在合适的位置呢,即怎么保证让基准的位置刚好它的左边全是比它小的,它的右边全是比它大的?

其实就是这样一种思想,数组就像一座桥,桥的两端分别有个哨兵巡游,一个从前往后走,一个从后往前走。

前面的哨兵遇到靠前的比基准大的数字,把它放到后面,遇到靠后的比基准小的数字,把它放到前面。 那么要怎么放呢?比如说前面走的哨兵发现了一个数字 520 比 550要小,把这个数字放到哪呢,毫无疑问当然是应该把这个数字放到靠后,后面往前走的哨兵就可以起到接应的效果了,给谁不是给呢,后面哨兵的位置又是已知的,交换一下两个哨兵所在位置的数字就好了。

将基准放到合适的位置与数据的分布息息相关,依据现在学到的知识来看,我们还是很难预测基准的位置的,即使利用三数取中法我们也只能得到一个不是那么极端的基准(或者太大,或者太小), 我们普遍是希望基准是中位数的。

哨兵的位移也是有学问的,一般是一个哨兵遇到一个冲突的数字(比基准大却靠前或比基准小却靠后)而和另一个方向的哨兵交换数字后,另一个方向的哨兵再开始位移检测冲突的数字。比如靠前位置的哨兵发现一个数字,和靠后位置的哨兵交换数字,靠后位置的哨兵再开始走。这样做好像更适合基准是中间数吧,所以希望两个哨兵都是相同进度往中间走的,而不是一个走向另一个的尽头。

二者汇合时意味着什么? 意味着他们所在位置的左边都是比基准小的,他们所在位置的右边都是比基准大的,因为他们只有在检测完冲突的数据之后才能位移,现在他们已经没有冲突的数据可以检测了。那么这个位置,放上基准数字就是画龙点睛了。

然后基准两侧的区域各自重复上述步骤。直到有序。

快速排序优化

  1. 优化选取基准
    2如果我们选取的 pivotkey 是处于整个序列的中间位置,那么我们可以将整个序列分成小数集合和大数集合了,但注意,如果 pivotkey 不是中间数。即总是固定选取第一个关键字或是其他位置的关键字,这是一种不合理的做法。
  • 三数取中法: 取三个关键字先进行排序,将中间数作为枢轴,一般是取左端、右端和中间三个数。
    在这里插入图片描述
    图片来源:https://www.cnblogs.com/chengxiao/p/6262208.html
package sortdemo;

import java.util.Arrays;

/**
 * Created by chengxiao on 2016/12/14.
 * 快速排序
 */
public class QuickSort {
    public static void main(String[] args) {
        int[] arr = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
        quickSort(arr, 0, arr.length - 1);
        System.out.println("排序结果:" + Arrays.toString(arr));
    }

    /**
     * @param arr
     * @param left  左指针
     * @param right 右指针
     */
    public static void quickSort(int[] arr, int left, int right) {
        if (left < right) {
            //获取枢纽值,并将其放在当前待处理序列末尾
            dealPivot(arr, left, right);
            //枢纽值被放在序列末尾
            int pivot = right - 1;
            //左指针
            int i = left;
            //右指针
            int j = right - 1;
            while (true) {
                while (arr[++i] < arr[pivot]) {
                }
                while (j > left && arr[--j] > arr[pivot]) {
                }
                if (i < j) {
                    swap(arr, i, j);
                } else {
                    break;
                }
            }
            if (i < right) {
                swap(arr, i, right - 1);
            }
            quickSort(arr, left, i - 1);
            quickSort(arr, i + 1, right);
        }

    }

    /**
     * 处理枢纽值
     *
     * @param arr
     * @param left
     * @param right
     */
    public static void dealPivot(int[] arr, int left, int right) {
        int mid = (left + right) / 2;
        if (arr[left] > arr[mid]) {
            swap(arr, left, mid);
        }
        if (arr[left] > arr[right]) {
            swap(arr, left, right);
        }
        if (arr[right] < arr[mid]) {
            swap(arr, right, mid);
        }
        swap(arr, right - 1, mid);
    }

    /**
     * 交换元素通用处理
     *
     * @param arr
     * @param a
     * @param b
     */
    private static void swap(int[] arr, int a, int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值