为什么堆排序的时间复杂度是O(N*logN)?

2024-04-24 23:28

本文主要是介绍为什么堆排序的时间复杂度是O(N*logN)?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

前言:

堆排序(以排升序为例)

步骤(用大根堆,倒这排,排升序):

1.先把要排列的数组建立成大根堆

2.堆顶元素(82)和最后一个元素交换(2)

3.无视掉交换后的元素(82),对(2)进行向下调整

翻译成代码

mian方法:

heapSortUp方法:

siftDown方法:

堆排序时间复杂度分析:


前言:

本文章以升序为例进行讲解(实际上两种排列时间复杂度都一样,只是比较方式建立大小堆恰好相反)

文章涉及:

1.向下调整算法

2.建堆的方式及其时间复杂度

3.堆排序步骤和时间复杂度分析

注意:如果1,2点还不了解,建议学习完之后在来学习堆排序,才能明白下边讲的是什么。

这里有小编自己写的链接,详细介绍了堆的创建以及向下/向上调整算法:优先级队列(堆)

堆排序(以排升序为例)

如果是排升序,要建立大根堆,反之亦然。

排降序,建立小堆

为什么?

看完他的原理,就知道了。


以数组array={

4,6, 82, 7, 8, 9, 3, 2

}

为例

步骤(用大根堆,倒这排,排升序):

1.先把要排列的数组建立成大根堆

2.堆顶元素(82)和最后一个元素交换(2)

3.无视掉交换后的元素(82),对(2)进行向下调整

此时又变成了大根堆(无视已经排好的82):

此时的82已经被排号了

其是堆排序的整体思路已经讲完了,接下来就是循环执行2,3点
3和9换位置,然后无视排好的82,9,对3进行向下调整:

在向下调整完之后,又是一个大根堆,我们继续,循环这个逻辑,最终的结果就变成了:

这时,就是一个升序的数组了。

翻译成代码

mian方法:

public class Test {public static void main(String[] args) {int[] arr = new int[]{4,6, 82, 7, 8, 9, 3, 2};//要排的数组BigHeap bigHeap = new BigHeap();//这个是我自己写的大根堆bigHeap.init(arr);//把数组传入对象bigHeap.creatHeap();//先建立起大堆bigHeap.heapSortUp();//进行堆排序}
}

heapSortUp方法:

1.我的堆,底层使用elem的数组实现的!!!!!

2.useSize是堆的容量

3.swap的两个参数都是数组的下标

public int[] heapSortUp() {int endIndex = useSize - 1;//最后一个下标的位置(也就是容量减1)while (endIndex > 0) {//如果等于零,就不用交换了swap(0, endIndex);//顶元素和最后一个元素交换endIndex--;//最后一个下标--,就可以起到无视排号数,的作用siftDown(0, endIndex);}return elem;}

siftDown方法:

public void siftDown(int parent, int end) {//parent end都是有效下标int child = 2 * parent + 1;//默认是左孩子while (child <= end) {//调整到最后一个子节点,为止//先判断是否有右孩子if (child + 1 <= end) {//如果有判断谁大,大的当左孩子if (elem[child] < elem[child + 1]) {child++;}}//左孩子在和父节点进行比较if (elem[child] > elem[parent]) {//如果孩子节点大,那么父子交换位置swap(child, parent);} else {break;//如果父节点已经是最大的就不用调整了,这棵树就是大根堆//因为我们会从后往前,把这棵树(数组)一次遍历调整完}//下面继续往往下面调整parent = child;//当前的父亲,变成自己的孩子child = parent * 2 + 1;//孩子变成孩子的孩子}}

堆排序时间复杂度分析:

其实很简单,上面我们一共说了三个方法:

1.main

2.heapSortUp

3.siftDown

我们从main方法切入,实际上执行堆排序的程序就是这两步:

 public static void main(String[] args) {int[] arr = new int[]{4,6, 82, 7, 8, 9, 3, 2};BigHeap bigHeap = new BigHeap();bigHeap.init(arr);//这两步:bigHeap.creatHeap();//先创建大根堆bigHeap.heapSortUp();//堆排序,内部实现等一下看}

学了堆我们都直到,建堆的时间复杂度是O(N)

然后在加上heapSortUp的时间复杂度,不就是堆排序的时间复杂度了吗?

具体看一下,heapSortUp:

 public int[] heapSortUp() {int endIndex = useSize - 1;while (endIndex > 0) {swap(0, endIndex);endIndex--;siftDown(0, endIndex);}return elem;}

useSize和siftDown是我们要计算的时间复杂度,其他都是常量不用管

useSize实际上就是所给数组的长度嘛,就是N咯

学了siftDown就是向下调整算法,向下调整算法向上调整算法的时间复杂度都是logN(以2为底)-----》至于怎么算的,可以看小编文章前言部分的链接

所以堆排序的时间复杂度==O(useSize)+O(siftDown)*O(creatHeap)=N+N*logN

然后取得最高阶,则时间复杂度就是O(N*logN)

这篇关于为什么堆排序的时间复杂度是O(N*logN)?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

python处理带有时区的日期和时间数据

《python处理带有时区的日期和时间数据》这篇文章主要为大家详细介绍了如何在Python中使用pytz库处理时区信息,包括获取当前UTC时间,转换为特定时区等,有需要的小伙伴可以参考一下... 目录时区基本信息python datetime使用timezonepandas处理时区数据知识延展时区基本信息

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Java中字符串转时间与时间转字符串的操作详解

《Java中字符串转时间与时间转字符串的操作详解》Java的java.time包提供了强大的日期和时间处理功能,通过DateTimeFormatter可以轻松地在日期时间对象和字符串之间进行转换,下面... 目录一、字符串转时间(一)使用预定义格式(二)自定义格式二、时间转字符串(一)使用预定义格式(二)自

Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码

《Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码》:本文主要介绍Java中日期时间转换的多种方法,包括将Date转换为LocalD... 目录一、Date转LocalDateTime二、Date转LocalDate三、LocalDateTim

golang获取当前时间、时间戳和时间字符串及它们之间的相互转换方法

《golang获取当前时间、时间戳和时间字符串及它们之间的相互转换方法》:本文主要介绍golang获取当前时间、时间戳和时间字符串及它们之间的相互转换,本文通过实例代码给大家介绍的非常详细,感兴趣... 目录1、获取当前时间2、获取当前时间戳3、获取当前时间的字符串格式4、它们之间的相互转化上篇文章给大家介

Feign Client超时时间设置不生效的解决方法

《FeignClient超时时间设置不生效的解决方法》这篇文章主要为大家详细介绍了FeignClient超时时间设置不生效的原因与解决方法,具有一定的的参考价值,希望对大家有一定的帮助... 在使用Feign Client时,可以通过两种方式来设置超时时间:1.针对整个Feign Client设置超时时间

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时