数据结构 - 堆

(1)什么是二叉堆

二叉堆本质上是一种完全二叉树,二叉堆的经典表示方法是使用一个数组表示,其中:

  • 根结点为数组的第一个元素A[0]。
  • 其它结点中,第i个结点和数组索引元素对应的关系为:
A[(i – 1) / 2] 返回第i个结点的父结点
A[(2 * i) + 1] 返回第i个结点的左儿子结点
A[(2 * i) + 2] 返回第i个结点的右儿子结点

它分为两个类型:

  • 最大堆

    最大堆任何一个父节点的值,都大于等于它左右孩子节点的值。

  • 最小堆

    最小堆任何一个父节点的值,都小于等于它左右孩子节点的值。

假设父节点的下标是parent,那么它的左孩子下标就是 2*parent+1;它的右孩子下标就是 2*parent+2

(2)二叉堆的主要操作

  • 堆的构建

    大顶堆

    //从第一个非叶子节点开始依次对数组中的元素进行下沉操作
    //和孩子节点的最大值max比较
    //大于max — 不需要在下沉
    //小于max — 和max交换位置 - 继续和下一层孩子节点比较,直到队列末尾
    function ajustMaxHeap(array, index, length) {
          for (let i = 2 * index + 1; i < length; i = 2 * i + 1) {
            if (i + 1 < length && array[i + 1] > array[i]) {
              i++;
            }
            if (array[index] >= [array[i]]) {
              break;
            } else {
              [array[index], array[i]] = [array[i], array[index]];
              index = i;
            }
          }
        }
    
        function createMaxHeap(arr, length) {
          for (let i = Math.floor(length / 2) - 1; i >= 0; i--) {
            ajustMaxHeap(arr, i, length);
          }
          return arr;
        }
    

    小顶堆

    //从第一个非叶子节点开始依次对数组中的元素进行下沉操作
    //和孩子节点的最小值min比较
    //小于min — 不需要在下沉
    //大于min — 和min交换位置(下沉) - 继续和下一层孩子节点比较,直到队列末尾
    function ajustMinHeap(array, index, length) {
          for (let i = 2 * index + 1; i < length; i = 2 * i + 1) {
            if (i + 1 < length && array[i + 1] < array[i]) {
              i++;
            }
            if (array[index] < [array[i]]) {
              break;
            } else {
              [array[index], array[i]] = [array[i], array[index]];
              index = i;
            }
          }
        }
    
        function createMinHeap(arr, length) {
          for (let i = Math.floor(length / 2) - 1; i >= 0; i--) {
            ajustMinHeap(arr, i, length);
          }
          return arr;
        }
    
  • 堆的插入

    //由于堆属于优先队列,只能从末尾添加
    //添加后有可能破坏堆的结构,需要从下到上进行调整
    //如果元素小于父元素,上浮
    //以小顶堆为例:
    function minHeapAdd(array = [], element) {
          array.push(element);
          if (array.length > 1) {
            let index = array.length - 1;
            let target = Math.floor((index - 1) / 2);
            while (target >= 0) { array[target]);
              if (array[index] < array[target]) {
                [array[index], array[target]] = [array[target], array[index]]
                index = target;
                target = Math.floor((index - 1) / 2);
              } else {
                break;
              }
            }
          }
          return array;
        }
    
  • 堆的移除

    //由于堆属于优先队列,只能从头部移除
    //移除头部后,使用末尾元素填充头部,开始头部下沉操作
    //以小顶堆为例:
    function minHeapPop(array = []) {
          let result = null;
          if (array.length > 1) {
            result = array[0];
            array[0] = array.pop();
            ajustMinHeap(array, 0, array.length);
          } else if (array.length === 1) {
            return array.pop();
          }
          return result;
        }
    
  • 封装

    class Heap {
      constructor(arr, type) {
        this.data = [...arr];
        this.type = type;
        this.size = this.data.length;
      }
        
      create() {
          for (let i = Math.floor((this.size / 2) - 1); i >= 0; i--) {
            this.ajust(i);
          } 
      }
        
      ajust (index) {
          const arr = this.data;
          for (let i = 2 * index + 1; i < this.size; i = 2 * i + 1) {
            if (i + 1 < this.size) {
              if ((this.type === 'max' && arr[i + 1] > arr[i]) ||
                (this.type === 'min' && arr[i + 1] < arr[i])) {
                i++;
              }
            }
            if ((this.type === 'max' && arr[index] < [arr[i]]) ||
              (this.type === 'min' && arr[index] > [arr[i]])) {
              [arr[index], arr[i]] = [arr[i], arr[index]];
              index = i;
            } else {
              break;
            }
          }
        }
        
        add (element) {
          const arr = this.data;
          arr.push(element);
          if (this.size > 1) {
            let index = this.size - 1;
            let target = Math.floor((index - 1) / 2);
            while (target >= 0) {
              if ((this.type === 'min' && arr[index] < arr[target]) ||
                (this.type === 'max' && arr[index] > arr[target])) {
                [arr[index], arr[target]] = [arr[target], arr[index]]
                index = target;
                target = Math.floor((index - 1) / 2);
              } else {
                break;
              }
            }
          }
        }
        
        pop () {
          const arr = this.data;
          let result = null;
          if (this.size > 1) {
            result = arr[0];
            arr[0] = arr.pop();
            this.ajust(0, this.size);
          } else if (this.size === 1) {
            return arr.pop();
          }
          return result;
        }
        
    }
    
        var heap = new Heap('max');
        heap.add(6)
        heap.add(10)
        console.log(heap.value);
        console.log(heap.pop());
        console.log(heap.value);
    

JavaScript中二叉树(二叉堆)的介绍(代码示例)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章