数据结构--堆
Posted 可持续化发展
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构--堆相关的知识,希望对你有一定的参考价值。
目录
堆的定义
堆 是一种特别的二叉树,满足以下条件的二叉树,可以称之为 堆:
- 完全二叉树;
- 每一个节点的值都必须 大于等于或者小于等于 其孩子节点的值。
堆 具有以下的特点:
可以在 O(logN) 的时间复杂度内向 堆 中插入元素;
可以在 O(logN) 的时间复杂度内向 堆 中删除元素;
可以在 O(1)的时间复杂度内获取 堆 中的最大值或最小值。
堆的分类
堆 有两种类型:最大堆 和 最小堆。
最大堆:堆中每一个节点的值 都大于等于 其孩子节点的值。所以最大堆的特性是 堆顶元素(根节点)是堆中的最大值。
最小堆:堆中每一个节点的值 都小于等于 其孩子节点的值。所以最小堆的特性是 堆顶元素(根节
点)是堆中的最小值。
堆的插入
现在有一个堆,我们分为3步:
1.先判断是不是最大堆 或最小堆
2.按完全二叉树的插入操作,将节点插入堆中
3.对堆进行调整,使其满足最大堆或最小堆的特性
堆的删除
删除操作是指在 堆 中删除堆顶元素。元素删除之后,堆 依旧需要维持它的特性。
堆的删除分为以下几步:
1、从上到下,从左到右,找到完全二叉树的最后一个节点,将最后一个节点的值覆盖堆顶元素,然后删除最后一个节点。
2、开始调整堆,使其满足最大堆或最小堆的特性。
可以用数组
实现堆。我们将堆中的元素以二叉树的形式存入在数组
中。以下代码将使用数组
实现整数类型的「最大堆」和「最小堆」
用数组来表示完全二叉树
节点的个数
创建堆
创建 堆 指的是初始化一个堆实例。所有堆方法的前提必须是在堆实例上进行操作。换句话说,我们必须要首先创建一个 堆 实例,然后才能使用 堆 的常用方法。在创建 堆 的过程中,我们也可以同时进行 堆化 操作。堆化 就是将一组数据变成 堆 的过程。
时间复杂度: O(N)。
空间复杂度: O(N)。
// Java中的堆可以用优先队列(PriorityQueue)来表示
import java.util.Collections;
import java.util.PriorityQueue;
import java.util.Arrays;
// 创建一个空的最小堆
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
// 创建一个空的最大堆
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
// 创建带初始值的「堆」, 或者称为「堆化」操作,此时的「堆」为「最小堆」
PriorityQueue<Integer> heapWithValues= new PriorityQueue<>(Arrays.asList(3,1,2));
插入元素
插入操作指的是向 堆 中插入一个新元素。值的注意的是,新元素插入完毕后,堆 依旧需要维持它的特性。
时间复杂度: O(log N)。
空间复杂度: O(1)。
// 最小堆插入元素
minHeap.add(1);
// 最大堆插入元素
maxHeap.add(1);
获取堆顶元素
最大堆 的堆顶元素是 堆 中的最大值,最小堆 的堆顶元素是 堆 中的最小值。因此,堆顶元素是 堆 中最重要的元素。
时间复杂度: O(1)。
空间复杂度:O(1)。
// 最小堆获取堆顶元素,即最小值
minHeap.peek();
// 最大堆获取堆顶元素,即最大值
maxHeap.peek();
删除元素
删除堆顶元素后,值得注意的是,堆 依旧需要维持它的特性。此时,新的堆顶元素也是当前堆中的最大值(如果堆是 最大堆)或最小值(如果堆是 最小堆)。
时间复杂度:O(log N)。
空间复杂度:O(1)。
// 最小堆删除堆顶元素
minHeap.poll();
// 最大堆删除堆顶元素
maxheap.poll();
获取堆的长度
堆 的长度可以用来判断当前堆的大小,也可以用来判断当前堆是否还有元素。如果当前堆中没有元素,则 堆 的长度为 0。
时间复杂度:O(1)
空间复杂度:O(1)
// 最小堆的长度
minHeap.size();
// 最大堆的长度
maxHeap.size();
// 注意:Java中判断堆是否还有元素,除了检查堆的长度是否为0外,还可以使用isEmpty()方法。
// 如果堆中没有元素,则isEmpty()方法返回true。
// 如果堆中还有元素,则isEmpty()方法返回false。
最小堆
import java.util.*;
public class MinHeap {
public static void main(String[] args) {
//创建一个最小堆实例
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
minHeap.add(3);
minHeap.add(1);
minHeap.add(2);
//查看最小堆的所有元素,结果为:[1,3,2]
System.out.println("minHeap:"+ minHeap.toString());
//获取最小堆的堆顶元素
int peekNum = minHeap.peek();
//结果为:1
System.out.println("peekNum:"+ peekNum);
//删除最小堆的堆顶元素
int pollNum = minHeap.poll();
//结果为 1
System.out.println("pollNum:"+ pollNum);
//查看删除1后最小堆的堆顶元素,结果为 2
System.out.println("peekNum:"+ minHeap.peek());
//查看所有元素 [2, 3]
System.out.println("minHeap:"+ minHeap.toString());
//查看最小堆的元素个数,最小堆的长度 2
int heapSize = minHeap.size();
System.out.println("minHeap Size:"+ heapSize);
//判断最小堆是否还有元素
boolean isEmpty = minHeap.isEmpty();
System.out.println("isEmpty:"+ isEmpty);
}
}
最大堆
import java.util.*;
public class MaxHeap {
public static void main(String[] args) {
//创建一个最小堆实例
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
maxHeap.add(3);
maxHeap.add(1);
maxHeap.add(2);
//查看最小堆的所有元素,结果为:[3, 1, 2]
System.out.println("maxHeap:"+ maxHeap.toString());
//获取最小堆的堆顶元素
int peekNum = maxHeap.peek();
//结果为:3
System.out.println("peekNum:"+ peekNum);
//删除最小堆的堆顶元素
int pollNum = maxHeap.poll();
//结果为 3
System.out.println("pollNum:"+ pollNum);
//查看删除1后最小堆的堆顶元素,结果为 2
System.out.println("peekNum:"+ maxHeap.peek());
//查看所有元素 [2, 1]
System.out.println("maxHeap:"+ maxHeap.toString());
//查看最小堆的元素个数,最小堆的长度 2
int heapSize = maxHeap.size();
System.out.println("maxHeap Size:"+ heapSize);
//判断最小堆是否还有元素
boolean isEmpty = maxHeap.isEmpty();
System.out.println("isEmpty:"+ isEmpty);
}
}
堆排序
理论:堆排序指的是利用堆的数据结构对一组无序元素进行排序。
最小堆 排序算法步骤如下:
- 将所有元素堆化成一个 最小堆 ;
- 取出并删除堆顶元素,并将该堆顶元素放置在存储有序元素的数据集 T 中;
- 此时,堆 会调整成新的 最小堆;
- 重复 3 和 4 步骤,直到 堆 中没有元素;
- 此时得到一个新的数据集 T,其中的元素按照 从小到大 的顺序排列。
最大堆排序算法步骤如下:
- 将所有元素堆化成一个 最大堆;
- 取出并删除堆顶元素,并将该堆顶元素放置在存储有序元素的数据集 T 中;
- 此时,堆 会调整成新的 最大堆;
- 重复 3 和 4 步骤,直到 堆 中没有元素;
- 此时得到一个新的数据集 T,其中的元素按照从大到小的顺序排列。
以上是关于数据结构--堆的主要内容,如果未能解决你的问题,请参考以下文章