快速排序——“数据结构与算法”

各位CSDN的uu们好呀,今天又是小雅兰的数据结构与算法专栏啦,下面,就让我们进入快速排序的世界吧!!!


快速排序 

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右 子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

 hoare法

 单趟动图如下:

在这里插入图片描述 

 

//hoare法
int PartSort1(int* a, int left, int right)
{int keyi = left;while (left < right){//右边找小//要防止死循环和越界的问题while (left < right && a[right] >= a[keyi]){--right;}//左边找大while (left < right && a[left] <= a[keyi]){++left;}Swap(&a[left], &a[right]);}Swap(&a[left], &a[keyi]);return left;
}
void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int keyi = PartSort1(a, begin, end);//[begin,keyi-1] keyi [keyi+1,end]QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);
}

 测试一下快速排序:

void TestQuickSort()
{
    int a[] = { 2,1,4,3,6,5,7,9,8,10 };
    PrintArray(a, sizeof(a) / sizeof(a[0]));
    QuickSort(a, 0, sizeof(a) / sizeof(a[0]) - 1);
    PrintArray(a, sizeof(a) / sizeof(a[0]));
}

 

这边有一个问题

如何保证left和right相遇的位置一定比keyi小呢?

左边作keyi,右边先走,保障了相遇位置的值比keyi小或者是就是keyi的位置

left和right相遇,无非就是两种情况,left遇right和right遇left

情况一:left遇right,right是停下来,left在走。right先走,right停下来的位置一定比keyi小,相遇的位置就是right停下来的位置,就一定比keyi小。

情况二:right遇left,在相遇这一轮,left就没动,right在移动,跟left相遇,相遇位置就是left的位置,left的位置就是keyi的位置,或者交换过一些轮次,相遇left的位置一定比keyi小

右边作keyi,左边先走,保障了相遇位置的值比keyi大 

 


 挖坑法

在这里插入图片描述

 

//挖坑法
int PartSort2(int* a, int left, int right)
{int key = a[left];int hole = left;while (left < right){//右边找小//要防止死循环和越界的问题while (left < right && a[right] >= key){--right;}a[hole] = a[right];hole = right;//左边找大while (left < right && a[left] <= key){++left;}a[hole] = a[left];hole = left;}a[hole] = key;return hole;
}
void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int keyi = PartSort2(a, begin, end);//[begin,keyi-1] keyi [keyi+1,end]QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);
}

 

  


前后指针法

 

 

 

 

//前后指针法
int PartSort3(int* a, int left, int right)
{int prev = left;int cur = left + 1;int keyi = left;while (cur <= right){if (a[cur] < a[keyi]){++prev;Swap(&a[prev], &a[cur]);}++cur;}Swap(&a[prev], &a[keyi]);keyi = prev;return keyi;
}
void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int keyi = PartSort3(a, begin, end);//[begin,keyi-1] keyi [keyi+1,end]QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);
}


 快速排序优化 

  1. 三数取中法选key
  2. 递归到小的子区间时,可以考虑使用插入排序

 

 

  • 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
  • 时间复杂度:O(N*logN)
  • 空间复杂度:O(logN)
  • 稳定性:不稳定

三数取中:

int GetMidIndex(int* a, int left, int right)
{int mid = (left + right) / 2;if (a[left] < a[mid]){if (a[mid] < a[right]){return mid;}else if (a[left] < a[right]){return right;}else{return left;}}else // a[left] > a[mid]{if (a[mid] > a[right]){return mid;}else if (a[left] > a[right]){return right;}else{return left;}}
}

优化后的所有方式源代码:

int GetMidIndex(int* a, int left, int right)
{
    int mid = (left + right) / 2;
    if (a[left] < a[mid])
    {
        if (a[mid] < a[right])
        {
            return mid;
        }
        else if (a[left] < a[right])
        {
            return right;
        }
        else
        {
            return left;
        }
    }
    else // a[left] > a[mid]
    {
        if (a[mid] > a[right])
        {
            return mid;
        }
        else if (a[left] > a[right])
        {
            return right;
        }
        else
        {
            return left;
        }
    }
}


