分治法 - 随机快速排序(全网最细)

写在前面:

我们都知道在数据结构中有一种排序算法叫做快速排序又叫快排,这个排序算法比较重要,很多大厂面试的时候都会考!!!  (ps:bb相信我看我我这篇)

                                                                                        

一般情况下的时间复杂度为O(nlogn)这个复杂度已经算是非常理想非常小了,但是在有些情况下比如一段已经有序了的数列那么它的时间复杂度就会退化为O(^{^{}}n^{2}),这肯定是我们所不想看见的。而使用概率算法思想改进快速排序算法,就能使其效率尽量趋近于最佳效率O(nlogn)。所以就有了随机快速排序。

随机快速排序的主要思想是在原有快排的基础上增加随机数产生器,在快速排序进行元素分割之前,使用随机数产生器生成一个随机的元素下标,交换该下标元素和序列的第一个元素。接着按分治法思想进行元素分割和递归求解。这样讲可能有点抽象,还是直接看代码吧

Java版本:

package com.heima.test;
import javax.swing.tree.FixedHeightLayoutCache;
import java.util.Random;
import java.util.Scanner;

public class quick_sort {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();//     输入待排序序列的元素个数
        int[] arr = new int[n+1];
        for (int i = 1; i <= n; i++) {
            arr[i] =  sc.nextInt();//     输入待排序序列的元素
        }
        System.out.println("排序前:");
        showarr(arr,1,n);
        quicksort(arr,1,n);
        System.out.println("排序后:");
        showarr(arr,1,n);
    }

    /* 生成随机数 */
    public static int random(int a,int b ){
        /* 随机选取分界值 */
        //返回a - b 之间的随机数 [a,b) 如果要生成13-50之间的随机数 那么就是 %(50-13+1)+13
        Random r = new Random();
        return r.nextInt(b-a+1)+a;
    }

    /* 显示数组中的元素 */
    public static  void showarr(int[] a,int start,int end){
        System.out.print("[");
        for (int i = start; i <=end; i++) {
            if(i<end){
                System.out.print(a[i]+",");
            }
            else{
                System.out.println(a[i]+"]");
            }
        }
    }

    /* 快速排序 */
    public static void quicksort(int[] a,int left,int right){
        // 递归结束条件
        if(left<right){
            // 随机选取分界值  这里是跟经典快排唯一区别的地方
            int r = random(left,right);
            // 将下标为分界值的元素与左边的第一个元素交换
            int t = a[left];a[left] = a[r];a[r] =t;
            int pos = partition(a,left,right);//     将待排序序列划分成两个子序列
            // 递归排序左子序列
            quicksort(a,left,pos-1);
            // 递归排序右子序列
            quicksort(a,pos+1,right);
        }
    }
    /* 将待排序序列划分成两个子序列 */
    public static int partition(int[] a,int left,int right){
        int i = left;
        int j = right;
        // 我们这里选左边的为 基准值 所以从右边开始遍历
        while(i<j){
            while(i<j&&a[j]>a[left])j--; //  这里应该也是可以等于的 因为我们是要将大于基准值的元素放到右边
            while(i<j&&a[i]<=a[left])i++; // 但是 这两个whi e循环的位置不能交换 因为要保证相遇点的值 要小于等于基准值
//           这里有个小Tips: 就是扫描的方向要跟基准值的方向相反!!!
            if(i<j) { // 交换 i和j 指向的元素
                int t = a[i];
                a[i] = a[j];
                a[j] = t;
            }
        }
        // 最后将基准值与相遇点的值交换(将基准值放到属于它的位置上)  这里相遇点的值 是小于等于基准值的
        int t= a[i];
        a[i]  = a[left];
        a[left]=t;
        return i;
    }
}

C/C++版本:

#include<bits/stdc++.h>

using namespace std;

/* 生成随机数 */
int random(int a, int b) {
    /* 随机选取分界值 */
    // 返回a - b 之间的随机数 [a,b] 如果要生成13-50之间的随机数 那么就是 %(50-13+1)+13
    random_device rd;
    mt19937 gen(rd());
    uniform_int_distribution<> dis(a, b);
    return dis(gen);
}

/* 显示数组中的元素 */
void showarr(vector<int>& a, int start, int end) {
    cout << "[";
    for (int i = start; i <= end; i++) {
        if (i < end) {
            cout << a[i] << ",";
        } else {
            cout << a[i] << "]" << endl;
        }
    }
}

