java数据结构堆_数据结构:堆

本文介绍了堆排序中的最大堆数据结构,堆是一种完全二叉树,可以用数组实现。最大堆的性质是每个节点的值大于其子节点的值,根节点为最大值。通过`maxHeapify`函数可以规范化最大堆,`buildUpHeap`函数用于从无序数组构建最大堆。堆排序的基础知识和自底向上的建堆方法在这里得到了详细讲解。
摘要由CSDN通过智能技术生成

这是小密圈《进击的Java新人》第十一周第二课。

我们今天接着昨天讲的内容把选择排序的相关知识都讲完。选择排序中有一类特殊的排序算法,叫做堆排序。在介绍堆排序之前,我们必须先来讲明白堆是什么。

堆是一种非常灵活的数据结构,我们可以单独地使用它来解决很多有趣的问题。而且,由于堆的定义本来就有最优的含义,所以它与贪心算法有着天然的联系。在后面的讲解中,我们会不断地遇到以堆做为基本的数据结构进行贪心求解的例子。

堆这种数据结构本质是一个完全二叉树,如图 4.1 所示,但是通过分析,我们可以使用数组来实现它。由于堆本质上是一棵完全二叉树,因此,这里可以直接使用二叉树的相关概念,例如高度等等。在实现二叉树的时候,树结点通常这样定义:

public class Node {

public T data;

public Node left;

public Node right;

public Node parent;

public int state;

public Node(T d) {

this.data = d;

}

}

就是说,一个结点通常会有左,右孩子结点指针和父结点指针。但在完全二叉树中,是可以省略掉这三个指针的,因为完全二叉树的结点编号都是有规律的。给定某一个结点,假设它的下标为i,那么它的左孩子结点的下标就是2i + 1,右孩子结点的下标就是2i + 2,它的父结点为(i−1)/2。这样,我们就把可以省略去这些指针,直接将堆中的结点存储在数组中了。请对照示意图理解一下这段话。

堆又分为最大堆和最小堆。堆的性质非常简单,如果是最大堆,对于每个结点,都有结点的值大于两个孩子结点的值。如果是最小堆,那么对于每个结点,都有结点的值小于孩子结点的值。由此,可以得到一个推论,那就是,最大堆的根结点,必然是堆中的最大值,同理,最小堆的根结点,也必然是堆中的最小值。

建堆

对于一个堆,如果除了堆顶元素不满足结点大于孩子结点的条件,它的两个子树已经是符合条件的最大堆,我们很容易就可以将其再维护成一个符合条件的最大堆。将堆顶元素与两个孩子结点中最大的那个进行交换,然后再对互换的子树递归地进行维护。

public static void maxHeapify(int arr[], int length, int root) {

if (root >= length) {

return;

}

int largest = root;

int left = root * 2 + 1;

int right = root * 2 + 2;

if (left < length && arr[left] < arr[largest]) {

largest = left;

}

if (right < length && arr[right] < arr[largest]) {

largest = right;

}

if (largest != root) {

int t = arr[root];

arr[root] = arr[largest];

arr[largest] = t;

maxHeapify(arr, length, largest);

}

}

如图 4.2 所示,除了堆顶元素不满足最大堆的条件外,根结点的两棵子树已经分别是两个最大堆。使这个堆规范化的过程实际上就是堆顶元素13不断地向下降的过程。

有了规范化最大堆的函数以后,我们就可以轻松地从把一个无序数组规范化成一个堆。首先,如果堆中只含有一个元素,那么它必然是一个规范的最大堆,也就是说,如果把一个数组表示成完全二叉树,那么树上的每一个叶子结点都是一个规范的最大堆。这样,我们可以不断地自底向上规范化子堆,直到整个堆已经全部规范化。

public static void buildUpHeap(int[] arr) {

if (arr.length <= 1)

return;

int n = (arr.length - 2) / 2;

while (n >= 0) {

maxHeapify(arr, arr.length, n);

n--;

}

}

好了。今天的课程就到这里了。我们今天讲的方法是自底向上地建堆。这种方法应用于堆排序可以减少空间的使用,但其实不利于扩展。明天我们再讲一下自上而下的建堆方法。然后,我们再讲一下堆排序。

堆的内容还没讲解完,今天不留作业,因为好几道题目都是要求自上而下建堆的。今天只要对照图和代码把堆的性质牢牢掌握就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值