堆(逐个添加元素创建堆)-堆结构的创建+堆结构的实际应用

2024-09-07 01:44

本文主要是介绍堆(逐个添加元素创建堆)-堆结构的创建+堆结构的实际应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、问题引入

一堆数据的值不断变化,我们想要从这堆数据中获取到最大值或者最小值(比如电影排行榜中电影的排名,每部电影观看人数越多,那么该部电影的排名就越高)

1、数据结构解决的是数据的存储问题,算法解决的是存储了的数据的使用效率问题

2、数据结构里面的堆结构(heap)和Java语言中的数据堆不一样

3、数据结构里面的堆结构本质上是数组

4、数组的元素查询效率高(由于使用索引查询),时间复杂度为O(1),元素删除效率低(由于删除一个元素需要移动很多其他的元素)

5、二叉树的元素删除效率高(由于只需逐级调整),删除元素的时间复杂度为O(log_{2}^{n})

6、二叉树(平衡二叉树、满二叉树、完全二叉树)

完全二叉树:深度为h的二叉数,除到底h层外,其他各层(第1层到第(h-1)层)的结点数都达到最大数目,且第h层所有的结点都连续集中在最左边,具备这两个特点的二叉树就是完全二叉树

二、认识堆

1、堆的定义

(1)堆(heap)是计算机科学中一类特殊的数据结构的统称

(2)堆是一个可以被看作一棵树的数组对象(即将数组元素以特殊完全二叉树的形式在数组中进行存储的,特殊在子父结点在数组中的索引会满足一定的数学关系/即元素在数组中存储,但以完全二叉树结点的规律进行使用)

(3)堆的本质就是将数组元素转换为特殊完全二叉树的形式在数组中实现存储

(4)构建堆的本质就是利用堆的方式将数组中的元素在数组中进行重新排列

(5)堆最终是为优先队列准备的

2、堆的分类

(1)最大堆:根结点最大的堆,又称大根堆

(2)最小堆:根结点最小的堆,又称小根堆

3、堆的特点

(1)堆中某个结点(即元素)的值总是不大于(大根堆)或不小于(小根堆)其父结点的值

(2)一个堆可以等效于一棵完全二叉树(将堆数组中的元素从前向后按照完全二叉树的形式从上向下从左到右进行排列即可得到堆数组等效的完全二叉树)

4、完全二叉树父结点与子结点在堆数组中索引间的关系

(1)左子结点索引=父结点索引*2+1

(2)右结点索引=父结点索引*2+2

(3)父结点索引=(子结点索引-1)/2(除根结点外,根结点没有父结点)

三、创建堆

1、泛型:因为堆中的数据的类型可能为复杂数据类型,因此在创建堆时要使用泛型来规范堆中存储的数据的类型

2、新元素添加要比较:在向堆中填加新元素时必须要比较大小,因此在定义泛型时要扩展泛型,使得堆中的数据允许进行比较

public class MyHeap <T extends Comparable<T>>{}

3、泛型在通过new赋值时必须使用给定类型来new

elements=(T[])new Comparable[DEFAULT_SIZE];

4、最大堆的效率分析

(1)获取堆顶元素的时间复杂度为O(1)

(2)向堆中添加元素的时间复杂度为O(h)=O(log_{2}^{n})

三、堆的核心代码

