看图说话数据结构之二叉堆(优先队列)——java实现

    上篇文章数据结构之二叉堆(优先队列)——原理解析详细介绍了二叉堆的实现原理,本篇文章在上篇文章的基础上,介绍二叉堆的建堆原理,二叉堆的入队和出队操作的java代码实现。

一丶二叉堆的存储结构

    在上篇文章中,为了清晰的介绍二叉堆的原理,我们将二叉堆画出成了链式结构,链式结构涉及比较多的指针操作,因为二叉堆的具有完全二叉树的结构特性,更为简单的做法是将二叉堆的存储结构设计为数组。

图1 大根堆

    对于如上图所示的二叉堆,利用数组来存树形结构如下所示。
图2 存储结构

可以看到其存储结构具有如下特点:

  • 利用数组来存数大根堆其存储顺序和树的层次遍历顺序相同
  • 数组的第一个元素(下标Index=0)不存放数据,重当哨兵元素,其具体作用后续会涉及。
  • 在二根堆不断的入队和出队的操作下,数组中元素的数目会发生变化,必须设置一个指针,指向数组的边界元素。
  • 二叉堆是具有堆序的完全二叉树,那么也满足完全二叉树的所有特点,可以知道对于完全二叉树的数组存储具有如下特点,对于数组中下标为i的元素,若其左孩子存在,那么其左孩子下标为2i,其右孩子若存在,下为2i+1,其父节点的坐标为i/2。这是一条非常重要的性质。
二丶二叉堆的建堆原理。

    对于N个元素的建堆的过程等价于N个元素插入的过程,这是对二叉堆建堆过程最直观的理解,这里描述另外的一种方法。假如待建堆的数组如下,构建一个大根堆。

A={5,9,4,3,2,1}

  1. 依据待建堆数组构建一个随机完全二叉树,构建结果如下:


    图3 随机完全二叉树
  2. 对于图3而言,已经满足了二叉树的结构特性了,只要完成二叉树的堆序特性,那么建堆的过程就算完成了。此时二叉树currentSize = 6,6这个下标指向堆尾元素1。i=currentSize/2=3,3这个下标指向堆尾元素1的父节点4,元素4也是最后一个非叶子节点。我们我们利用”下滤”操作调整元素4的堆序特性。结果如下图,其实元素4满足堆序特点,无需调整。


    图4 第一次下滤调整
  3. 步骤2中i=3,指向元素4,此时i--,i=2指向元素9,继续利用下滤操作调整元素9的堆序特性结果如下:


    图5 第二次堆序调整
  4. i继续自减,i=2,指向元素5,此时利用”下滤”操作调整该元素的堆序特性,调整如下:


    图3第三次堆序调整
  5. i继续自减,i=0发现数组已无元素可调,结束,建堆完成。

三丶二叉堆的java代码实现

//二叉堆--大根堆的java代码实现
//利用二叉堆完全树的结构特性我们利用数组来存储二叉堆。
public class BinaryHeap {
    //currentSize数组的边界
    intcurrentSize;
    //储存二叉堆节点元素的数组
    int[] item;
    publicBinaryHeap(int [] data){
       this.currentSize=data.length;
       //实际上并不是乘5,这里乘5只是为了保证其具有足够的空间大小。
       item = new int[(currentSize+1)*5];
       //这里特别注意,数组的第一个元素并不存数数据
       //直接复制构建一棵随机完全二叉树
       for(int i =0;i<data.length;i++){
           item[i+1] = data[i];
       }
       //对构成的随机完全二叉树进行堆序的调整
       buildHeap();
    }
    //建堆操作的原理:对随机完全二叉树的每个非叶子节点完成下滤操作。
    privatevoid buildHeap(){
       if(item==null||item.length<=0){
           return ;
       }
       for(int i =currentSize/2;i>0;i--){
           percolateDown(i);                      
       }
    }
    //index:指定下滤的元素下标
    privatevoid percolateDown(int index) {
       intcopy = item[index];
       intchild=0;
       for(int i = index;i*2<=currentSize;i=child){
           //child指向左节点。
           child = i*2;
           //这需要判断该节点是否存在右孩子
           int max = item[child];
           if(child+1<=currentSize&&max<item[child+1]){
              //++child指向右节点
              max = item[++child];
           }
           if(copy<max){
              //不满足堆序性质,覆盖
              item[index] = max;
           }else{
              //满足堆序性质,结束该次堆调整。
              item[i] = copy;
              return ;
           }
       }
    }
    @Override
    publicString toString() {
       return"BinaryHeap [item=" + Arrays.toString(item) + "]";
    }
    publicvoid insert(int element){
       currentSize++;
       item[currentSize] = element;
       //数组元素0这里有个哨兵。
       item[0] = element;
       intparent = 0;
       for(int i = currentSize;i>0;i =parent){
            parent = i/2;
            if(item[parent]<item[0]){
               item[i] = item[parent];
            }else{
               item[i] = item[0];
               item[0] = 0;
               return;
            }
       }
    }
    publicint deleteMax(){
       intdata = item[1];
       item[1] = item[currentSize--];
       percolateDown(1);
       returndata;
    }
    publicstatic void main(String [] args){
       int[] data = new int[]{5,9,4,3,2,1};
       BinaryHeap heap = new BinaryHeap(data);
       heap.insert(10);
       System.out.println(heap.toString());
       System.out.println(heap.deleteMax());
       System.out.println("-----------------------");
       System.out.println(heap);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352