IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 堆的实现(java) -> 正文阅读

[数据结构与算法]堆的实现(java)

堆的基础表示

数据的存储规则

在这里插入图片描述
堆结构类似与二叉树(此处用最大堆举例),不同的是堆只用满足左右孩子均小于该节点值即可,由此,堆是一个完全二叉树(一层一层按顺序摆放数据)

用数组存储堆中的数据

在这里插入图片描述

由于堆中的数据存储方法满足完全二叉树(相当于顺序存储),故可以用数组顺序存储数据(从1开始

由于后续删除、添加元素需要寻找节点的父亲节点、左孩子、右孩子,根据图示,易得出规律

MaxHeap基本方法的实现

public class MaxHeap <E extends Comparable<E>>{
	private Array<E> data;
	
	public MaxHeap(int capacity) {
		data=new Array<>(capacity);
	}
	public MaxHeap() {
		data=new Array<>();
	}
	
	//返回堆中元素的个数
	public int size() {
		return data.getSize();
	}
	
	//返回一个布尔值,表示堆是否为空
	public boolean isEmpty() {
		return data.isEmpty();
	}
	
	//返回完全二叉树的数组表示中,一个索引所表示的元素的父亲节点的索引
	private int parent(int index) {
		if(index==0)
			throw new IllegalArgumentException("Index 0 doesn't have parent.");
		return (index-1)/2;
	}
	
	//返回完全二叉树的数组表示中,一个索引所表示元素的左孩子节点
	private int leftChild(int index) {
		return index*2+1;
	}
	
	//返回完全二叉树的数组表示中,一个索引所表示元素的右孩子节点
		private int rightChild(int index) {
			return index*2+2;
		}
	}

向堆中添加元素

添加思路

在这里插入图片描述
首先在动态数组尾部添加元素

在这里插入图片描述再向上寻找其父亲节点,比较父亲结点位置值,若该位置值大于父亲节点的值,间二者间的值进行交换,直至父亲结点值大于新添加的元素

代码实现

   //向堆中添加元素
		public void add(E e) {
			data.addLast(e);
			siftUp(data.getSize()-1);
		}
       private void siftUp(int k) {
    	   while(k>0&&data.get(parent(k)).compareTo(data.get(k))<0) {//只有在k位置存在且值大于父亲节点的情况下才swap
    		   data.swap(k, parent(k));
    		   k=parent(k);
    	   }
       }

取出堆中的最大元素

取出最大元素很容易,问题就是如何对堆中其它元素进行操作
在这里插入图片描述
取出元素后,首先将数组末尾元素移到数组首部,填补空缺
在这里插入图片描述
再比较该结点与其孩子节点的值,选择大于该结点,且值较大的孩子结点进行交换

在这里插入图片描述
一直进行交换直至没有左右孩子或均大于左右孩子为止
在这里插入图片描述
代码实现

//取出堆中的最大元素
       public E extractMax() {
    	   E ret=findMax();
    	   data.swap(0, data.getSize()-1);
    	   data.removeLast();
    	   siftDown(0);
    	   return ret;
       }
       
       private void siftDown(int k) {
    	   while(leftChild(k)<data.getSize()) {//循环条件为左孩子存在
    		   int j=leftChild(k);
    		   //首先判断右孩子是否存在,再比较两者的值,选择应该与谁交换
    		   if(rightChild(k)<data.getSize()&&data.get(j).compareTo(data.get(j+1))<0)
    		       j++;
    		   if(data.get(k).compareTo(data.get(j))>=0)
    				   break;
    		   data.swap(k, j);
    		   k=j;
    	   }
       }

将数组转换为堆

MaxHeap构造函数

在这里插入图片描述
想要将传入的数组原地转换为堆,方法很简单,只需找到倒数第一个非叶子节点,也就是最后一个节点的父亲节点(此处标为红色的位置),从此处依次往前,进行siftDown操作即可

MaxHeap中的heapify方法:

public MaxHeap(E[] arr) {
		data=new Array<>(arr);
		for(int i=parent(arr.length-1);i>=0;i--)
			siftDown(i);
	}

堆排序

堆排序

由于堆自身的特性,我们可以知道,索引为0的位置,永远存放堆中的最大元素。据此,我们可以利用堆对数组进行排序

	public static <E extends Comparable<E>> void sort(E[] data) {
		MaxHeap<E> maxHeap=new MaxHeap<>();
		for(E e:data)
		   maxHeap.add(e);
		for(int i=data.length-1;i>=0;i--) {
			data[i]=maxHeap.extractMax();
		}
	}

优化的堆排序

想要对堆排序进行优化,我们可以对数组进行原地heapify,再对最大值进行处理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如图示,就是要原地实现数组的heapify,再将堆中第一个元素与最后一个元素交换位置。

  • 交换位置后,堆可能不会满足最大堆的性质(图二中标黄的部分),所以要对第一个元素进行heapify,使其满足堆的性质。
  • 接下来再重复这个操作
public static <E extends Comparable<E>> void sort2(E[] data) {
		if(data.length<=1) return ;
		//将普通数组转换为堆的形式
		for(int i=(data.length-2)/2;i>=0;i--) {
	        siftDown(data,i,data.length);
	    //再对堆进行swap,siftDown操作
	    for(i=data.length-1;i>=0;i--) {
	    	swap(data,0,i);
	    	siftDown(data,0,i);
	    }
	}
		}
	//对data[0,n)所形成的最大堆中,索引为k的元素,执行siftDown
	private static <E extends Comparable<E>> void siftDown(E[] data,int k,int n) {
	    while(2*k+1<n) {//循环条件为左孩子存在
	    	int j=2*k+1;
	    		   //首先判断右孩子是否存在,再比较两者的值,选择应该与谁交换
	        if(j+1<n&&data[j].compareTo(data[j+1])<0)
	    		  j++;
	    	if(data[k].compareTo(data[j])>=0)
	    	    break;
	    	swap(data,k, j);
	    	k=j;
	    	   }
	       }
    private static <E> void swap(E[] arr,int i,int j){
		E tmp=arr[i];
		arr[i]=arr[j];
		arr[j]=tmp;
	}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-04 13:05:02  更:2021-10-04 13:06:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 13:53:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码