Java详细讲解堆排序与时间复杂度的概念
作者:淡沫初夏Zz 发布时间:2023-10-20 02:00:11
一、堆排序
1、什么是堆排序
(1)堆排序:堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
(2)堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
2、堆排序思想
(1)将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆
(2)将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端
(3)重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序
3、代码实现
import java.util.Arrays;
public class Sort {
//将任意数组进行原地堆排序
public static void heapSort(int[] arr) {
//把数组调整为最大堆,从最后一个非叶子节点开始下沉
for (int i = (arr.length-1-1)/2; i >= 0; i--) {
siftDown(arr,i,arr.length);
}
//将堆顶元素和最后一个元素交换
for (int i = arr.length-1; i > 0 ; i--) {
swap(arr,0,i);
siftDown(arr,0,i);
}
}
//下沉操作
private static void siftDown(int[] arr, int i, int n) {
while ((2 * i)+1 < n){
int j = (2 * i) + 1;
if(j+1<n && arr[j+1]>arr[j]){
j = j+1;
}
if(arr[i] >= arr[j]){
break;
}else{
swap(arr,i,j);
i = j;
}
}
}
public static void main(String []args){
int []arr = {7,6,7,11,5,12,3,0,1};
System.out.println("排序前:"+ Arrays.toString(arr));
heapSort(arr);
System.out.println("排序后:"+Arrays.toString(arr));
}
}
运行截图:
二、时间复杂度分析
1、初始化建堆
初始化建堆只需要对二叉树的非叶子节点由下至上,由右至左选取非叶子节点来调用adjusthead()函数。那么倒数第二层的最右边的非叶子节点就是最后一个非叶子结点。
假设高度为k,则从倒数第二层右边的节点开始,这一层的节点都要执行子节点比较然后交换;倒数第三层呢,则会选择其子节点进行比较和交换,如果没交换就可以不用再执行下去了。高层也是这样逐渐递归。
那么总的时间计算为:s = 2^( i - 1 ) * ( k - i );其中 i 表示第几层,2^( i - 1) 表示该层上有多少个元素,( k - i) 表示子树上要下调比较的次数。
S = n - log(n) -1,所以时间复杂度为:O(n)
2、排序重建堆
每次重建意味着有一个节点出堆,所以需要将堆的容量减一。adjustheap()函数的时间复杂度k=log(n),k为堆的层数。所以在每次重建时,随着堆的容量的减小,层数会下降,函数时间复杂度会变化。重建堆一共需要n-1次循环,每次循环的比较次数为log(i),则相加为:log2+log3+…+log(n-1)+log(n)≈log(n!)。
所以时间复杂度为O(nlogn)
3、总结
初始化建堆的时间复杂度为O(n),排序重建堆的时间复杂度为nlog(n),所以总的时间复杂度为O(nlogn),空间复杂度为O(1)。
来源:https://blog.csdn.net/qq_55660421/article/details/122380669


猜你喜欢
- 最近由于编程的需要,对 C# 的类型转换做了一些研究,其内容涉及 C# 的装箱/拆箱/别名、数值类型间相互转换、字符的 ASCII 码和 U
- 本文将引导大家做一个音乐播放器,在做这个Android开发实例的过程中,能够帮助大家进一步熟悉和掌握学过的List
- 本文实例总结了C#中多态、重载与重写的概念与区别。对于初学C#的朋友来说有不错的参考价值。分享给大家供大家参考。具体分析如下:重写:是指重写
- 本文研究的主要内容是Java编程二项分布的递归和非递归实现,具体如下。问题来源:算法第四版 第1.1节 习题27:return (1.0 -
- 看似很鸡肋其实在某些特殊场景还是比较有用的。比如你将实体类转Map或者拿到一个Map结果的时候,你是怎么获取某个map的key和value。
- public static string Replace(string source, string match, string repla
- @RequestBody和@ResponseBody及Stringify()的作用首先,在项目的前后交互中json数据格式比较常用,普遍认为
- MyBatis插入Insert、InsertSelective的区别逆向自动生成的mybatis对应配置Mapper文件里面,有两个方法,分
- 在学习C#语言的时候,首先要学习控制台的应用程序,这样才能专注于语言的学习,减少学习的梯度,也有利于输出自己需要输出的内容。因此第一步学习C
- 服务端:using System;using System.Collections.Generic;using System.Net;usi
- 一. 简介 俩个数据库db1,db2, db1数据库的map
- Android动画 实现开关按钮动画(属性动画之平移动画),最近做项目,根据项目需求,有一个这样的功能,实现类似开关的动画效果,经过自己琢磨
- 需求:视频通话界面,两个surfaceView一个显示本端的视图,另一个显示对端的视图,由于显示比例的问题总会存在一个覆盖另一个的问题,为保
- 这个模拟功能的实现主要依靠了PATH和二阶贝塞尔曲线。首先上一张图来简单看一下:这个模拟功能有以下几个特点:在开始的时候点击圆以外的区域不会
- ViewModel的创建方式在我们项目中, 引入了viewModel 做MVI 设计模式的组成部分,它是JetPack 组件库中的重要成员。
- Java语言的垃圾回收1.垃圾回收机制的基本概念问:1.什么是Java垃圾回收?答:在Java语言的生命周期中,Java运行环境提供了一个系
- 本文实例讲述了C#获取机器码的方法。分享给大家供大家参考,具体如下:using System.Runtime.InteropServices
- Java中的我们可以利用split把字符串按照指定的分割符进行分割,然后返回字符串数组split 方法该方法的作用是:将一个字符串分割为子字
- 本文将通过阅读spring源码,分析@ComponentScan注解扫描组件的原理。和@Bean注解一样,@ComponentScan注解也
- 我们玩玩手机的录像功能吧。做个DEMO。 看看录制过程: mediarecorder = new MediaRecorder();// 创建