// hoare
// [left, right]
int PartSort1(int* a, int left, int right)
{
    int midi = GetMidIndex(a, left, right);
    Swap(&a[left], &a[midi]);

    int keyi = left;
    while (left < right)
    {
        // 右边找小
        while (left < right && a[right] >= a[keyi])
        {
            --right;
        }

        // 左边找大
        while (left < right && a[left] <= a[keyi])
        {
            ++left;
        }

        Swap(&a[left], &a[right]);
    }

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

    return left;
}


// 挖坑法
// [left, right]
int PartSort2(int* a, int left, int right)
{
    int midi = GetMidIndex(a, left, right);
    Swap(&a[left], &a[midi]);

    int key = a[left];
    int hole = left;
    while (left < right)
    {
        // 右边找小
        while (left < right && a[right] >= key)
        {
            --right;
        }

        a[hole] = a[right];
        hole = right;

        // 左边找大
        while (left < right && a[left] <= key)
        {
            ++left;
        }

        a[hole] = a[left];
        hole = left;
    }

    a[hole] = key;

    return hole;
}

// 前后指针法
// [left, right]
int PartSort3(int* a, int left, int right)
{
    int midi = GetMidIndex(a, left, right);
    Swap(&a[left], &a[midi]);

    int prev = left;
    int cur = left + 1;
    int keyi = left;
    while (cur <= right)
    {
        if (a[cur] < a[keyi] && ++prev != cur)
        {
            Swap(&a[prev], &a[cur]);
        }

        ++cur;
    }

    Swap(&a[prev], &a[keyi]);
    keyi = prev;
    return keyi;
}


void QuickSort(int* a, int begin, int end)
{
    if (begin >= end)
    {
        return;
    }
    int keyi = PartSort3(a, begin, end);
    //[begin,keyi-1] keyi [keyi+1,end]
    QuickSort(a, begin, keyi - 1);
    QuickSort(a, keyi + 1, end);
}

 


快速排序非递归

 

 

void QuickSortNonR(int* a, int begin, int end)
{Stack st;StackInit(&st);StackPush(&st, end);StackPush(&st, begin);while (!StackEmpty(&st)){int left = StackTop(&st);StackPop(&st);int right = StackTop(&st);StackPop(&st);int keyi = PartSort1(a, left, right);// [left, keyi-1] keyi [keyi+1, right]if (keyi + 1 < right){StackPush(&st, right);StackPush(&st, keyi + 1);}if (left < keyi - 1){StackPush(&st, keyi - 1);StackPush(&st, left);}}StackDestroy(&st);
}

 测试一下快速排序非递归:

void TestQuickSortNonR()
{
    int a[] = { 2,1,4,3,6,5,7,9,8,10 };
    PrintArray(a, sizeof(a) / sizeof(a[0]));
    QuickSortNonR(a, 0, sizeof(a) / sizeof(a[0]) - 1);
    PrintArray(a, sizeof(a) / sizeof(a[0]));
}

 

Stack.h和Stack.c的内容:

 

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;//栈顶int capacity;//容量
}Stack;// 初始化栈 
void StackInit(Stack* pst);// 销毁栈 
void StackDestroy(Stack* pst);// 入栈 
void StackPush(Stack* pst, STDataType x);// 出栈 
void StackPop(Stack* pst);// 获取栈顶元素 
STDataType StackTop(Stack* pst);// 获取栈中有效元素个数 
int StackSize(Stack* pst);// 检测栈是否为空 
bool StackEmpty(Stack* pst);#include"Stack.h"
// 初始化栈 
void StackInit(Stack* pst)
{assert(pst);pst->a = NULL;pst->top = 0;pst->capacity = 0;
}
// 销毁栈 
void StackDestroy(Stack* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->top = pst->capacity = 0;
}
// 入栈 
void StackPush(Stack* pst, STDataType x)
{assert(pst);//扩容if (pst->top == pst->capacity){int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}pst->a = tmp;pst->capacity = newcapacity;}pst->a[pst->top] = x;pst->top++;
}
// 检测栈是否为空
bool StackEmpty(Stack* pst)
{assert(pst);if (pst->top == 0){return true;}else{return false;}//return pst->top==0;
}
// 出栈 
void StackPop(Stack* pst)
{assert(pst);assert(!StackEmpty(pst));pst->top--;
}
// 获取栈顶元素 
STDataType StackTop(Stack* pst)
{assert(pst);assert(!StackEmpty(pst));return pst->a[pst->top - 1];
}// 获取栈中有效元素个数 
int StackSize(Stack* pst)
{assert(pst);return pst->top;
}


 好啦,小雅兰的快速排序的所有的内容就到这里啦,还要继续加油学数据结构与算法啦,敬请期待小雅兰下一篇的归并排序的内容!!!

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C语言学习】数据类型转换

