LeetCode--排序算法(堆排序、归并排序、快速排序)

排序算法

  • 归并排序
    • 算法思路
    • 代码
    • 时间复杂度
  • 堆排序
    • 什么是堆?
    • 如何维护堆?
    • 如何建堆?
    • 堆排序
    • 时间复杂度
  • 快速排序
    • 算法思想
    • 代码
    • 时间复杂度

归并排序

算法思路

归并排序算法有两个基本的操作,一个是,也就是把原数组划分成两个子数组的过程。另一个是,它将两个有序数组合并成一个更大的有序数组。

将待排序的线性表不断地切分成若干个子表,直到每个子表只包含一个元素,这时,可以认为只包含一个元素的子表是有序表。
将子表两两合并,每合并一次,就会产生一个新的且更长的有序表,重复这一步骤,直到最后只剩下一个子表,这个子表就是排好序的线性表。
在这里插入图片描述

代码

// 归并排序
public int[] sortArray(int[] nums) {return mergeSort(nums, 0, nums.length - 1);
}private int[] mergeSort(int[] nums, int left, int right) {// 递归终止条件if (left >= right) {// 返回单个元素的数组return new int[]{nums[left]};}// 分治int mid = (left 0+ right) / 2;// 分别对左右子数组进行排序int[] leftArr = mergeSort(nums, left, mid);int[] rightArr = mergeSort(nums, mid + 1, right);int[] res = new int[leftArr.length + rightArr.length];// 合并两个有序数组int i = 0, j = 0, k = 0;while (i < leftArr.length && j < rightArr.length) {if (leftArr[i] <= rightArr[j]) {res[k++] = leftArr[i++];} else {res[k++] = rightArr[j++];}}while (i < leftArr.length) {res[k++] = leftArr[i++];}while (j < rightArr.length) {res[k++] = rightArr[j++];}return res;
}

时间复杂度

O(nlogn)

堆排序

什么是堆?

如下图(大根堆)(二叉)堆是一个数组,它可以被看成一个完全二叉树。
二叉树形式:
在这里插入图片描述
数组形式:
在这里插入图片描述
堆的根节点在数组中的下标为0,我们很容易得到左孩子为1,右孩子为2,第i个节点的左孩子为2i+1,右孩子为2i+2 。
二叉堆分为两种形式:大根堆和小根堆。大根堆性质,根节点的值大于所以子树节点的值。小根堆性质,根节点的值小于所以子树节点的值。

如何维护堆?

Java代码维护大根堆:

//维护大根堆
private void heapify(int n,int i) {//当前根节点int largest = i;//左孩子节点int lchild = 2*i+1;//右孩子节点int rchild = 2*i+2;//找三个元素最大的作为父节点if (lchild < n && nums[lchild] > nums[largest]) {largest = lchild;}if (rchild < n && nums[rchild] > nums[largest]) {largest = rchild;}//如果交换则维护交换后的if (largest != i) {swap(largest,i);heapify(n,largest);}
}

问题:为啥交换后,只需要维护交换后的子节点呢?
举一个例子:
在这里插入图片描述
根节点需要跟左孩子交换,交换后,根节点的右子树并未改变树结构,则只需要递归维护根节点左子树的堆性质。

如何建堆?

我们可以用自低向上的方法利用上面维护堆的算法heapify来建堆。子数组从n/2开始都是树的叶子节点。每个叶子节点可以被看成包含一个元素的堆。所以建堆的过程从n/2-1–>0 。

//1.建堆//从最后一个有孩子的节点开始 n/2-1for (int i = n/2-1; i >= 0; i--) {heapify(n,i);}

堆排序

前面我们利用建堆算法成功建立一个大根堆。因为数组最大元素总在根节点nums[0]中,通过把它与nums[n-1]交换,我们可以让该元素放到正确的位置。这时候,如果我们从堆中去掉节点n-1,剩余节点中根的孩子结点仍然是大根堆,而新的根节点可能违背大根堆性质。为了维护大根堆性质,需要不断调用 heapify 从而在nums 上构建一个新的大根堆。堆排序算法会不断重复这个过程,直到堆的大小从n-1降到1 。

给出完整的堆排序算法:

private int[] nums;// 待排序数组
//堆排序									
private void heap_sort(int n) {//1.建堆//从最后一个有孩子的节点开始 n/2-1for (int i = n/2-1; i >= 0; i--) {heapify(n,i);}//2.堆排序for (int i = n-1; i > 0; i--) {swap(i,0);//交换最后一个和根元素heapify(i,0);//交换后维护}
}
//维护大根堆
private void heapify(int n,int i) {int largest = i;int lchild = 2*i+1;int rchild = 2*i+2;//找三个元素最大的作为父节点if (lchild < n && nums[lchild] > nums[largest]) {largest = lchild;}if (rchild < n && nums[rchild] > nums[largest]) {largest = rchild;}//如果交换则维护交换后的if (largest != i) {swap(largest,i);heapify(n,largest);}
}private void swap(int i,int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;
}

时间复杂度

O(nlogn)

快速排序

