Dart实现二叉堆

定义与原理

二叉堆是一种特殊的堆。具有如下的特性:

  • 具有完全二叉树的特性
  • 堆中的任何一个父节点的值都大于等于它左右孩子节点的值,或者都小于等于它左右孩子节点的值

二叉堆分为两类:

  • 最大堆
    父节点的值大于等于左右孩子节点的值
    在这里插入图片描述
  • 最小堆
    父节点的值小于等于左右孩子节点的值
    在这里插入图片描述

堆顶:二叉堆的根节.

二叉堆的三个主要操作:

  • 插入一个节点。
  • 删除一个节点。
  • 构建一个二叉堆。

在二叉堆这种结构中,对于删除一个节点,我们一般删的是根节点

代码实现

二叉树一般是采用链表的方式来实现的,但二叉堆我们是采用数组的方式来存储的
在这里插入图片描述
如果知道了一个节点的位置,如何知道一个节点的左右孩子节点的位置呢?

这其实不难,根据完全二叉树的特点,假如一个节点的下标为n,则可以求得它左孩子的下标为:2n+1;右孩子下标为:2n+2

//Author:Shawn
//Email:stepfencurryxiao@gmail.com

/*
 *         1
 *       /   \
 *      2     3
 *     / \   / \
 *     5 4   6  7
 *    / \
 *    8 9
 *  
 * Array:[1,2,3,5,4,6,7,8,9]
 * 
 * leftchild : 2n + 1
 * rightcgild : 2n + 2
*/

List upAdjust(List arr,int length){
  //标记插入的节点
  var child = length - 1;
  //其父节点
  int parent = ((child - 1) / 2).toInt();
  //把插入的节点临时保存起来
  int temp = arr[child];
  
  //进行上浮
  while(child > 0 && temp < arr[parent]){
    //当temp找到正确的位置之后,我们再把temp的值赋给这个节点
    arr[child] = arr[parent];
    child = parent;
    parent = ((child - 1) / 2).toInt();
  }
  arr[child] = temp;
  return arr;
}
/**
    *  下沉操作,执行删除操作相当于把最后
    *  * 一个元素赋给根元素之后,然后对根元素执行下沉操作
    * @param arr
    * @param parent 要下沉元素的下标
    * @param length 数组长度
    */
List downAdjust(List arr,int parent,int length){
  //保存要下沉的元素
  int temp = arr[parent];
  //定位左孩子节点位置
  int child = 2 * parent + 1;
  //开始下沉
  while (child < length) {
       //如果右孩子节点比左孩子小,则定位到右孩子
       if (child + 1 < length && arr[child] > arr[child + 1]) {
               child++;
           }
           //如果父节点比孩子节点小或等于,则下沉结束
       if (temp <= arr[child])
           break;
       //单向赋值
       arr[parent] = arr[child];
       parent = child;
       child = 2 * parent + 1;
  }
  arr[parent] = temp;
  return arr;
}

List buildHead(List arr,int length) {
       //从最后一个非叶子节点开始下沉
       for (int i = ((length - 2) / 2).toInt(); i >= 0; i--) {
           arr = downAdjust(arr, i, length);
       }
       return arr;
}

void main(){
  List arr = [1,3,0,5,4,6,7,8,9];
  List BinaryHeap = buildHead(arr,arr.length);
  print(BinaryHeap);
}

运行结果:

[0, 3, 1, 5, 4, 6, 7, 8, 9]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值