快速排序-加餐

1.快排性能的关键点分析

决定快排性能的关键点是每次单趟排序后,key对数组的分割,如果每次选的key基本都二分居中,那么快排的递归树就是一棵均匀的满二叉树,性能达到最佳。

但是在实践中虽然不可能每次都是二分居中,但是性能也是可控的,但是如果每次选到最小或者最大值,就会划分成0和N-1个子问题,时间复杂度就会变成O(N^2),就比如数组是有序的就会出现这种情况。

在之前相关的章节,我们用了三数取中随机选取key和小区间优化来解决这个问题,虽然解决了大多数问题,但是还是有一些场景没能解决,就比如数组中有大量重复的数据。

一下的措施可以进一步的优化我们的快速排序。

2.优化的方法

2.1三路划分

当面对有着大量跟key相同的值时,三路划分的核心思想就是把数组中的数据划分为三段(比key小的,跟key相等的,比key大的)。

基本步骤:

1.key默认取left位置的值(需要记录key的值)

2.left指向区间的最左边,right指向区间的最右边,cur指向left+1的位置

3.如果cur的值比key小,交换cur和left的数据位置,left++,cur++

4.如果cur的值比key大,交换cur和right的数据位置,right--

5.如果cur的值和key相等,cur++

6.cur大于right结束

. - 力扣(LeetCode)

2.2lomuto的快排

这里指的就是前后指针法,老铁们看过我之前的数据结构-排序2的快排那一节就知道了。

上述leetcode用的就是lomuto的快排加上随机取key的方法实现的。

2.3introsort的快排

introsort是introspective sort的缩写,实现思路就是进行自我侦测和反省,快排递归深度太深(sgi STL中使用的是深度为2倍排序元素数量的对数值,这里是指C++里使用的场景)那就说明在这种数据序列下,选key出现了问题,性能在快速退化,那么就不要再进行快排分割递归了,改换为堆排序进行排序。 

void Swap(int* p1,int* p2)

{

    int tmp = *p1;

    *p1 = *p2;

    *p2 = tmp;

}

//选择排序

 void InsertSort(int* a,int n)

 {

    for(int i = 0;i < n-1;i++)

    {

        int end = i;

        int tmp = a[end + 1];

        while(end >= 0)

        {

            if(tmp < a[end])

            {

                a[end+1] = a[end];

                --end;

            }

            else

            {

                break;

            }

        }

        a[end+1] = tmp;

    }

 }

 void AdjustDown(int* a, int n, int parent)

{

    //先假设左孩子小

    int child = parent * 2 + 1;

    while (child < n) //child >= n 说明孩子不存在,调整到叶子了

    {

        //找到小的那个孩子

        if ((child + 1) < n && a[child + 1] > a[child])//防止右孩子的越界风险

        {

            ++child;

        }

        if (a[child] > a[parent])

        {

            Swap(&a[child], &a[parent]);

            parent = child;

            child = parent * 2 + 1;

        }

        else

        {

            break;

        }

    }

}

//堆排序

void HeapSort(int* a, int n)

{

    for (int i = (n - 1 - 1) / 2; i >= 0; i--)

    {

        AdjustDown(a, n, i);//向下调整建堆 O(N)

    }

    //O(N*logN)

    int end = n - 1;

    while (end > 0)

    {

        Swap(&a[0], &a[end]);

        AdjustDown(a, end, 0);

        --end;

    }

}

//三数取中

int GetMidi(int* a, int left, int right)

{

    int midi = (left + right) / 2;

    //left midi right

    if (a[left] < a[midi])

    {

        if (a[midi] < a[right])

        {

            return midi;

        }

        else if (a[left] < a[right])

        {

            return right;

        }

        else

        {

            return left;

        }

    }

    else  //a[left] > a[midi]

    {

        if (a[midi] > a[right])

        {

            return midi;

        }

        else if (a[left] > a[right])

        {

            return right;

        }

        else

        {

            return left;

        }

    }

}

//自省排序

void IntroSort(int* a,int left,int right,int depth,int defaultDepth)

