堆其实是个很简单的数据结构

举报
Tom forever 发表于 2019/10/26 10:39:40 2019/10/26
【摘要】 说到堆这种数据结构,很多人的第一反应是感觉很复杂,其实不然,堆就是个优先级队列而已,或者,堆其实就是一种树。本文先讲原理,后面给出堆的实现代码。优先级队列可以用有序数组来实现,这种做法的问题是,尽管删除最大数据项的时间复杂度为O(1),但是插入还是需要较长的O(N)时间,这是因为必须移动数组中平均一半的数据项以插入新数据项,并在完成插入后,数组依然有序。本文主要介绍实现优先级队列的另一种结构...

说到堆这种数据结构,很多人的第一反应是感觉很复杂,其实不然,堆就是个优先级队列而已,或者,堆其实就是一种树。本文先讲原理,后面给出堆的实现代码。

优先级队列可以用有序数组来实现,这种做法的问题是,尽管删除最大数据项的时间复杂度为O(1),但是插入还是需要较长的O(N)时间,这是因为必须移动数组中平均一半的数据项以插入新数据项,并在完成插入后,数组依然有序。

本文主要介绍实现优先级队列的另一种结构:堆。堆是一种树,并非java和C++等编译语言里的“堆”。由它实现的优先级队列的插入和删除的时间复杂度都是O(logN)。尽管这样删除的时间变慢了一些,但是插入的时间快的多了。当速度非常重要,且有很多插入操作是,可以选择堆来实现优先级队列。堆有如下特点:

  • 它是完全二叉树。即除了树的最后一层节点不需要是满的外,其他的每一层从左到右都完全是满的。

  • 它常常用一个数组实现。用数组实现的完全二叉树中,节点的索引有如下特点(设该节点的索引为x):
    它的父节点的索引为 (x-1) / 2; 它的左子节点索引为 2x + 1; 它的右子节点索引为 2x + 2。

  • 堆中每个节点的关键字都大于(或等于)这个节点的子节点的关键字。这也是堆中每个节点必须满足的条件。所以堆和二叉搜索树相比,是弱序的。



向堆中插入数据,首先将数据项存放到叶节点中(即存到数组的最后一项),然后从该节点开始,逐级向上调整,直到满足堆中节点关键字的条件为止。

从堆中删除数据与插入不同,删除时永远删除根节点的数据,因为根节点的数据最大,删除完后,将最后一个叶节点移到根的位置,然后从根开始,逐级向下调整,直到满足堆中节点关键字的条件为止。

原理就这么多,堆真的很简单

下面给出堆的实现代码:


public class Heap {    private Node[] heapArray;    private int maxSize;    private int currentSize;    public Heap(int mx) {        maxSize = mx;        currentSize = 0;        heapArray = new Node[maxSize];    }    public boolean isEmpty() {        return (currentSize == 0)? true : false;    }    public boolean isFull() {        return (currentSize == maxSize)? true : false;    }    public boolean insert(int key) {        if(isFull()) {            return false;        }        Node newNode = new Node(key);        heapArray[currentSize] = newNode;        trickleUp(currentSize++);        return true;    }    //向上调整    public void trickleUp(int index) {        int parent = (index - 1) / 2; //父节点的索引        Node bottom = heapArray[index]; //将新加的尾节点存在bottom中        while(index > 0 && heapArray[parent].getKey() < bottom.getKey()) {            heapArray[index] = heapArray[parent];            index = parent;            parent = (parent - 1) / 2;        }        heapArray[index] = bottom;    }    public Node remove() {        Node root = heapArray[0];        heapArray[0] = heapArray[--currentSize];        trickleDown(0);        return root;    }    //向下调整    public void trickleDown(int index) {        Node top = heapArray[index];        int largeChildIndex;        while(index < currentSize/2) { //while node has at least one child            int leftChildIndex = 2 * index + 1;            int rightChildIndex = leftChildIndex + 1;            //find larger child            if(rightChildIndex < currentSize &&  //rightChild exists?                    heapArray[leftChildIndex].getKey() < heapArray[rightChildIndex].getKey()) {                largeChildIndex = rightChildIndex;            }            else {                largeChildIndex = leftChildIndex;            }            if(top.getKey() >= heapArray[largeChildIndex].getKey()) {                break;            }            heapArray[index] = heapArray[largeChildIndex];            index = largeChildIndex;        }        heapArray[index] = top;    }    //根据索引改变堆中某个数据    public boolean change(int index, int newValue) {        if(index < 0 || index >= currentSize) {            return false;        }        int oldValue = heapArray[index].getKey();        heapArray[index].setKey(newValue);        if(oldValue < newValue) {            trickleUp(index);        }        else {            trickleDown(index);        }        return true;    }    public void displayHeap() {        System.out.println("heapArray(array format): ");        for(int i = 0; i < currentSize; i++) {            if(heapArray[i] != null) {                System.out.print(heapArray[i].getKey() + " ");            }            else {                System.out.print("--");            }        }    }}class Node {    private int iData;    public Node(int key) {        iData = key;    }    public int getKey() {        return iData;    }    public void setKey(int key) {        iData = key;    }}



这个实现的代码,可以在等公交的时候、吃饭排队的时候拿来看看,利用碎片化时间来学习。



转载声明:本文转载自公众号【程序员私房菜】。    

原文链接:https://mp.weixin.qq.com/s/26wUJ7cXtqvNVryKUdv09g


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。