快速排序模拟实现

2023-09-22 10:46:48

快速排序,时间复杂度为O(NlogN),属于排序中相对快的那一列,以下是快排的模拟实现:

法一:左右指针交换法

void swap(int* x, int* y)
{
    int tmp = *x;
    *x = *y;
    *y = tmp;
}//交换函数


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


}//三数取中



int PartSort1(int* a, int left, int right)
{
    int mid = getmid(a, left, 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[keyi], &a[left]);
    return left;


}


void sort(int* arr, int left, int right)
{
	if (left < right)
	{

		int mid = PartSort1(arr, left, right);
		sort(arr, left, mid - 1);
		sort(arr, mid + 1, right);

	}



}

本思路是以left下标所指的元素为分界线,left指针向右移动找比分界元素大的,right指针向左移动找比分解元素小的,然后两者交换。通过这样循环,使得左侧的元素都是比分界元素小的,右侧元素都是比分界元素大的,且此时分界元素已经放在了排好序后的正确位置上。再对分界元素左侧、右侧调用同样的方法,最后就能实现排序。三数取中是一种优化方式,使得left下标所指向的元素更加贴近当前left到righ范围内的中间值。最后之所以用left指向位置和keyi指向位置进行交换,是因为left此时所指元素一定小于等于keyi所指向的元素。下面会证明为什么left此时所指元素一定小于等于keyi所指向的元素:

当循环停止以后,循环前的最后一次移动分两种情况,一种是right指针左移动碰到left,一种是left指针右移动碰到right。对于第一种情况,此时left指针所指的位置是前面left和right所指元素交换后的,所以此时left所指元素一定是小于keyi的。对于第二种情况,此时right指针已经结束移动,所指向的位置也是小于keyi的元素。所以left此时所指元素一定小于等于keyi所指向的元素。当然,如果先移动left指针再移动right指针,就不能符合上述结论。

法二:挖坑法