一、自动类型转换 1.当运算符两边的数据类型不同时&#xff0c;C语言会帮我们将其转换为较大的类型。即将数据转换成表达范围更大的类型。 将前一种类型转换为后一种类型 char --> short --> int --> long --> long long int --> float --> double2.对于…

C/C++的5大内存分区

1、堆区&#xff08;heap&#xff09;——由程序员分配和释放&#xff0c; 若程序员不释放&#xff0c;程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事 2、栈区&#xff08;stack&#xff09;——由编译器自动分配释放 &#xff0c;存放函数的参数值&#xff0c;局…

python基础

本篇博客的内容是《python编程从入门到实践》的精简版&#xff0c;主要是书中&#xff08;本人认为的&#xff09;重点精简&#xff0c;以及自己学习的一些理解。 文章目录 更好的阅读体验变量和简单的数据类型变量字符串字符串的几种定义方法字符串拼接 列表简介列表是什么运…

ELK + Fliebeat + Kafka日志系统

参考&#xff1a; ELKFilebeatKafka分布式日志管理平台搭建_51CTO博客_elk 搭建 ELK 日志分析系统概述及部署&#xff08;上&#xff09;-阿里云开发者社区 ELK是三个开源软件的缩写&#xff0c;分别表示&#xff1a;Elasticsearch , Logstash, Kibana , 它们都是开源软件。…

python 数据分析面试题:求分组排第n名的记录数据

近期面试遇到一个面试题&#xff0c;分享给大家。 文中会提供详细的解题思路以及问题延伸 一、面试题 面试题&#xff1a;输出各学科总分第一名的学员姓名、年龄、分数数据&#xff1a; class_a {name: [学员1, 学员2, 学员3, 学员4,学员5],age: [23, 24, 26, 27,25],course…

05|Oracle学习(UNIQUE约束)

1. UNIQUE约束介绍 也叫&#xff1a;唯一键约束&#xff0c;用于限定数据表中字段值的唯一性。 1.1 UNIQUE和primary key区别&#xff1a; 主键/联合主键每张表中只有一个。UNIQUE约束可以在一张表中&#xff0c;多个字段中存在。例如&#xff1a;学生的电话、身份证号都是…

AB 压力测试

服务器配置 阿里云Ubuntu 64位 CPU1 核 内存2 GB 公网带宽1 Mbps ab -c100 -n1000 http://127.0.0.1:9501/ -n&#xff1a;在测试会话中所执行的请求个数。默认时&#xff0c;仅执行一个请求。 -c&#xff1a;一次产生的请求个数。默认是一次一个。 ab -c 100 -n 200 ht…

PHP从入门到精通—PHP开发入门-PHP概述、PHP开发环境搭建、PHP开发环境搭建、第一个PHP程序、PHP开发流程

每开始学习一门语言&#xff0c;都要了解这门语言和进行开发环境的搭建。同样&#xff0c;学生开始PHP学习之前&#xff0c;首先要了解这门语言的历史、语言优势等内容以及了解开发环境的搭建。 PHP概述 认识PHP PHP最初是由Rasmus Lerdorf于1994年为了维护个人网页而编写的一…

无涯教程-Lua - 函数声明

函数是一起执行任务的一组语句&#xff0c;您可以将代码分成单独的函数。 Lua语言提供了程序可以调用的许多内置方法。如方法 print()打印在控制台中作为输入传递的参数。 定义函数 Lua编程语言中方法定义的一般形式如下- optional_function_scope function function_name(…

什么?你还没有用过JPA Buddy,那么你工作肯定没5年

