微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

TypeScript数据结构与算法15二叉堆的实现-BinaryMaxHeap

源码如下:

import { DataStruct_Array } from "../02-Arrays/DataStruct_Array";


//最大二叉堆也需要具有可比较性
type Comparable = {
    compareto(that: Comparable): number;
    equals(that: Comparable): boolean;
}


//最大二叉堆可比较性的数据类型
export class MaxBH_Data implements Comparable {
    constructor(private e: any) {
    }
    compareto(that: MaxBH_Data): number {
        return this.e - that.e;
    }
    equals(that: MaxBH_Data): boolean {
        return this.e === that.e;
    }
}

/**
* Autor: Created by 李清风 on 2021-01-03.
* Desc: 二叉堆(是一颗完全二叉树)
*           满二叉树:除了叶子节点,所有的节点都有左右节点
*           完全二叉树:她不一定是一个满二叉树,但是它缺失部分,一定是在右下侧
*/
export class DataStruct_BinaryMaxHeap<T>{

    //从底层实现一个最大堆

    //我使用数组来存储二叉堆
    //公式:(0号设置为空的情况)
    //parent(i) = i/2;
    //left child (i) = 2*i;
    //right child (i) = 2*i + 1;

    //(0号不设置为空的情况)
    //parent(i) = (i-1)/2;
    //left child (i) = 2*i+1;
    //right child (i) = 2*i + 2;

    private array: DataStruct_Array<T>;
    //private size:number;


    //当然你也可以初始化一个不知道多少个元素的二叉堆,扩容我帮你处理
    public constructor(capacity: number) {
        this.array = new DataStruct_Array<T>(capacity)
    }

    public size(): number {
        return this.array.getSize();
    }

    public isEmpty(): boolean {
        return this.array.isEmpty();
    }

    //返回完全二叉树中,index索引对应的父亲节点索引
    private parent(index: number) {
        if (index == 0) {
            throw new Error("index-0 doesn't hava parent.");
        }
        return (index - 1) / 2;
    }

    //返回完全二叉堆中,index索引对应的左孩子的节点索引
    private leftChild(index: number): number {
        return index * 2 + 1;
    }

    //返回完全二叉堆中,index索引对应的右孩子的i节点索引
    private rightChild(index: number): number {
        return index * 2 + 2;
    }

    //往堆中添加元素
    public add(e: T) {
        this.array.addLast(e);
        //上浮指定的元素
        this.siftUp(this.array.getSize() - 1);
    }

    private siftUp(k: number) {

        //上浮限定:不能是根节点&&如果小于其父亲节点 
        //this.array.get(this.parent(k)) 当前k节点的父亲节点元素
        //this.array.get(k) 当前k节点的元素

        while (k > 0 && this.array.get(this.parent(k)).compareto(this.array.get(k)) < 0) {
            this.array.swap(k, this.parent(k));
            k = this.parent(k);
        }
    }

    //从堆中取出元素,下沉操作
    public extractMax() {
        let ret = this.findMax();

        //将0索引和堆中最后一个元素交换位置,也就是将堆中最大元素放到末尾
        this.array.swap(0, this.array.getSize() - 1);
        this.array.removeLast();//删除末尾

        this.siftDown(0);//数据开始下沉操作
        return ret;
    }

    //找出堆中最大元素
    public findMax(): T {
        if (this.array.getSize() == 0) {
            //为空
            throw new Error("Can not findMax when heap is empty!");
        }
        return this.array.get(0);
    }

    siftDown(k: number) {
        while (this.leftChild(k) < this.array.getSize()) {
            let j = this.leftChild(k);
            if (j + 1 < this.array.getSize() && this.array.get(j + 1).compareto(this.array.get(j)) > 0) {
                j = this.rightChild(k);
            }
            //array[j]是leftChild和rightChild中的最大值
            if (this.array.get(k).compareto(this.array.get(j)) >= 0) {
                break;
            }
            this.array.swap(k, j);
            k = j; //准备下一次循环
        }
    }

    //取出最大元素后,替换成新元素e
    public replace(e) {
        let ret = this.findMax();
        this.array.set(0, e);
        this.siftDown(0);
        return ret;
    }
}

二叉堆HeapHeapify操作的单独拿出来实现

/**
* Autor: Created by 李清风 on 2020-12-17.
* Desc: 二叉堆heapify操作的实现
*/
export class DataStruct_HeapHeapify<T>{

    private array: DataStruct_HeapifyArray<T>;

    //用户传递进来一个数组,我们将数组转换成堆的形状
    public constructor(arr: T[]) {
        this.array = new DataStruct_HeapifyArray<T>(arr);
        for (let i = this.parent(arr.length - 1); i >= 0; i--) {
            this.siftDown(i); //实现heapify过程
        }
    }

    public size(): number {
        return this.array.getSize();
    }

    public isEmpty(): boolean {
        return this.array.isEmpty();
    }

    //返回完全二叉树中,index索引对应的父亲节点索引
    private parent(index: number) {
        if (index == 0) {
            throw new Error("index-0 doesn't hava parent.");
        }
        return (index - 1) / 2;
    }

    //返回完全二叉堆中,index索引对应的左孩子的节点索引
    private leftChild(index: number): number {
        return index * 2 + 1;
    }

