Java快速排序算法、三路快排(Java算法和数据结构总结笔记)[7/20]

news2024/11/26 16:27:52

一、什么是快速排序算法

        快速排序的基本思想是选择一个基准元素(通常选择最后一个元素)将数组分割为两部分,一部分小于基准元素,一部分大于基准元素。

        然后递归地对两部分进行排序,直到整个数组有序。这个过程通过 partition 方法实现,它使用两个指针 i 和 j 来遍历数组,将小于基准元素的元素交换到左边,大于基准元素的元素交换到右边。

        最后,将基准元素放入正确的位置,并返回该位置作为划分点。快速排序的时间复杂度为O(nlogn)。

如下:快速排序算法的实现代码:

import java.util.Arrays;

/**
 * @Description 快速排序算法
 **/
public class QuickSort {

    public static void main(String[] args) {
        int[] array = {0, 8, 9, 5, 6, 1, 4, 9, 3, 6, 3, 8, 2, 1, 7};
        quickSort(array, 0, array.length - 1);
        System.out.println("Sorted array: " + Arrays.toString(array));
    }

    // 递归函数用于执行快速排序
    public static void quickSort(int[] array, int low, int high) {
        if (low < high) {
            // 分割数组并获取基准元素的索引
            int pivotIndex = partition(array, low, high);

            // 递归排序左侧和右侧子数组
            quickSort(array, low, pivotIndex - 1);
            quickSort(array, pivotIndex + 1, high);
        }
    }

    // 函数用于分割数组并返回基准元素的索引
    public static int partition(int[] array, int low, int high) {
        // 选择基准元素(在本例中选择最后一个元素)
        int pivot = array[high];
        int i = low - 1;

        // 遍历数组
        for (int j = low; j < high; j++) {
            if (array[j] < pivot) {
                // 如果元素小于基准元素,则交换位置
                i++;
                swap(array, i, j);
            }
        }

        // 将基准元素放入正确的位置
        swap(array, i + 1, high);

        // 返回基准元素的索引
        return i + 1;
    }

    // 函数用于交换数组中的两个元素
    public static void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

排序输出:

上述代码中,就是快速排序算法的一种实现,总结来说就是:

1. 选择一个基准元素(通常是数组中的最后一个元素)。 
2. 将数组分割为两部分,一部分是小于基准元素的元素,另一部分是大于基准元素的元素。 
3. 对这两部分分别递归地应用快速排序算法,直到每个子数组都有序。 
4. 将所有子数组合并起来,得到最终排序后的数组。 
 
具体步骤实现: 
 
1. 选择基准元素。 
2. 设置两个指针,一个指向数组的起始位置(通常为low),另一个指向数组的结束位置(通常为high)。 
3. 从起始位置开始,向右移动指针,直到找到一个大于或等于基准元素的元素。 
4. 从结束位置开始,向左移动指针,直到找到一个小于或等于基准元素的元素。 
5. 如果左指针的位置小于右指针的位置,则交换这两个元素。 
6. 重复步骤3到5,直到左指针的位置大于或等于右指针的位置。 
7. 将基准元素与左指针所指向的元素进行交换,将基准元素放置在正确的位置。 
8. 递归地对基准元素左侧和右侧的子数组应用快速排序算法。 
 
快速排序的关键在于划分过程,即将数组分割为两部分。通过不断地划分和排序,最终实现整个数组的排序。快速排序的平均时间复杂度为O(nlogn),是一种高效的排序算法。

二、快速排序算法和三路快排的关系

        快速排序算法和三路快速排序算法都是基于快速排序思想的排序算法,它们之间的关系是三路快速排序算法是对快速排序算法的一种改进和优化。 
 
        快速排序算法通过选择一个基准元素,将数组分割为两部分,一部分是小于基准元素的元素,另一部分是大于基准元素的元素。然后递归地对这两部分进行排序,直到整个数组有序。 
 
        而三路快速排序算法在快速排序的基础上进行了改进。它通过选择两个基准元素,将数组划分为三部分:小于第一个基准元素、等于第一个基准元素、大于第一个基准元素的元素。然后递归地对小于和大于基准元素的两部分进行排序,而不需要再对等于基准元素的部分进行排序,因为它们已经在正确的位置上。 
 
三路快速排序算法在处理包含大量重复元素的数组时表现更好,因为它能够更有效地处理重复元素,减少了不必要的比较和交换操作。相比于快速排序算法,三路快速排序算法的时间复杂度仍然是O(nlogn),但在某些情况下,它的性能更好。 
 
总的来说,三路快速排序算法是对快速排序算法的改进,通过减少重复元素的比较和交换操作,提高了排序的效率。

三、三路快排代码实现

/**
 * @Description 三路快排
 **/
public class ThreeWayQuickSort {