1. 概述 JPA Buddy是一个广泛使用的IntelliJ IDEA插件&#xff0c;面向使用JPA数据模型和相关技术&#xff08;如Spring DataJPA&#xff0c;DB版本控制工具&#xff08;Flyway&#xff0c;Liquibase&#xff09;&#xff0c;MapStruct等&#xff09;的新手和有经验的开发人员…

【论文阅读】通过解缠绕表示学习提升领域泛化能力用于主题感知的作文评分

摘要 本文工作聚焦于从领域泛化的视角提升AES模型的泛化能力&#xff0c;在该情况下&#xff0c;目标主题的数据在训练时不能被获得。本文提出了一个主题感知的神经AES模型&#xff08;PANN&#xff09;来抽取用于作文评分的综合的表示&#xff0c;包括主题无关&#xff08;pr…

【MySQL】表的增删查改

文章目录 一、创建表create二、查看表desc三、修改表3.1 修改表名alter3.2 在表中插入数据insert3.3 在表中新增字段alter3.4 修改指定列的属性alter3.5 移除表中的一列alter3.6 修改表中某一列的列名alter 四、删除表drop 一、创建表create mysql> create table if not ex…

Python爬虫教程篇+图形化整理数据(数学建模可用)

一、首先我们先看要求 1.写一个爬虫程序 2、爬取目标网站数据&#xff0c;关键项不能少于5项。 3、存储数据到数据库&#xff0c;可以进行增删改查操作。 4、扩展&#xff1a;将库中数据进行可视化展示。 二、操作步骤&#xff1a; 首先我们根据要求找到一个适合自己的网…

【深度学习】High-Resolution Image Synthesis with Latent Diffusion Models,论文

13 Apr 2022 论文&#xff1a;https://arxiv.org/abs/2112.10752 代码&#xff1a;https://github.com/CompVis/latent-diffusion 文章目录 PS基本概念运作原理 AbstractIntroductionRelated WorkMethodPerceptual Image CompressionLatent Diffusion Models Conditioning Mec…

ERROR 1064 - You have an error in your SQL syntax;

ERROR 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near (/, 少个逗号吧&#xff0c;以前开始写SQL&#xff0c;特别是修改SQL的时候容易出现这样错误。 而且自己也知道在附近…

应用案例|基于高精度3D视觉引导压缩机抓取定位应用

Part.1 行业现状 3D机器视觉是一种新兴的人工智能技术&#xff0c;它在机器视觉和机器学习领域中发挥着重要的作用。在工业领域&#xff0c;3D视觉技术被广泛应用于引导工业机器人进行抓取和定位操作。使用显扬科技的技术可以实现识别和定位压缩机。 Part.2 如何识别和定位压缩…

SpringBoot+ruoyi框架图片上传和文件下载

第一次接触ruoyi框架&#xff0c;碰到文件上传和下载问题&#xff0c;今天来总结一下。 使用若依框架文件上传下载首先配置文件路径要配好。 文件下载&#xff1a; application.yml若依配置 # 项目相关配置 ruoyi:# 名称name: RuoYi# 版本version: 3.6.0# 版权年份copyright…

Compose应用案例(利用docker compose安装lnmp实例)

目录 Compose应用案例 一、前提配置 &#xff08;一&#xff09;安装docker-ce&#xff08;Linux安装Docker&#xff09; &#xff08;二&#xff09;安装docker-compose 二、安装docker compose部署lnmp &#xff08;一&#xff09;目录结构&#xff1a; &#xff08;二…

MQTT服务器详细介绍:连接物联网的通信枢纽

随着物联网技术的不断发展&#xff0c;MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;协议作为一种轻量级、可靠、灵活的通信协议&#xff0c;被广泛应用于物联网领域。在MQTT系统中&#xff0c;MQTT服务器扮演着重要的角色&#xff0c;作为连接物联网设备和…

布隆过滤器

文章目录 布隆过滤器布隆过滤器的概念布隆过滤器的插入布隆过滤器的删除 布隆过滤器 布隆过滤器就是为了解决位图不能解决的问题。 用哈希表存储用户记录&#xff0c;缺点&#xff1a;浪费空间用位图存储用户记录&#xff0c;缺点&#xff1a;不能处理哈希冲突将哈希与位图结合…