// 挖坑法
int PartSort2(int* a, int left, int right)
{
     int mid = getmid(a, left, right);
     swap(&a[left], &a[mid]);
    //三数取中
    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 sort(int* arr, int left, int right)
{
	if (left < right)
	{

		int mid = PartSort2(arr, left, right);
		sort(arr, left, mid - 1);
		sort(arr, mid + 1, right);

	}



}

该方法的思路是先把left所指的位置视为坑,保存最左的元素到可以中 ,此后利用right指针和left指针移动找元素填坑和创建新坑。此时整个数组中一直保持着有一个下标指向坑,最后再将最开始保存的key放入坑中,形成完整的数组。left和right指针的移动规则仍然是left找比key大的,right找比key小的。

法三:前后指针法

int PartSort3(int* a, int left, int right)
{

    int prev = left;
    int cur = left+1;

    while (cur <= right)
    {
        while(cur <= right&&a[cur] <= a[left])
        {  
            prev++;
            swap(&a[cur], &a[prev]);
            cur++;
           
        }
        if (cur > right)
        {
            break;
        }
        while (cur <= right && a[cur] > a[left])
        {
            cur++;

        }
        if (cur > right)
        {
            break;
        }

    }
    swap(&a[prev], &a[left]);
    
    return prev;
}


void sort(int* arr, int left, int right)
{
	if (left < right)
	{

		int mid = PartSort2(arr, left, right);
		sort(arr, left, mid - 1);
		sort(arr, mid + 1, right);

	}



}

思路是让prev的下一位元素是比a[left]大的元素,cur所指的元素是比a[left]小的元素,然后交换,使得小于a[left]的元素往左移动,比a[left]大的元素不断往右移动。

更多推荐

AI 与大模型引新安全威胁?亚马逊云科技与领创集团的探索和实践

出品|CSDN云计算作为数字化底座,疫情后的安全需求仍在增长。据统计,2023年上半年国内GDP增速为5.4%,其中网络安全市场规模增长10%。另一面,今年爆火的AIGC与大模型,也在被攻击者利用,演化出新型的诈骗与攻击手段。在亚马逊云科技re:Inforce2023中国站上,领创集团信息安全总监赵海旭分享了AI与大模

大数据面试题:Flink延迟数据是怎么解决的

最近朋友面试某猪的时候,被问到一个问题答得面试官不太满意,问的是前司数据延迟问题是怎么解决的,我稍作整理。一、什么是延迟数据大数据处理过程中Join的场景太多太多了,几乎所有公司的APP都会涉及到两条流数据之间的维度拼接,将表变宽等场景,避免不了进行多流Join操作。同时join场景中受网络或物理设备等因素影响也有可能

184_Python 在 Excel 和 Power BI 绘制堆积瀑布图

184_Python在Excel和PowerBI绘制堆积瀑布图一、背景在2023年8月22日微软Excel官方宣布:在Excel原生内置的支持了Python。博客原文笔者第一时间就更新到了Excel的预览版,通过了漫长等待分发,现在可以体验了,先来看看效果。在Excel公式选项卡下Python菜单原来的Excel公示栏

使用PageHelper进行分页

使用PageHelper进行分页1.使用SpringBoot2.不使用SpringBoot的实现1.使用SpringBoot要在SpringMVC中使用PageHelper进行分页,你需要完成以下几个步骤:添加PageHelper依赖:在你的项目中添加PageHelper的Maven或Gradle依赖。例如,如果你使用

[效率提升]使用shell脚本完成一些git操作

[效率提升]使用shell脚本完成一些git操作根据分支名自动Add和Commit并Push到远程开发分支例如开发分支名为:feature-xxx功能Commit信息为:xxx功能#!/bin/bash#获取当前分支名称current_branch=$(gitrev-parse--abbrev-refHEAD)echo

计算机毕设 flink大数据淘宝用户行为数据实时分析与可视化

文章目录0前言1、环境准备1.1flink下载相关jar包1.2生成kafka数据1.3开发前的三个小tip2、flink-sql客户端编写运行sql2.1创建kafka数据源表2.2指标统计:每小时成交量2.2.1创建es结果表,存放每小时的成交量2.2.2执行sql,统计每小时的成交量2.3指标统计:每10分钟累计

【含java2023面试题】HashMap、HashTable、ConcurrentHashMap

作为Java中最常用的Map集合,HashMap、HashTable和ConcurrentHashMap都是线程安全的,但它们之间有什么区别呢?在本文中,我们将深入探讨这三种Map集合的区别,并通过Java代码示例来演示它们之间的差异。AI绘画关于SD,MJ,GPT,SDXL百科全书面试题分享点我直达2023Pytho

Java面试八股文宝典:初识数据结构-数组的应用扩展之HashTable

前言上一章我们了解HashMap后,让我们深入研究HashTable,这是另一个键值对存储的数据结构。Hash表是一个非常重要且广泛用于编程中的数据结构,了解其工作原理和用法对于编写高效的程序非常重要。简述HashTable是Java中的一个古老的哈希表实现,它在Java的早期版本中被引入。虽然它在新的Java版本中不

Spark-3.2.4 高可用集群安装部署详细图文教程

目录一、Spark环境搭建-Local1.1服务器环境1.2基本原理1.2.1Local下的角色分布1.3搭建1.3.1安装Anaconda1.3.1.1添加国内阿里源1.3.2创建pyspark环境1.3.3安装spark1.3.4添加环境变量1.3.5启动spark1.3.5.1bin/pyspark1.3.5.2

337.打家劫舍III

337.打家劫舍III-力扣(LeetCode)小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为root。除了root之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。给定

PostgreSQL 数据定义语言 DDL

文章目录表创建主键约束非空唯一约束检查约束外键约束默认值约束触发器表空间构建表空间视图索引索引的基本概念索引的分类创建索引物化视图表创建PostgreSQL表的构建语句与所有数据库都一样,结构如下,其核心在于构建表时,要指定上一些约束,例如主键、非空、唯一、检查、外键、默认值等。CREATETABLEtable_nam

热文推荐