    //返回完全二叉堆中,index索引对应的右孩子的i节点索引
    private rightChild(index: number): number {
        return index * 2 + 2;
    }

    //往堆中添加元素
    public add(e: T) {
        this.array.addLast(e);
        //上浮指定的元素
        this.siftUp(this.array.getSize() - 1);
    }

    private siftUp(k: number) {
        while (k > 0 && this.array.get(this.parent(k)).compareto(this.array.get(k)) < 0) {
            this.array.swap(k, this.parent(k));
            k = this.parent(k);
        }
    }

    //从堆中取出元素,下沉操作
    public extractMax() {
        let ret = this.findMax();

        //将0索引和堆中最后一个元素交换位置,也就是将堆中最大元素放到末尾
        this.array.swap(0, this.array.getSize() - 1);
        this.array.removeLast();//删除末尾

        this.siftDown(0);//数据开始下沉操作
        return ret;
    }

    //找出堆中最大元素
    public findMax() {
        if (this.array.getSize() == 0) {
            //为空
            throw new Error("Can not findMax when heap is empty!");
        }
        return this.array.get(0);
    }

    siftDown(k: number) {
        while (this.leftChild(k) < this.array.getSize()) {
            let j = this.leftChild(k);
            if (j + 1 < this.array.getSize() && this.array.get(j + 1).compareto(this.array.get(j)) > 0) {
                j = this.rightChild(k);
            }
            //array[j]是leftChild和rightChild中的最大值
            if (this.array.get(k).compareto(this.array.get(j)) >= 0) {
                break;
            }
            this.array.swap(k, j);
            k = j; //准备下一次循环
        }
    }
}


/**
* Autor: Created by 李清风 on 2020-12-17.
* Desc: 针对二叉堆heapify操作的实现,而创建的数组
*/
class DataStruct_HeapifyArray<T> {

    private data: T[];
    private size: number;


    //用来实现,用户将数组转换成二叉堆
    public constructor(arr: T[]) {
        this.data = new Array<T>(arr.length);
        for (let i = 0; i < arr.length; i++) {
            this.data[i] = arr[i];
        }
        this.size = arr.length;
    }

    public getSize(): number {
        return this.size;
    }

    public getCapacity(): number {
        return this.data.length
    }

    public isFull(): boolean {
        return this.size == this.data.length;
    }

    public isEmpty(): boolean {
        return this.size == 0;
    }

    //在数组尾添加元素
    public addLast(e: T) {
        this.add(this.size, e);
    }

    //添加元素到首
    public addFirst(e: T) {
        this.add(0, e);
    }

    public add(index: number, e: T) {
        if (index < 0 || index > this.size) {
            throw new Error("LogError:Add Failed.Require index >=0 and index<size.");
        }
        if (this.size == this.data.length) {
            this.resize(this.data.length * 2);//对数组进行扩容
        }
        for (let i: number = this.size - 1; i >= index; i--) {
            this.data[i + 1] = this.data[i];
        }
        this.data[index] = e;
        this.size++;
    }


    //因为使用了array来构造,这里只提供扩容的思路
    private resize(expandCount: number) {
        let newData: T[] = new Array<T>(expandCount);
        for (let i = 0; i < this.size; i++) {
            newData[i] = this.data[i];
        }
        this.data = newData; //内存引用地址转,等待GC回收
    }

    //移除指定index的元素
    public remove(index: number): T {
        if (index < 0 || index > this.size) {
            throw new Error("LogError:Add Failed.Require index >=0 and index<size.");
        }
        let ret: T = this.data[index];
        for (let i = index + 1; i < this.size; i++) {
            this.data[i - 1] = this.data[i]; //移位
        }
        this.size--;//更新size
        this.data[this.size] = null; //引用类型要注意释放loitering objects
        if (this.size == this.data.length / 2) {
            this.resize(this.data.length);
        }
        return ret;
    }

    public removeFirst() {
        return this.remove(0);
    }

    public removeLast() {
        return this.remove(this.size - 1);
    }

    public removeElement(e: T) {
        let index = this.find(e);
        if (index > 0) {
            this.remove(index);
        }
    }

    public get(index: number): T {
        if (index < 0 || index > this.size) {
            throw new Error("LogError:Add Failed.Require index >=0 and index<size.");
        }
        return this.data[index];
    }

    public getFirst(): T {
        return this.get(0);
    }

    public getLast(): T {
        return this.get(this.size - 1);
    }

    public set(index: number, e: T) {
        if (index < 0 || index > this.size) {
            throw new Error("LogError:Add Failed.Require index >=0 and index<size.");
        }
        this.data[index] = e;
    }

    public contains(e: T): boolean {
        for (let i = 0; i < this.size; i++) {
            if (this.data[i] == e) {
                return true;
            }
        }
        return false;
    }


    //寻找符合的元素,可以使用二分查找实现,但是需要对数组指定sort函数
    public find(e: T): number {
        for (let i = 0; i < this.size; i++) {
            if (this.data[i] == e) {
                return i;
            }
        }
        return -1;
    }

    //针对二叉堆扩展的交换函数
    public swap(i: number, j: number) {
        if (i < 0 || i >= this.size || j < 0 || j >= this.size) {
            throw new Error("Index is illegal");
        }

        let temp: T = this.data[i];
        this.data[i] = this.data[j];
        this.data[j] = temp;
    }
}

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