package com.ffyc.heap;public class MyHeap <T extends Comparable<T>>{private final int DEFAULT_SIZE = 10;// 使用数组作为存储结构的数据结构数组在初始时必须有一个默认长度private T[] elements;private int size;// 堆的容量大小(堆实际存储的元素的数目),数据结构删除元素并没有真正删除,只是让删除元素无法被访问到public MyHeap(){elements=(T[])new Comparable[DEFAULT_SIZE];// 向下转型}private int getParentIndex(int index){return index==0?-1:(index-1)/2;}private int getLeftIndex(int index){return index*2+1;}private void swap(int i,int j){T tmp=elements[i];elements[i]=elements[j];elements[j]=tmp;}/*** 上浮:将元素放在最后一个位置,不停地逐级向上进行比较,如果比父元素大,则与父元素交换位置,直至比到不能比的时候,将元素放在合适的位置上* @param index 要上浮结点的索引*/private void floatUp(int index){// 获得父结点的索引int parentIndex=getParentIndex(index);while (parentIndex != -1&&elements[index].compareTo(elements[parentIndex])>0){swap(index, parentIndex);// 迭代法index = parentIndex;parentIndex=getParentIndex(index);}}// 添加数据public void offer(T data){elements[size++]=data;// 上浮问题 调整末尾元素的位置floatUp(size-1);}// 判断堆是否为空public boolean isEmpty(){return size==0;}// 获得堆顶元素public T peek(){if(isEmpty())return null;return elements[0];}@Overridepublic String toString() {StringBuilder sb=new StringBuilder("[");for (int i = 0; i < size; i++) {sb.append(elements[i]+",");}sb.deleteCharAt(sb.length()-1);sb.append("]");return sb.toString();}private void swimDown(int parentIndex){T swimData=elements[parentIndex];int currentIndex=parentIndex;int leftIndex=getLeftIndex(currentIndex);while(leftIndex<size){int rightIndex=leftIndex+1;int highIndex=leftIndex;// 子结点的最大值的索引if(leftIndex < size && elements[highIndex].compareTo(elements[rightIndex])<0){highIndex=rightIndex;}if(swimData.compareTo(elements[highIndex])<0){swap(currentIndex, highIndex);currentIndex=highIndex;leftIndex=getLeftIndex(currentIndex);}else{break;}}}// 删除堆顶元素public T poll(){if(isEmpty()) return null;// 交换堆顶元素和最后一个元素的位置(使用最后一个元素覆盖堆顶元素)T data=elements[0];elements[0]=elements[--size];// 下沉问题 调整堆顶元素的位置swimDown(0);return data;}}

四、堆的应用

1、从一堆数据中获取第二大数据但至多只能用一次while循环(微软面试题,不能用Arrays类中的sort方法)

public static void main(String[] args) {MyHeap<Integer>myHeap=new MyHeap<>();myHeap.offer(3);myHeap.offer(7);myHeap.offer(5);myHeap.offer(8);myHeap.offer(2);myHeap.offer(4);myHeap.offer(1);myHeap.poll();System.out.println(myHeap.peek());}

2、获取所有新闻中点击量最大的新闻的id

package com.ffyc.heap;public class News implements Comparable<News>{private int id;// 新闻的唯一标识private int count;// 新闻的点击量public News(int id, int count) {this.id = id;this.count = count;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}@Overridepublic int compareTo(News o) {return this.count-o.getCount();}public static void main(String[] args) {MyHeap<News>myHeap=new MyHeap<>();myHeap.offer(new News(1, 15));myHeap.offer(new News(2, 25));myHeap.offer(new News(3, 13));myHeap.offer(new News(4, 12));myHeap.offer(new News(5, 27));// 获得新闻排行榜点击量最高的新闻的idSystem.out.println(myHeap.peek().getId());// 将新闻排行榜点击量最高的新闻的id下架myHeap.poll();System.out.println(myHeap.peek().getId());}
}

五、堆的缺点(通过逐个添加元素创建的堆)

无法实现改变其中一个新闻的点击量后实现所有新闻的重新排名(根据点击量的大小进行排名)

这篇关于堆(逐个添加元素创建堆)-堆结构的创建+堆结构的实际应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

C语言函数递归实际应用举例详解

《C语言函数递归实际应用举例详解》程序调用自身的编程技巧称为递归,递归做为一种算法在程序设计语言中广泛应用,:本文主要介绍C语言函数递归实际应用举例的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录前言一、递归的概念与思想二、递归的限制条件 三、递归的实际应用举例(一)求 n 的阶乘(二)顺序打印

Python中随机休眠技术原理与应用详解

《Python中随机休眠技术原理与应用详解》在编程中,让程序暂停执行特定时间是常见需求,当需要引入不确定性时,随机休眠就成为关键技巧,下面我们就来看看Python中随机休眠技术的具体实现与应用吧... 目录引言一、实现原理与基础方法1.1 核心函数解析1.2 基础实现模板1.3 整数版实现二、典型应用场景2

idea中创建新类时自动添加注释的实现

《idea中创建新类时自动添加注释的实现》在每次使用idea创建一个新类时,过了一段时间发现看不懂这个类是用来干嘛的,为了解决这个问题,我们可以设置在创建一个新类时自动添加注释,帮助我们理解这个类的用... 目录前言:详细操作:步骤一:点击上方的 文件(File),点击&nbmyHIgsp;设置(Setti

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

使用Java实现通用树形结构构建工具类

《使用Java实现通用树形结构构建工具类》这篇文章主要为大家详细介绍了如何使用Java实现通用树形结构构建工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录完整代码一、设计思想与核心功能二、核心实现原理1. 数据结构准备阶段2. 循环依赖检测算法3. 树形结构构建4. 搜索子

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

Java中&和&&以及|和||的区别、应用场景和代码示例

《Java中&和&&以及|和||的区别、应用场景和代码示例》:本文主要介绍Java中的逻辑运算符&、&&、|和||的区别,包括它们在布尔和整数类型上的应用,文中通过代码介绍的非常详细,需要的朋友可... 目录前言1. & 和 &&代码示例2. | 和 ||代码示例3. 为什么要使用 & 和 | 而不是总是使

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa