数据结构与算法七 堆

news2024/12/23 10:54:51

一 堆

1.1 堆定义

堆是计算机科学中一类特殊的数据结构的统称,堆通常可以被看做是一棵完全二叉树的数组对象。

堆的特性:

  1. 它是完全二叉树,除了树的最后一层结点不需要是满的,其它的每一层从左到右都是满的,如果最后一层结点不是满的,那么要求左满右不满。
    在这里插入图片描述

  2. 它通常用数组来实现
    具体方法就是将二叉树的结点按照层级顺序放入数组中,根结点在位置1,它的子结点在位置2和3,而子结点的子结点则分别在位置4,5,6和7,以此类推。
    在这里插入图片描述
    如果一个结点的位置为k,则它的父结点的位置为[k/2],而它的两个子结点的位置则分别为2k和2k+1。这样,在不使用指针的情况下,我们也可以通过计算数组的索引在树中上下移动:从a[k]向上一层,就令k等于k/2,向下一层就令k等于2k或2k+1。

  3. 每个结点都大于等于它的两个子结点。这里要注意堆中仅仅规定了每个结点大于等于它的两个子结点,但这两个子结点的顺序并没有做规定,跟我们之前学习的二叉查找树是有区别的。

1.2 堆的API设计

在这里插入图片描述

1.3 堆的实现

1.3.1 insert插入方法的实现

堆是用数组完成数据元素的存储的,由于数组的底层是一串连续的内存地址,所以我们要往堆中插入数据,我们只能往数组中从索引0处开始,依次往后存放数据,但是堆中对元素的顺序是有要求的,每一个结点的数据要大于等于它的两个子结点的数据,所以每次插入一个元素,都会使得堆中的数据顺序变乱,这个时候我们就需要通过一些方法让刚才插入的这个数据放入到合适的位置。
在这里插入图片描述
所以,如果往堆中新插入元素,我们只需要不断的比较新结点a[k]和它的父结点a[k/2]的大小,然后根据结果完成数据元素的交换,就可以完成堆的有序调整。

1.3.2 delMax删除最大元素方法的实现

由堆的特性我们可以知道,索引1处的元素,也就是根结点就是最大的元素,当我们把根结点的元素删除后,需要有一个新的根结点出现,这时我们可以暂时把堆中最后一个元素放到索引1处,充当根结点,但是它有可能不满足堆的有序性需求,这个时候我们就需要通过一些方法,让这个新的根结点放入到合适的位置。

在这里插入图片描述
所以,当删除掉最大元素后,只需要将最后一个元素放到索引1处,并不断的拿着当前结点a[k]与它的子结点a[2k]和a[2k+1]中的较大者交换位置,即可完成堆的有序调整。

1.3.3 堆的实现代

//堆代码
public class Heap<T extends Comparable<T>> {
	//存储堆中的元素
	private T[] items;
	//记录堆中元素的个数
	private int N;
	public Heap(int capacity) {
		items = (T[]) new Comparable[capacity+1];
		N=0;
	}
	//判断堆中索引i处的元素是否小于索引j处的元素
	private boolean less(int i,int j){
		return items[i].compareTo(items[j])<0;
	}
	//交换堆中i索引和j索引处的值
	private void exch(int i,int j){
		T tmp = items[i];
		items[i] = items[j];
		items[j] = tmp;
	}
	//往堆中插入一个元素
	public void insert(T t){
		items[++N] = t;
		swim(N);
	}
	//删除堆中最大的元素,并返回这个最大元素
	public T delMax(){
		T max = items[1];
		//交换索引1处和索引N处的值
		exch(1,N);
		//删除最后位置上的元素
		items[N]=null;
		N--;//个数-1
		sink(1);
		return max;
	}
	//使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
	private void swim(int k){
		//如果已经到了根结点,就不需要循环了
		while(k>1){
			//比较当前结点和其父结点
			if(less(k/2,k)){
			//父结点小于当前结点,需要交换
			exch(k/2,k);
		}
		k = k/2;
		}
	}
	//使用下沉算法,使索引k处的元素能在堆中处于一个正确的位置
	private void sink(int k){
		//如果当前已经是最底层了,就不需要循环了
		while(2*k<=N){
			//找到子结点中的较大者
			int max;
			if (2*k+1<=N){//存在右子结点
				if (less(2*k,2*k+1)){
					max = 2*k+1;
				}else{
					max = 2*k;
				}
			}else{//不存在右子结点
				max = 2*k;
			}
			//比较当前结点和子结点中的较大者,如果当前结点不小,则结束循环
			if (!less(k,max)){
			break;
		}
		//当前结点小,则交换,
		exch(k,max);
		k = max;
		}
	}
}

//测试代码
public class Test {
	public static void main(String[] args) throws Exception {
		Heap<String> heap = new Heap<String>(20);
		heap.insert("S");
		heap.insert("G");
		heap.insert("I");
		heap.insert("E");
		heap.insert("N");
		heap.insert("H");
		heap.insert("O");
		heap.insert("A");
		heap.insert("T");
		heap.insert("P");
		heap.insert("R");
		String del;
		while((del=heap.delMax())!=null){
			System.out.print(del+",");
		}
	}
}

1.4 堆排序

给定一个数组:

 String[] arr = {"S","O","R","T","E","X","A","M","P","L","E"}

请对数组中的字符按从小到大排序。

实现步骤:

  1. 构造堆;
  2. 得到堆顶元素,这个值就是最大值;
  3. 交换堆顶元素和数组中的最后一个元素,此时所有元素中的最大元素已经放到合适的位置;
  4. 对堆进行调整,重新让除了最后一个元素的剩余元素中的最大值放到堆顶;
  5. 重复2~4这个步骤,直到堆中剩一个元素为止。

在这里插入图片描述

1.4.1 堆构造过程

堆的构造,最直观的想法就是另外再创建一个新数组,然后从左往右遍历原数组,每得到一个元素后,添加到新数组中,并通过上浮,对堆进行调整,最后新的数组就是一个堆。

上述的方式虽然很直观,也很简单,但是我们可以用更聪明一点的办法完成它。创建一个新数组,把原数组0~length-1的数据拷贝到新数组的1~length处,再从新数组长度的一半处开始往1索引处扫描(从右往左),然后对扫描到的每一个元素做下沉调整即可。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

1.4.2 堆排序过程

对构造好的堆,我们只需要做类似于堆的删除操作,就可以完成排序。

  1. 将堆顶元素和堆中最后一个元素交换位置;
  2. 通过对堆顶元素下沉调整堆,把最大的元素放到堆顶(此时最后一个元素不参与堆的调整,因为最大的数据已经到了数组的最右边)
  3. 重复1~2步骤,直到堆中剩最后一个元素。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码

//对排序代码
public class HeapSort {
	//对source数组中的数据从小到大排序
	public static void sort(Comparable[] source) {
		//1.创建一个比原数组大1的数组
		Comparable[] heap = new Comparable[source.length + 1];
		//2.构造堆
		createHeap(source,heap);
		//3.堆排序
		//3.1定义一个变量,记录heap中未排序的所有元素中最大的索引
		int N = heap.length-1;
		while(N!=1){
			//3.2交换heap中索引1处的元素和N处的元素
			exch(heap,1,N);
			N--;
			//3.3对索引1处的元素在0~N范围内做下沉操作
			sink(heap,1,N);
		}
		//4.heap中的数据已经有序,拷贝到source中
		System.arraycopy(heap,1,source,0,source.length);
	}
	
	//根据原数组source,构造出堆heap
	private static void createHeap(Comparable[] source, Comparable[] heap) {
		//1.把source中的数据拷贝到heap中,从heap的1索引处开始填充
		System.arraycopy(source,0,heap,1,source.length);
		//2.从heap索引的一半处开始倒叙遍历,对得到的每一个元素做下沉操作
		for (int i = (heap.length-1)/2; i>0 ; i--) {
			sink(heap,i,heap.length-1);
		}
	}
	//判断heap堆中索引i处的元素是否小于索引j处的元素
	private static boolean less(Comparable[] heap, int i, int j) {
		return heap[i].compareTo(heap[j])<0;
	}
	//交换heap堆中i索引和j索引处的值
	private static void exch(Comparable[] heap, int i, int j) {
		Comparable tmp = heap[i];
		heap[i] = heap[j];
		heap[j] = tmp;
	}
	//在heap堆中,对target处的元素做下沉,范围是0~range
	private static void sink(Comparable[] heap, int target, int range){
		//没有子结点了
		while (2*target<=range){
			//1.找出target结点的两个子结点中的较大值
			int max=2*target;
			if (2*target+1<=range){
				//存在右子结点
				if (less(heap,2*target,2*target+1)){
					max=2*target+1;
				}
			}
			//2.如果当前结点的值小于子结点中的较大值,则交换
			if(less(heap,target,max)){
				exch(heap,target,max);
			}
			//3.更新target的值
			target=max;
		}
	}
}

//测试代码
public class Test {
	public static void main(String[] args) throws Exception {
		String[] arr = {"S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E"};
		HeapSort.sort(arr);
		System.out.println(Arrays.toString(arr));
	}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

4月最新编程排行出炉,第一名ChatGPT都在用~

作为一名合格的&#xff08;准&#xff09;程序员&#xff0c;必做的一件事是关注编程语言的热度&#xff0c;编程榜代表了编程语言的市场占比变化&#xff0c;它的变化更预示着未来的科技风向和机会&#xff01; 快跟着一起看看本月排行有何看点&#xff1a; 4月Tiobe排行榜前…

【CSS】使用 固定定位 实现顶部导航栏 ( 核心要点 | 固定定位元素居中设置 | 代码示例 )

文章目录一、核心要点分析1、顶部导航栏要点2、固定定位垂直居中设置二、代码示例一、核心要点分析 实现下图所示功能 : 上方有一个固定导航栏 , 水平居中设置 ;左右两侧各一个广告栏 , 垂直居中设置 ; 1、顶部导航栏要点 顶部导航栏要点 : 使用固定定位 , 上边偏移设置为 0 …

Linux Ubuntu虚拟机下载安装以及初始配置--VMware、Ubuntu、Xshell、Xftp

一、下载准备 Ubuntu系统下载链接&#xff08;系统本身&#xff09;&#xff1a;官网链接 VMware虚拟机下载链接&#xff08;搭载Ubuntu系统&#xff09;&#xff1a;网盘链接密码XMKD Xshell下载链接&#xff08;虚拟机远程连接&#xff09;&#xff1a;官网链接 Xftp下载…

MySQL索引数据结构入门

之前松哥写过一个 MySQL 系列&#xff0c;但是当时是基于 MySQL5.7 的&#xff0c;最近有空在看 MySQL8 的文档&#xff0c;发现和 MySQL5.7 相比还是有不少变化&#xff0c;同时 MySQL 又是小伙伴们在面试时一个非常重要的知识点&#xff0c;因此松哥打算最近再抽空和小伙伴们…

PyQt5学习笔记一、安装PyQt5和在PyCharm中配置工具

一、安装PyQt5 1. 可以在cmd窗口安装PyQt5和工具 可以在cmd窗口使用命令 pip install PyQt5 安装PyQt5&#xff0c;若指定版本使用命令 pip install PyQt5version&#xff0c;此时同时安装了PyQt5和sip。参考链接 在cmd命令窗口安装Python模块_Mr. 李大白的博客-CSDN博客htt…

potPlay——记忆播放位置、各种快捷键

potPlay——记忆播放位置、各种快捷键potPlay——各种快捷键简洁版完整版快捷键列表potPlay——记忆播放位置potPlay——各种快捷键 简洁版 Q 复位 亮度&#xff0c;对比度&#xff0c;色度复位键 W/E 调暗/调亮 R/T 对比度 Y/U 饱和度 I/O 色彩度 D 上一帧 F 下一帧 M 静音 …

Docker开启并配置远程安全访问

前言 在工作学习中&#xff0c;为了提高项目部署效率&#xff0c;一般会在Idea中直接使用Docker插件连接服务器Docker容器&#xff0c;然后将项目打包与DockerFile一起build成Docker镜像部署运行。但是不可能服务器总是跟着主机的&#xff0c;因此呢时常会面临的一个问题就是从…

【微信小程序】-- uni-app 项目--- 购物车 -- 配置 tabBar 效果(五十一)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &…

事务的ACID特性

1. 絮絮叨叨 重温Apache ORC时&#xff0c;发现ORC支持ACID想起自己之前一度不知道ACID是哪些单词的缩写&#xff0c;更别提面试中常提到的事物隔离级别等知识了因此&#xff0c;特地学习一下数据库中事务的ACID 2. ACID 2.1 What’s transaction&#xff1f; 考虑一个真实…

42.原型对象 prototype

目录 1 面向对象与面向过程 2 原型对象 prototype 3 在内置对象中添加方法 4 constructor 属性 5 实例对象原型 __proto__ 6 原型继承 7 原型链与instanceof 7.1 原型链 7.2 instanceof 8 案例-模态框 1 面向对象与面向过程 编程思想有 面向过程 与 面向…

几何-九种二次曲面类型

&#xff08;一&#xff09;椭圆锥面 &#xff08;1&#xff09;把z平方看成一个一直变大的常数&#xff0c;那么可以看出延z方向&#xff0c;是一个一直变大的椭圆。 &#xff08;2&#xff09;把一个x或y赋予0&#xff0c;显然是一个两条关于原点对称的直线。 由上即可判断…

不小心删除了文件能恢复吗 误删除文件怎么找回

电脑是我们平时工作或者生活、学习中使用频率非常高的电子设备&#xff0c;已经成为了我们日常生活中不可或缺的一部分。删除文件是电脑使用过程中常见的一种操作&#xff0c;因为电脑的储存空间是有限的&#xff0c;我们需要对电脑数据进行清理&#xff0c;避免电脑储存空间占…

视觉检测相比于人工目视检测有哪些优势

技术的发展可以给我们带来好的结果。 是其中之一。 这在现代工业生产中非常常见。 视觉检测设备可以更好地检测生产中的错误和产品质量问题&#xff0c;提高工业生产的效率和自动化水平&#xff0c;提高工业生产的准确性&#xff0c;加快工作进度&#xff0c;节约时间&#xff…

docker too many open files解决方式

1&#xff1a;问题描述 今天在环境上执行docker ps命令失败&#xff0c;如下提示 [rootcontrol02 ~]# docker ps -a lgrep nginx Cannot connect to the Docker daemon at unix:///var/run/docker.sock, Is the docker daemon running?2&#xff1a;查看节点docker状态 看信…

【Arduino 和 HC-12 远程无线通信模块】

【Arduino 和 HC-12 远程无线通信模块】 1. 概述2. HC-12 无线通信模块3. Arduino 和 HC-123.1 原理图3.2 示例 01 – Arduino 代码3.3 AT 命令:3.4 例子 023.5 代码说明:4. HC-12 无线通信:使用加速度计的步进电机控制4.1 原理图4.2 代码说明:1. 概述 在本Arduino教程中,…

Web 开发的一些常用基础——HTTP请求、响应、Cookies、Session

HTTP 请求 进入浏览器的开发者模式下的 Network 监听组件&#xff0c;访问百度 https://www.baidu.com/&#xff0c;输入该 URL 后回车&#xff0c;观察这个过程中发生了怎样的网络请求&#xff1a; 请求&#xff0c;由客户端向服务端发出&#xff0c;可以分为 4 部分内容&…

基于DSP+FPGA的多轴运动控制平台(一)硬件设计

2实验平台总体方案与硬件设计 2.1.1 实验平台的功能需求分析 针对便于多轴运动控制技术的研究&#xff0c;培养此方面技术的人才&#xff0c;实验平台应能 对多轴运动实现高速高精度的控制效果&#xff0c;同时保证系统开放性和兼容多种算法及 参数的运行。 实验过程契合实际工…

4.16--计算机网络之HTTP篇之常见面试题篇--(复习+深入)---好好沉淀,加油呀

1.HTTP 基本概念 1.HTTP 是什么&#xff1f; HTTP 是超文本传输协议 HTTP 是一个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」。 「HTTP 是用于从互联网服务器传输超文本到本地浏览器的协议」&#xff0c;这种说法正确吗…

Android -- OkHttp的简单使用和封装

OkHttp的封装 由于是封装我们可以吧OKHttp和Gson给结合起来&#xff0c;那么我们在gradle文件添加以下的依赖 1 2 3 compile "com.squareup.okhttp:okhttp:2.4.0" compile com.squareup.okio:okio:1.5.0 compile "com.google.code.gson:gson:2.8.0" ①Ca…

Windows Subsystem for Android (WSA) 下载:在 Windows 11 上运行 Android 应用 (April 2023)

适用于 Android™️ 的 Windows 子系统&#xff0c;2023 年 4 月更新 (April 2023) 请访问原文链接&#xff1a;https://sysin.cn/blog/wsa/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org Windows 11 上适用于 Android™ 的 …