    public static void main(String[] args) {
        int[] array = {9, 8, 5, 9, 2, 9, 1, 2, 3, 4, 6, 8, 4, 7};
        quickSort(array, 0, array.length - 1);
        System.out.println("排序后的数组:");
        for (int num : array) {
            System.out.print(num + " ");
        }
    }

    // 三路快速排序算法
    public static void quickSort(int[] array, int low, int high) {
        if (low < high) {
            // 将数组划分为三部分,并返回等于pivot值的范围
            int[] range = partition(array, low, high);
            // 递归地对小于pivot和大于pivot的部分进行排序
            quickSort(array, low, range[0] - 1);
            quickSort(array, range[1] + 1, high);
        }
    }

    // 划分数组为三部分的函数
    public static int[] partition(int[] array, int low, int high) {
        int pivot = array[low]; // 选择第一个元素作为pivot
        int lt = low; // 初始化lt指针指向low
        int gt = high; // 初始化gt指针指向high
        int i = low + 1; // 初始化i指针指向low的下一个位置

        while (i <= gt) {
            if (array[i] < pivot) {
                swap(array, i, lt);
                i++;
                lt++;
            } else if (array[i] > pivot) {
                swap(array, i, gt);
                gt--;
            } else {
                i++;
            }
        }

        // 返回等于pivot值的范围
        int[] range = {lt, gt};
        return range;
    }

    // 交换数组中两个元素的函数
    public static void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

排序输出:

三路快速排序算法是一种高效的排序算法,它通过将数组划分为三个部分来进行排序:

小于pivot的部分、等于pivot的部分和大于pivot的部分。

下面是三路快速排序算法的实现思路步骤总结: 
 
1. 选择一个pivot元素(通常选择数组的第一个元素)。 
2. 初始化三个指针:lt指向数组的起始位置,gt指向数组的结束位置,i指向数组的起始位置的下一个位置。 
3. 从i开始遍历数组,比较当前元素与pivot的大小关系: 
   - 如果当前元素小于pivot,将它与lt指针指向的元素交换,并将lt和i指针都向右移动一位。 
   - 如果当前元素大于pivot,将它与gt指针指向的元素交换,并将gt指针向左移动一位。 
   - 如果当前元素等于pivot,将i指针向右移动一位。 
4. 重复步骤3,直到i指针遍历完整个数组。 
5. 最终,数组将被划分为三个部分:小于pivot的部分、等于pivot的部分和大于pivot的部分。 
6. 递归地对小于pivot和大于pivot的部分进行三路快速排序。 
 
三路快排算法通过将相等的元素放在中间,这样就避免了重复比较和交换的过程,从而提高了排序的效率。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据的备份和恢复

数据的备份和恢复 备份&#xff1a;完全备份 增量备份 完全备份&#xff1a;将整个数据库完整的进行备份 增量备份&#xff1a;在完全备份的基础之上&#xff0c;对后续新增的内容进行备份 备份的需求 1、在生产环境中&#xff0c;数据的安全至关重要、任何数据的丢失都可…

【10套模拟】【2】

关键字&#xff1a; 哈希函数解决问题、进栈、无向图边与度、双向链表插入新结点、折半查找判定树ASL、孩子兄弟表示法、树变二叉、快排partiction划分

十大排序算法C++实现

分类 复杂度 排序稳定性定义&#xff1a; 假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#xff0c;若经过排序&#xff0c;这些记录的相对次序保持不变&#xff0c;即在原序列中&#xff0c;A1A2&#xff0c;且A1在A2之前&#xff0c;而在排序后的序…

Django初窥门径-oauth登录认证

引言 在现代Web应用程序中&#xff0c;用户身份验证和授权是至关重要的组成部分。Django&#xff0c;一个流行的Python Web框架&#xff0c;为用户身份验证提供了内置支持。本文将探讨如何创建和注册Django应用&#xff0c;自定义身份验证服务&#xff0c;配置AUTHENTICATION_…

网络数据包传感器简化流量监控

数据包捕获基于数据包镜像的概念&#xff0c;可用于深度数据包检查、测量应用程序的响应时间以及监视服务器、网络和用户行为&#xff0c;该技术还可用于对需要特定信息的某些区域进行广泛分析&#xff0c;尽管它有效&#xff0c;但并非在所有情况下都是必要的。要分析和管理流…

【MogDB/openGauss误删未归档的xlog日志如何解决】

在使用MogDB/openGauss数据库的过程中&#xff0c;有时候大量业务&#xff0c;或者导数据会导致pg_xlog下的日志数量持续增长&#xff0c;此时如果xlog的产生频率太快&#xff0c;而来不及自动清理&#xff0c;极有可能造成pg_xlog目录的打满。如果对数据库的xlog不太了解的时候…

HTTP 协议详解-上(Fiddler 抓包演示)

文章目录 HTTP 协议HTTP 协议的工作过程HTTP 请求 (Request)认识URL关于 URL encode认识 "方法" (method)GET 方法POST 方法其他方法请求 "报头" (header)请求 "正文" (body) HTTP 响应详解状态码响应 "报头" (header) HTTP 协议 HTT…

仪表盘 gauge

option {tooltip: {formatter: {a} <br/>{b} : {c}%},series: [{name: Pressure,type: gauge,startAngle: 225, // 起始角度&#xff0c;同极坐标endAngle: -45, // 终止角度&#xff0c;同极坐标// axisLine: {// //坐标轴轴线// show: false// },// splitLine: {//…

RT-Thread 10. 使用keil4编译GD32F450

1. 修改keil路径 2.增加MCU型号宏定义 3. 在ENV界面输入 scons -c scons --targetmdk44. 编译 scons --verbose提示错误 Warning: L6310W: Unable to find ARM libraries. Error: L6411E: No compatible library exists with a definition of startup symbol __main. Finish…

Pytorch 里面torch.no_grad 和model.eval(), model.train() 的作用

torch.no_grad: 影响模型的自微分器&#xff0c;使得其停止工作&#xff1b;这样的话&#xff0c;数据计算的数据就会变快&#xff0c;内存占用也会变小&#xff0c;因为没有了反向梯度计算&#xff0c;当然&#xff0c;我哦们也无法做反向传播。 model.eval() 和model.train()…

C/C++数的输入输出 2021年6月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C数的输入输出 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C数的输入输出 2021年6月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 输入一个整数和双精度浮点数&#xff0c;先将浮…

Sui发布RPC2.0 Beta,拥抱GraphQL并计划弃用JSON-RPC

为了解决现有RPC存在的许多已知问题&#xff0c;Sui正在准备推出一个基于GraphQL的新RPC服务&#xff0c;名为Sui RPC 2.0。GraphQL是一种开源数据查询和操作语言&#xff0c;旨在简化需要复杂数据查询的API和服务。 用户目前可以访问Sui主网和测试网网络的Beta版本的只读快照…

如何以电商“API”接口的形式帮助电商商家解决货源及运营难题?

如何帮助电商商家解决货源及运营难题&#xff1f;API 接口创建供应链的突出优势应该就是“API”接口的开发与应用了&#xff0c;通过API技术接口&#xff0c;来帮助商家快速实现货源采购及上架等需要。那么具体来说&#xff0c;创胜货源供应链是如何以“API”的形式来帮助电商商…

[第二章—Spring MVC的高级技术] 2.2 置multipart解析器

使用Servlet 3.0解析multipart请求 兼容Servlet 3.0的StandardServletMultipartResolver没有构 造器参数&#xff0c;也没有要设置的属性。 这样&#xff0c;在Spring应用上下文中&#xff0c;将 其声明为bean就会非常简单&#xff0c;如下所示&#xff1a; ● 既然这个Bean方…

计算机毕业设计java+vue+springboot的论坛信息网站

项目介绍 本论文系统地描绘了整个网上论坛管理系统的设计与实现&#xff0c;主要实现的功能有以下几点&#xff1a;管理员&#xff1b;首页、个人中心、用户管理、公告管理、公告类型管理、热门帖子管理、帖子分类管理、留言板管理、论坛新天地、我的收藏管理、系统管理&#…

[C/C++]数据结构 链表OJ题: 反转链表

描述: 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表 示例: 方法一: 让链表指向反向 如图所示: 代码思路: struct ListNode* reverseList(struct ListNode* head) {struct ListNode* n1NULL;struct ListNode* n2head;struct ListNode*…

webgoat-Broken Access ControlI 访问控制失效

Insecure Direct Object References 直接对象引用 直接对象引用是指应用程序使用客户端提供的输入来访问数据和对象。 例子 使用 GET 方法的直接对象引用示例可能如下所示 https://some.company.tld/dor?id12345 https://some.company.tld/images?img12345 https://some.…

【C++】map set

map & set 一、关联式容器二、键值对三、树形结构的关联式容器1. set&#xff08;1&#xff09;set 的介绍&#xff08;2&#xff09;set 的使用 2. multiset3. map&#xff08;1&#xff09;map 的介绍&#xff08;2&#xff09;map 的使用 4. multimap 四、map 和 set 的…

零基础编程入门教程软件推荐,零基础编程自学

零基础编程入门教程软件推荐&#xff0c;零基础编程自学 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型的软件&#xff0c;象如图这个实例就是用…

freertos多任务

以前我们都是一个任务&#xff0c;假设现在我们创建三个任务,项目工程在上一节网盘 #include "stm32f10x.h" // Device header #include "freertos.h" #include "task.h" #include "usart.h"TaskHandle_t myTaskHan…