{

    if(left >= right)

        return;

    //数组长度小于16的小数组,换为插入排序,简单递归次数

    if((right - left) + 1 < 16)

    {

        InsertSort(a+left,right - left + 1);

        return;

    }

    //当深度超过2*logN,则改用堆排序

    if(depth > defaultDepth)

    {

        HeapSort(a+left,right - left + 1);

        return;

    }

    depth++;

    int begin = left;

    int end = right;

    //三数取中

    int mid = GetMidi(a,left,right);

    Swap(&a[left],&a[mid]);

    int keyi = left;

    int prev = left;

    int cur = prev + 1;

    while(cur <= right)

    {

        if(a[cur] < a[keyi] && ++prev != cur)

            Swap(&a[prev],&a[cur]);

       

        cur++;

    }

    Swap(&a[prev],&a[keyi]);

    keyi = prev;

    //[begin,keyi-1] keyi [keyi+1,end]

    IntroSort(a,begin,keyi-1,depth,defaultDepth);

    IntroSort(a,keyi+1,end,depth,defaultDepth);

}

//快排

void QuickSort(int* a,int left,int right)

{

    int depth = 0;

    int logn = 0;

    int N =right - left + 1;

    for(int i = 1;i < N;i *= 2)

    {

        logn++;

    }

    //自省排序

    IntroSort(a,left,right,depth,logn*2);

}

int* sortArray(int* nums, int numsSize, int* returnSize)

{

    srand(time(0));

    QuickSort(nums,0,numsSize-1);

    *returnSize = numsSize;

    return nums;

}

自省排序

. - 力扣(LeetCode)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/892140.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[CTF夺旗赛] CTFshow Web13-14 详细过程保姆级教程~

前言 ​ CTFShow通常是指网络安全领域中的“Capture The Flag”(夺旗赛)展示工具或平台。这是一种用于分享、学习和展示信息安全竞赛中获取的信息、漏洞利用技巧以及解题思路的在线社区或软件。参与者会在比赛中收集“flag”&#xff0c;通常是隐藏在网络环境中的数据或密码形…

面向对象--继承

文章目录 1. 继承概念及定义&#xff1a;继承的定义&#xff1a;继承关系和访问限定符&#xff1a;继承基类成员访问方式的变化 &#xff08;在派生类中访问方式&#xff09; 2. 基类和派生类对象赋值转换3 .继承中的作用域4. 派生类的默认成员函数5. 继承与友元6. 继承与静态成…

《Python爬虫逆向实战》内存漫游

所谓内存漫游&#xff0c;就是说我们可以在浏览器内存中随意检索任何想要的数据。在JS逆向过程中&#xff0c;最麻烦和最浪费时间的步骤就是跟值。本篇文章介绍内存漫游工具能够帮助我们快速定位某个加密值的生成位置&#xff0c;即可以直接搜索变量的值(value)&#xff0c;而不…

【Linux】Linux进程基础

1.进程介绍与概念 进程的本质是在计算机内存中运⾏的程序&#xff0c;但是这⼀个概念太过于⼴泛 每个应用程序运行于现代操作系统之上时&#xff0c;操作系统会提供一种抽象&#xff0c;好像系统上只有这个程序在运行&#xff0c;所有的硬件资源都被这个程序在使用。这种假象…

jenkins 插件Publish Over SSH (sskey) 同步文件夹

一、安装插件 Publish Over SSH SSH Pipeline Steps 二、添加sshkey 将ssh免密登录的私钥新建到 二、准备目录 源&#xff1a;images 目标&#xff1a;/root/images2 流水线脚本 pipeline {agent anystages {stage(Dest) {steps {script{def remote [:]remote.name tstr…

Go 语言应用开发:从入门到实战

Go 语言应用开发&#xff1a;从入门到实战 引言 Go&#xff08;Golang&#xff09;是由 Google 开发的一种开源编程语言&#xff0c;设计初衷是提高编程效率&#xff0c;尤其是在高并发场景下表现出色。Go 语言以其简洁、易学、高效并发的特性&#xff0c;逐渐成为开发者的首…

【LeetCode每日一题】——1588.所有奇数长度子数组的和

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【题目进阶】八【解题思路】九【时间频度】十【代码实现】十一【提交结果】 一【题目类别】 前缀和 二【题目难度】 简单 三【题目编号】 1588.所有奇数长度子数组的和 …

【fisco学习记录】搭建第一个单群组联盟链

前提&#xff1a;操作系统Windows11&#xff0c;安装wsl&#xff1a;Windows11安装wsl并迁移记录_adduser: please enter a username matching the regu-CSDN博客 一、 安装依赖 安装ubuntu依赖 sudo apt install -y openssl curl 二、创建操作目录, 下载安装脚本 ## 创建操…

一文介绍SQL标准1986~2023的演变