/* 将待排序序列划分成两个子序列 */
int partition(vector<int>& a, int left, int right) {
    int i = left;
    int j = right;
    // 我们这里选左边的为 基准值 所以从右边开始遍历
    while (i < j) {
        while (i < j && a[j] > a[left]) j--; //  这里应该也是可以等于的 因为我们是要将大于基准值的元素放到右边
        while (i < j && a[i] <= a[left]) i++; // 但是 这两个while循环的位置不能交换 因为要保证相遇点的值 要小于等于基准值
//       这里有个小Tips: 就是扫描的方向要跟基准值的方向相反!!!
        if (i < j) { // 交换 i和j 指向的元素
            int t = a[i];
            a[i] = a[j];
            a[j] = t;
        }
    }
    // 最后将基准值与相遇点的值交换(将基准值放到属于它的位置上)  这里相遇点的值 是小于等于基准值的
    int t = a[i];
    a[i] = a[left];
    a[left] = t;
    return i;
}

/* 快速排序 */
void quicksort(vector<int>& a, int left, int right) {
    // 递归结束条件
    if (left < right) {
        // 随机选取分界值  这里是跟经典快排唯一区别的地方
        int r = random(left, right);
        // 将下标为分界值的元素与左边的第一个元素交换
        int t = a[left]; a[left] = a[r]; a[r] = t;
        int pos = partition(a, left, right); //     将待排序序列划分成两个子序列
        // 递归排序左子序列
        quicksort(a, left, pos - 1);
        // 递归排序右子序列
        quicksort(a, pos + 1, right);
    }
}

int main() {
    int n;
    cin >> n; //     输入待排序序列的元素个数
    vector<int> arr(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> arr[i]; //     输入待排序序列的元素
    }
    cout << "排序前:" << endl;
    showarr(arr, 1, n);
    quicksort(arr, 1, n);
    cout << "排序后:" << endl;
    showarr(arr, 1, n);
    return 0;
}

Python版本:

import random

def random_num(a, b):
    """生成随机数"""
    """随机选取分界值"""
    # 返回a - b 之间的随机数 [a,b] 如果要生成13-50之间的随机数 那么就是 %(50-13+1)+13
    return random.randint(a, b)

def showarr(a, start, end):
    """显示数组中的元素"""
    print("[", end="")
    for i in range(start, end + 1):
        if i < end:
            print(a[i], end=",")
        else:
            print(a[i], end="]")
    print()

def partition(a, left, right):
    """将待排序序列划分成两个子序列"""
    i = left
    j = right
    # 我们这里选左边的为 基准值 所以从右边开始遍历
    while i < j:
        while i < j and a[j] > a[left]:
            j -= 1  #  这里应该也是可以等于的 因为我们是要将大于基准值的元素放到右边
        while i < j and a[i] <= a[left]:
            i += 1  # 但是 这两个while循环的位置不能交换 因为要保证相遇点的值 要小于等于基准值
#       这里有个小Tips: 就是扫描的方向要跟基准值的方向相反!!!
        if i < j:  # 交换 i和j 指向的元素
            a[i], a[j] = a[j], a[i]
    
    # 最后将基准值与相遇点的值交换(将基准值放到属于它的位置上)  这里相遇点的值 是小于等于基准值的
    a[i], a[left] = a[left], a[i]
    return i

def quicksort(a, left, right):
    """快速排序"""
    # 递归结束条件
    if left < right:
        # 随机选取分界值  这里是跟经典快排唯一区别的地方
        r = random_num(left, right)
        # 将下标为分界值的元素与左边的第一个元素交换
        a[left], a[r] = a[r], a[left]
        pos = partition(a, left, right)  #     将待排序序列划分成两个子序列
        # 递归排序左子序列
        quicksort(a, left, pos - 1)
        # 递归排序右子序列
        quicksort(a, pos + 1, right)

def main():
    n = int(input())  #     输入待排序序列的元素个数
    arr = [0] * (n + 1)  # 索引从1开始,所以需要n+1个元素
    for i in range(1, n + 1):
        arr[i] = int(input())  #     输入待排序序列的元素
    
    print("排序前:")
    showarr(arr, 1, n)
    quicksort(arr, 1, n)
    print("排序后:")
    showarr(arr, 1, n)

if __name__ == "__main__":
    main()

代码运行完结果(java):

最后感谢未来的大犇你能够看到最后,也希望各位能支持一下本彩笔   Orz (。◕∀◕。)

1赞十道1500算法题      

有问题欢迎大家指正和评论(此时一位4年后开BBA的大犇还默默点了个星)

写在最后:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麦烤楽鸡翅

投喂作者,防止Ta饿晕在键盘前

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值