堆排及时间复杂度分析

2024-02-08 19:44
文章标签 分析 复杂度 时间 堆排

本文主要是介绍堆排及时间复杂度分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

箴言:

初始阶段,不需要去纠结那一种更优美,非要找出那一种是最好的,其实能解决问题的就是好办法。

一,常见排序时间复杂度

冒泡快排归并堆排桶排
时间O(n^2)O(nlogn)O(nlogn)O(nlogn)kn
空间O(1)O(1)O(nlogn)O(1)kn

二,堆排

前情提要:

堆属于完全树,完全树可以理解为一个数组。如果不是完全树,就没办法和数组等价,就不会有下面这种父级和子级之间的关系。

已知父级下标i
左孩子下标: 2*i+1
右孩子下标: 2*i+2
已知孩子结点j(无论左还是右)
父级下标 (j-1)/2

堆排序过程:

堆排序分成两个阶段,第一个阶段从由无序数组建立一个大/小根堆,第二个阶段在大/小根堆的基础上调整,形成有序数组。

从无序数组到大根堆:

对于数组中每一个元素,我们需要将其和其父级做对比,若比父级大,则进行交换,直到最顶层为止。

代码:(其实找父亲的时候可以不区分左右减一除二即可,我这里就不改了)

    public static void builddui(int[] arr) {for (int i = 0; i < arr.length; i++) {int j = i;int p = 0;if (j % 2 == 1) {//左孩子p = (j - 1) / 2;} else {p = (j - 2) / 2;//右孩子}while (p >= 0 && arr[p] < arr[j]) {int t = arr[p];//交换位置arr[p] = arr[j];arr[j] = t;j = p;p = (j - 1) / 2;}}}

从大根堆到有序序列:

最后一个位置和堆顶交换,将交换之后的堆顶下沉到正确的位置。然后堆顶和倒数第二个交换,堆顶下沉到正确的位置,直到剩下一个为止。这是一个堆顶元素不断下沉的过程。

代码:(r表示的是最后一个的索引位置)

    public static void weichidui(int[] arr, int r) {int t = arr[r];arr[r] = arr[0];arr[0] = t;int cur = 0;//当前下标while (2 * cur + 1 < r) {int index = 2 * cur + 1;int maxv = arr[index];if (2 * cur + 2 < r && arr[index] < arr[2 * cur + 2]) {index = 2 * cur + 2;maxv = arr[2 * cur + 2];}if (maxv > arr[cur]) {int tmp = arr[cur];arr[cur] = arr[index];arr[index] = tmp;}cur = index;}}

时间复杂度分析:

上述两个阶段分别分析: 从无序序列到建成大顶堆: 已知数组中数量为n,每正确插入一个元素,时间复杂度为logn(因为树的深度为logn),因为插入n个元素,时间复杂度为nlogn。

从大顶堆到有序序列:每次首尾交换之后都需要将堆顶元素下沉到正确的位置,时间复杂度为logn(因为树的深度为logn,比较交换次数其实是小于logn的,但是理解为logn就行),需要下沉n次,所以时间复杂度是nlogn。

ABOVE ALL,堆排时间复杂度为2nlogn,也就是O(nlogn),一切操作都是在原数组上进行的操作,所以空间复杂度为O(1)。

堆排序是一个完美的排序方式,无论时间或者空间,数据量小的时候差距不明显,数据量越大,优势就会越明显。

代码:

数组:[34,56,23,33,5,46,4,57,6,76,34,42,634,6,536,3,3423,3,1,5,537,3,57,3563,4,65,764,4]

import java.util.Arrays;/*** @Author YuLing* @Date 2024-02-07 19:14* @Description:* @Version 1.0*/
public class dui {public static void main(String[] args) {int[] arr = new int[]{34,56,23,33,5,46,4,57,6,76,34,42,634,6,536,3,3423,3,1,5,537,3,57,3563,4,65,764,4};builddui(arr);System.out.println(Arrays.toString(arr));for (int i = 0; i < arr.length; i++) {weichidui(arr,  arr.length - 1 - i);}System.out.println(Arrays.toString(arr));}public static void builddui(int[] arr) {for (int i = 0; i < arr.length; i++) {int j = i;int p = 0;if (j % 2 == 1) {//左孩子p = (j - 1) / 2;} else {p = (j - 2) / 2;//右孩子}while (p >= 0 && arr[p] < arr[j]) {int t = arr[p];//交换位置arr[p] = arr[j];arr[j] = t;j = p;p = (j - 1) / 2;}}}public static void weichidui(int[] arr, int r) {int t = arr[r];arr[r] = arr[0];arr[0] = t;int cur = 0;//当前下标while (2 * cur + 1 < r) {int index = 2 * cur + 1;int maxv = arr[index];if (2 * cur + 2 < r && arr[index] < arr[2 * cur + 2]) {index = 2 * cur + 2;maxv = arr[2 * cur + 2];}if (maxv > arr[cur]) {int tmp = arr[cur];arr[cur] = arr[index];arr[index] = tmp;}cur = index;}}
}

输出:

[3563, 634, 3423, 57, 537, 764, 76, 34, 6, 56, 57, 46, 536, 4, 6, 3, 33, 3, 1, 5, 5, 3, 34, 23, 4, 42, 65, 4]
[1, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 23, 33, 34, 34, 42, 46, 56, 57, 57, 65, 76, 536, 537, 634, 764, 3423, 3563]

这篇关于堆排及时间复杂度分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/692028

相关文章

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

Python 标准库time时间的访问和转换问题小结

《Python标准库time时间的访问和转换问题小结》time模块为Python提供了处理时间和日期的多种功能,适用于多种与时间相关的场景,包括获取当前时间、格式化时间、暂停程序执行、计算程序运行时... 目录模块介绍使用场景主要类主要函数 - time()- sleep()- localtime()- g

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专

如何用Java结合经纬度位置计算目标点的日出日落时间详解

《如何用Java结合经纬度位置计算目标点的日出日落时间详解》这篇文章主详细讲解了如何基于目标点的经纬度计算日出日落时间,提供了在线API和Java库两种计算方法,并通过实际案例展示了其应用,需要的朋友... 目录前言一、应用示例1、天安门升旗时间2、湖南省日出日落信息二、Java日出日落计算1、在线API2

Spring中Bean有关NullPointerException异常的原因分析

《Spring中Bean有关NullPointerException异常的原因分析》在Spring中使用@Autowired注解注入的bean不能在静态上下文中访问,否则会导致NullPointerE... 目录Spring中Bean有关NullPointerException异常的原因问题描述解决方案总结

如何使用 Bash 脚本中的time命令来统计命令执行时间(中英双语)

《如何使用Bash脚本中的time命令来统计命令执行时间(中英双语)》本文介绍了如何在Bash脚本中使用`time`命令来测量命令执行时间,包括`real`、`user`和`sys`三个时间指标,... 使用 Bash 脚本中的 time 命令来统计命令执行时间在日常的开发和运维过程中,性能监控和优化是不

python中的与时间相关的模块应用场景分析

《python中的与时间相关的模块应用场景分析》本文介绍了Python中与时间相关的几个重要模块:`time`、`datetime`、`calendar`、`timeit`、`pytz`和`dateu... 目录1. time 模块2. datetime 模块3. calendar 模块4. timeit