算法思想

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序算法通过多次比较和交换来实现排序,其排序流程如下:

1、首先设定一个基数,通过该基数将数组分成左右两部分。

2、将大于或等于基数的数据集中到数组右边,小于基数的数据集中到数组的左边。此时,左边部分中各元素都小于或等于基数,而右边部分中各元素都大于或等于基数。

3、然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个基数,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。

4、重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。

概括来说为 挖坑填数 + 分治法。
在这里插入图片描述

代码

代码中使用Random作为随机生成器生成基数,思想不变,只是基数选取的方式改变。

private int[] nums;
// 随机数生成器, 用于生成选择基数元素
private final Random random = new Random();public int[] sortArray(int[] nums) {this.nums = nums;quickSort(0, nums.length - 1);return nums;
}
public void quickSort(int left, int right) {// 递归终止条件if (left >= right) {return;}// 调用partition函数,对数组进行分区,并获取基准元素的最终位置int pivot = partition(left, right);// 递归调用,对左子数组进行快速排序quickSort(left, pivot - 1);// 递归调用,对右子数组进行快速排序quickSort(pivot + 1, right);
}
public int partition(int left, int right) {// 生成一个随机的基准元素位置int pivot = random.nextInt(right - left + 1) + left;// 保存基准元素的值int pivotVal = nums[pivot];// 将基准元素交换到数组的最后一个位置swap(pivot, right);// 定义两个指针,i指向数组的最左边,j指向数组的最右边int i = left, j = right;while (i < j) {// 从左向右找到第一个大于等于基准元素的位置while (i < j && nums[i] <= pivotVal) {i++;}// 从右向左找到第一个小于等于基准元素的位置while (i < j && nums[j] >= pivotVal) {j--;}// 如果i和j指向的位置不合法,则交换i和j指向的元素if (i < j) {swap(i, j);}}// 将基准元素交换到正确的位置swap(i, right);return i;
}public void swap(int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;
}

时间复杂度

O(nlogn)

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

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

相关文章

加密流量TLS1.2 和TLS1.3的握手区别

加密流量TLS1.2 和TLS1.3的握手区别 TLS1.2 握手均是明文 1&#xff09;Client Hello 2&#xff09;Server Hello 3&#xff09;Certificate TLS1.3 握手中Client Hello是明文&#xff0c;而Server Hello中Extensions以及后面的握手信息不可见 1&#xff09;Client Hello…

5分钟掌握python中的匿名函数

lambda表达式&#xff0c;又称匿名函数&#xff0c;常用来表示内部仅包含1行表达式的函数。如果一个函数的函数体仅有 1 行表达式&#xff0c;则该函数就可以 用 lambda 表达式来代替。 lambda 表达式的语法格式如下&#xff1a; name lambda [list] : 表达式 其中&#xff…

单元测试3.0+ @RunWith(JMockit.class)+mock+Expectations

Jmockit使用笔记_基本功能使用Tested_Injectable_Mocked_Expectations_jmockit.class-CSDN博客 测试框架Jmockit集合junit使用 RunWith(JMockit.class) 写在测试案例类上的注解 Tested 在测试案例中,写在我们要测试的类上面, 一般用实现类 Injectable 在测试案例中声明…

保姆级教程Docker部署ClickHouse镜像

目录 1、安装Docker及可视化工具 2、创建挂载目录 3、获取配置文件 4、运行ClickHouse容器 5、Compose运行ClickHouse容器 6、查看ClickHouse运行状态 7、安装包部署 1、安装Docker及可视化工具 Docker及可视化工具的安装可参考&#xff1a;Ubuntu上安装 Docker及可视化…

如何通过深度学习提升大分辨率图像预测准确率?

随着科技的不断进步&#xff0c;图像处理在各个领域的应用日益广泛&#xff0c;特别是在医疗影像、卫星遥感、自动驾驶、安防监控等领域中&#xff0c;大分辨率图像的使用已经成为了一项不可或缺的技术。然而&#xff0c;大分辨率图像带来了巨大的计算和存储压力&#xff0c;同…

Spring实现Logback日志模板设置动态参数

版权说明&#xff1a; 本文由博主keep丶原创&#xff0c;转载请保留此块内容在文首。 原文地址&#xff1a; https://blog.csdn.net/qq_38688267/article/details/144842327 文章目录 背景设计日志格式实现配置动态取值logback-spring.xml 背景 多个单体服务间存在少量交互&…

【无线传感网】无线传感器网络拓扑控制技术

文章目录 拓扑控制的意义影响整个网络的生存时间减小节点间通信干扰&#xff0c;提高网络通信效率为路由协议、时间同步提供基础影响数据融合弥补节点失效的影响 拓扑控制的设计目标能量消耗覆盖度连通性算法的分布式程度网络延迟&#x1f6a9;干扰和竞争对称性鲁棒性和可扩展性…

如何在没有 iCloud 的情况下将联系人从 iPhone 传输到 iPhone