SQL标准1986年制定第一版&#xff0c;到最新的2023版&#xff0c;已经有38年的历史&#xff0c;现在依然是计算机非常活跃的语言&#xff0c;50%的程序员都能掌握SQL&#xff0c;数据分析师也是SQL的主要使用人员之一。 从早期的基本语法&#xff0c;到融合了XML、JSON等复杂数…

Qt- JSONXML

1. JSON概述 JSON&#xff08;JavaScript Object Notation, JS 对象简谱&#xff09;是一种轻量级的数据交换格式。 JSON 采用 key-value 的结构来组织和管理数据。 JSON 支持的数据类型&#xff1a; 数值型、字符串、布尔值、数组、对象等 JSON 来源于 JavaScript JSON应用…

UE5模型导入面板解读

1.Skeletal Mesh&#xff1a; 是一个可以让模型动起来的选项&#xff0c;适用于需要动画的角色或生物。是否勾选&#xff1a;如果导入的是一个需要动画的角色或生物&#xff0c;就勾选 Skeletal Mesh 选项&#xff1b;如果是静态物体&#xff0c;就不勾选。 2.Build Nanite&a…

【在Linux世界中追寻伟大的One Piece】Jsoncpp|序列化

目录 1 -> Jsoncpp 1.1 -> 特性 1.2 -> 安装 2 -> 序列化 3 -> 反序列化 4 -> Json::Value 1 -> Jsoncpp Jsoncpp是一个用于处理JSON数据的C库。它提供了将JSON数据序列化为字符串以及从字符串反序列化为C数据结构的功能。Jsoncpp是开源的&#xf…

Ubuntu20.04安装ROS2教程

Ubuntu20.04安装ROS2教程 ROS 2 安装指南支持的ROS 2 版本设置语言环境&#xff08;Set locale&#xff09;设置源&#xff08;Setup Sources&#xff09;设置密钥安装 ROS 2 包&#xff08;Install ROS 2 packages&#xff09;环境设置&#xff08;Environment setup&#xff…

拟声 0.37.0 | 拟物风格,超级优美,功能丰富

拟声是一款功能丰富的音视频播放器&#xff0c;支持多种音频来源&#xff0c;并具备独特的歌词弹幕、音源转换、跨设备共享与控制等功能。其创新的LRC歌词编解码器和新拟物风格的UI设计为用户提供了一个全新的视听体验。 大小&#xff1a;36M 百度网盘&#xff1a;https://pan…

第三届OpenHarmony技术大会在上海成功举办

10月12日&#xff0c;以“技术引领筑生态&#xff0c;万物智联创未来”为主题的第三届OpenHarmony技术大会&#xff08;以下简称“大会”&#xff09;在上海成功举办。本次大会由OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09;项目群技术指导委员会&…

【Mac苹果电脑安装】DBeaverEE for Mac 数据库管理工具软件教程【保姆级教程】

Mac分享吧 文章目录 DBeaverEE 数据库管理工具 软件安装完成&#xff0c;打开效果图片Mac电脑 DBeaverEE 数据库管理工具 软件安装——v24.21️⃣&#xff1a;下载软件2️⃣&#xff1a;安装JDK&#xff0c;根据下图操作步骤提示完成安装3️⃣&#xff1a;安装DBeaverEE&#…

如何进行数据库缩容 | OceanBase应用实践

作者&#xff1a;关炳文&#xff0c;爱可生 DBA 团队成员&#xff0c;负责数据库相关技术支持。 本文详细介绍了OceanBase V3.2版的集群中&#xff0c;面对数据文件缩容的场景的一套缩容方案&#xff0c;作为大家的参考。 缩容场景 某银行运行的一套采用1-1-1架构的OceanBase…

软件架构师 PV

PV操作与生产者消费者问题是操作系统中进程管理和同步机制的重要概念。以下是对PV操作以及生产者消费者问题的详细解释&#xff1a; 一、PV操作 PV操作由P操作原语和V操作原语组成&#xff0c;这两个原语是不可中断的过程&#xff0c;它们对信号量进行操作。 P操作&#xff…

首发 | 数据通解决方案:打造数据工程能力,驱动数据价值转化

数据已经成为企业竞争的核心资源。企业要想从海量数据资源中挖掘数据价值并促进价值转换&#xff0c;需要有全新的工程化方法对数据要素资源进行全生命周期管理。 数据工程是一套完整的实现从数据资源到企业价值的系统工程&#xff0c;旨在通过系统性技术与方法&#xff0c;将…

2024.10.16 软考学习笔记

刷题网站&#xff1a; 软考中级软件设计师在线试题、软考解析及答案-51CTO题库-软考在线做题备考工具