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; } }

浙公网安备 33010602011771号