概括 近期iOS 13.5的更新以及苹果公司发布的iPhone SE在众多iOS用户中引起了不小的轰动。此外&#xff0c;不少变化&#xff0c;如暴露通知 API、Face ID 增强功能以​​及其他在 COVID-19 期间与公共卫生相关的新功能&#xff0c;吸引了 iPhone 用户尝试新 iPhone 并更新到最…

matlab 设计滤波器

滤波器可视化工具 fvtool 与 filterAnalyzer 设计滤波器&#xff1a; matlab 菜单栏 APP - 滤波器设计

Keil中的gcc

文章目录 一、IDE背后的命令1.1 IDE是什么1.2 IDE的背后是命令1.3 有两套主要的编译器 二、准备工作2.1 arm-linux-gcc和gcc是类似的2.2 Code::Blocks2.2.1 设置windows环境变量2.2.2 命令行示例 三、gcc编译过程详解3.1 程序编译4步骤3.2 gcc的使用方法3.2.1 gcc使用示例3.2.2…

SQL-Server链接服务器访问Oracle数据

SQL Server 链接服务器访问 Oracle 离线安装 .NET Framework 3.5 方法一&#xff1a;使用 NetFx3.cab 文件 下载 NetFx3.cab 文件&#xff0c;并将其放置在 Windows 10 系统盘的 C:Windows 文件夹中。 以管理员身份运行命令提示符&#xff0c;输入以下命令并回车&#xff1a; …

关于easy-es对时间范围查询遇到的小bug

前言&#xff1a;在使用easy-es之前作为一个小白的我只有es原生查询的基础&#xff0c;在自己通过查看官方文档自学easy-es遇到了一个挫折&#xff0c;其他的还好语法和MybatisPlus差不多&#xff0c;正以为我觉得很快就能入手&#xff0c;在对时间范围的判断就给我当头一棒&am…

typora+picgo core+minio自动上传图片

1. 在服务器上安装docker版本minio 创建/docker/minio文件夹 mkdir -p /docker/minio在此文件夹创建docker-compose.yml version: "3.5" services:minio:image: quay.io/minio/minio:latestcontainer_name: minioprivileged: truerestart: alwaysports:# API接口访…

WebRTC线程的启动与运行

WebRTC线程运行的基本逻辑&#xff1a; while(true) {…Get(&msg, …);…Dispatch(&msg);… }Dispatch(Message *pmsg) {…pmsg->handler->OnMessage(pmsg);… }在执行函数内部&#xff0c;就是一个while死循环&#xff0c;只做两件事&#xff0c;从队列里Get取…

【OceanBase】使用 Superset 连接 OceanBase 数据库并进行数据可视化分析

文章目录 前言一、前提条件二、操作步骤2.1 准备云主机实例2.2 安装docker-compose2.3 使用docker-compose安装Superset2.3.1 克隆 Superset 的 GitHub 存储库2.3.2 通过 Docker Compose 启动 Superset 2.4 开通 OB Cloud 云数据库2.5 获取连接串2.6 使用 Superset 连接 OceanB…

我们能否使用 ANSYS SPEOS 测量水质?

介绍 Ansys SPEOS 是动态环境科学领域的尖端工具&#xff0c;可为围绕水质管理的复杂问题提供深入的见解和创新解决方案。通过其光学系统功能&#xff0c;它为理解和改善不同环境的生态动态提供了一个强大的框架。 主要特点和优势 多材质建模&#xff1a; 为了准确模拟环境…

简易屏幕共享工具-基于WebSocket

前面写了两个简单的屏幕共享工具&#xff0c;不过那只是为了验证通过截屏的方式是否可行&#xff0c;因为通常手动截屏的频率很低&#xff0c;而对于视频来说它的帧率要求就很高了&#xff0c;至少要一秒30帧率左右。所以&#xff0c;经过实际的截屏工具验证&#xff0c;我了解…

论文分享 | PromptFuzz:用于模糊测试驱动程序生成的提示模糊测试

大语言模型拥有的强大能力可以用来辅助多种工作&#xff0c;但如何有效的辅助仍然需要人的精巧设计。分享一篇发表于2024年CCS会议的论文PromptFuzz&#xff0c;它利用模型提示生成模糊测试驱动代码&#xff0c;并将代码片段嵌入到LLVM框架中执行模糊测试。 论文摘要 制作高质…

2024年底关于期货的工作总结

十几年程序猿出身&#xff0c;因几年前的懵懂无畏闯入期货市场&#xff0c;盈了&#xff0c;感觉期货太简单&#xff0c;飘然裸辞&#xff0c;想当财务自由者&#xff0c;全职做交易。当深入学习时&#xff0c;却亏了&#xff0c;原来市场是让人敬畏的&#xff0c;也是反人性的…

mybatis 和 mybatisPlus 兼容性问题

项目采用的是 mybatis&#xff0c; 后续引入了 mybatisPlus&#xff0c;用 mybatisX 创建的四个类一直报错&#xff0c;提示找不到符号&#xff0c;意识到 mybatis 和 mybatisPlus 的兼容性问题&#xff0c;通过修改配置 两者的配置如下 #配置mybatis配置 mybatis:type-aliase…