/**
* parent: 双亲节点
* left: 左子节点
* right: 右子节点
*/
interface TreeNode {
left: TreeNode | null,
right: TreeNode | null,
data: any,
count: number
}
class TreeNode {
constructor(data: any, left: TreeNode | null, right: TreeNode | null) {
this.data = data;
this.left = left;
this.right = right;
this.count = 1;
}
}
//二叉排序树
interface BsTree {
root: TreeNode | null
//删除一个节点
_removeNode(node: TreeNode, data: any): void
//删除给定的数据节点
remove(data: any): void
//向二叉树中插入节点
insert(data: any): void
//寻找给定数据的节点
find(data: any): TreeNode | null
//获得最小值的节点
getMinNode(node: TreeNode): TreeNode | null
//获得最大值的节点
getMaxNode(node: TreeNode): TreeNode | null
display(): void
// 获得二叉树中节点个数
getNodeNumber(node: TreeNode): number
// 获得二叉树中叶子节点的个数
getLeafNodeNumber(node: TreeNode): number
// 获取二叉树的深度
getTreeDepth(node: TreeNode): number
// 计算给定层数节点的个数
getLevelNodeNumber(level: any, node: TreeNode): number
// 判断二叉树是不是完全二叉树
isCompleteTree(node: TreeNode): boolean
// 求二叉树的镜像
invertTree(node: TreeNode): void
}
class BsTree {
root: TreeNode | null = null
/**
*
* @param node 要删除的节点
* @param data 要删除值
* 递归删除节点
* 待删除的节点是叶子节点。
* 待删除的节点没有左子节点,或者没有右子节点。
* 待删除的节点的左右子节点均存在。
* 当待删除的节点时叶子节点时,这种情况比较简单,直接将待删除的节点置空返回即可。
* 当待删除的节点没有左子节点时,返回该节点的右孩子节点,并删除该节点。待删除节点没有右节点时类似处理。
* 比较麻烦的是最后一种情况,待删除的节点的左右子节点均存在时,可以有两种做法:要么查找待删除节点左子树上的最大值,要么查找其右子树上的最小值。
* 这里使用查找其右子树上的最小值的方法。在找到待删除节点的右子树上的最小值后,创建一个临时节点,将临时节点上的值复制到待删除节点,然后再删除临时节点。
*/
_removeNode(node: TreeNode, data: any): TreeNode | null {
if (node == null) {
return null;
}
if (data == node.data) {
if (node.left == null && node.right == null) {
return null;
}
//没有左节点的节点
if (node.left == null) return node.right;
//没有右节点的节点
if (node.right == null) return node.left;
//有两个节点的节点
/*
做法:
找到待删除节点的右子树上的最小值创建一个临时节点。
将临时节点上的值复制到待删除节点,然后再删除临时节点
*/
// 寻找右子树上的最小值
let tmpNode = this.getMinNode(node.right);
if (tmpNode) {
node.data = tmpNode.data;
node.right = this._removeNode(node.right, tmpNode.data);
return node;
}
} else if (data < node.data && node.left) { // 待删除节点在左子树上
node.left = this._removeNode(node.left, data);
return node;
} else { // 待删除节点在右子树上
if (node.right) {
node.right = this._removeNode(node.right, data);
return node;
}
}
return null
}
/**
*
* @param data 要删除的节点值
*/
//删除给定的数据节点
remove(data: any): void {
if (this.root) {
console.log(this._removeNode(this.root, data));
}
}
/**
* 如果在插入时,root节点为空,则直接将新节点赋给root节点即可。
* 如果新的节点值小于当前节点值,说明待插入的位置应在在当前节点的左子树上,那么在大于时,就应该在当前节点的右子树上。进而更新当前节点所指向的节点,直到当前节点为空时,说明找到了正确的插入位置。
*/
insert(data: any): void {
let newNode = new TreeNode(data, null, null);
let parentNode = null;
if (this.root === null) {
this.root = newNode;
} else {
let currNode: any = this.root;
while (true) {
parentNode = currNode;
if (newNode.data > currNode.data) {
currNode = currNode.right;
if (!currNode) {
parentNode.right = newNode;
break;
}
} else if (newNode.data < currNode.data) {
currNode = currNode.left;
if (!currNode) {
parentNode.left = newNode;
break;
}
} else if (currNode.data === newNode.data) {
currNode.count++;
break;
}
}
}
}
//寻找给定数据的节点
find(data: any): TreeNode | null {
if (!this.root) {
return null;
}
let currNode: TreeNode = this.root;
while (currNode) {
if (data > currNode.data && currNode.right) {
currNode = currNode.right;
} else if (data < currNode.data && currNode.left) {
currNode = currNode.left;
} else {
return currNode;
}
}
return null;
}
//获得最小值的节点
getMinNode(node: TreeNode | null = this.root): TreeNode | null {
let currNode = node;
while (currNode?.left) {
currNode = currNode.left;
}
return currNode;
}
//获得最大值的节点
getMaxNode(node: TreeNode | null = this.root): TreeNode | null {
let currNode = node;
while (currNode?.right) {
currNode = currNode.right;
}
return currNode;
}
preOrderRec(node: any = this.root) {
let result = '';
if (!(node == null)) {
result += `${node.data} `;
result += this.preOrderRec(node.left);
result += this.preOrderRec(node.right);
}
return result;
}
// 前序遍历非递归方法
preOrderNonRec(node: any = this.root) {
let stack: Array<any> = [];
let result = '';
while (node || stack.length) {
if (node) {
result += `${node.data} `;
stack.push(node);
node = node.left;
} else {
node = stack.pop();
node = node.right;
}
}
return result;
}
inorderRec(node: any = this.root) {
let result = '';
if (!(node == null)) {
result += this.inorderRec(node.left);
result += `${node.data} `;
result += this.inorderRec(node.right);
}
return result;
}
//中序遍历非递归算法
inorderNonRec(node: any = this.root) {
let result = '';
let stack: Array<any> = [];
while (node || stack.length) {
if (node) {
stack.push(node);
node = node.left
} else {
node = stack.pop();
result += `${node.data} `;
node = node.right;
}
}
return result;
}
//后续遍历
postorderRec(node: any = this.root) {
let result = '';
if (!(node == null)) {
result += this.postorderRec(node.left);
result += this.postorderRec(node.right);
result += `${node.data} `
}
return result;
}
getNodeNumber(node = this.root) {
// 统计二叉树中结点个数的算法 (先根遍历)
let count = 0;
if (node) {
count++;
count += this.getNodeNumber(node.left);
count += this.getNodeNumber(node.right)
}
return count;
}
getnorNodeNumber(node: any = this.root) {
let queue = [];
let count = 0;
queue.push(node);
while (queue.length) {
count++;
let node = queue.shift();
if (node.left) {
queue.push(node.left);
}
if (node.right) {
queue.push(node.right);
}
}
return count;
}
//递归求叶子节点数量
getLeafNodeNumber(node: TreeNode | null = this.root): number {
let count = 0;
if (node) {
if (node.right == null && node.left == null) {
count++;
}
count += this.getNodeNumber(node.left);
count += this.getNodeNumber(node.right);
}
return count;
}
//非递归求叶子节点数量
getLeafnorNodeNumber(node: any = this.root): number {
let count = 0;
let queue = [];
if (node) {
queue.push(node);
while (queue.length) {
node = queue.shift();
if (node.left) {
queue.push(node.left);
}
if (node.right) {
queue.push(node.right);
}
if (!node.right && !node.left) {
count++;
}
}
}
return count;
}
//获得二叉树的深度
getTreeDepth(node: any = this.root): number {
if (!node) {
return 0;
}
let leftMax = this.getTreeDepth(node.left);
let rightMax = this.getTreeDepth(node.right);
if (leftMax > rightMax) {
return leftMax + 1;
} else {
return rightMax + 1;
}
}
//获得规定层数的节点个数(层序遍历法)
getLevelNodeNumber(level: number, node: any = this.root) {
if (node) {
let queue = [];
let depth = 1;
queue.push(node);
if (level === queue.length) return queue.length;
while (true) {
let size = queue.length;
if(size == 0) {
break;
}
while (size) {
node = queue.shift();//当前队列全部出栈后,保存的就是下一层节点
if (node.left) {
queue.push(node.left);
}
if (node.right) {
queue.push(node.right);
}
size--;
}
depth++;
if (depth === level) {
return queue.length;
}
}
}
}
//判断二叉树是不是完全二叉树 如果层次遍历时遇到一个空节点后,再向后的遍历的时候依然还有节点,则这个二叉树肯定不是完全二叉树。
isCompleteTree(node:any = this.root):boolean {
let queue = [];
let flag = false;
queue.push(node);
while(queue.length) {
node = queue.shift();
if(node) {
if(flag) return false;
queue.push(node.left);
queue.push(node.right);
} else {
flag = true;
}
}
return true;
}
//如果一个节点只有右子节点,则不是完全二叉树。当遍历到一个不是叶子节点的节点时,如果其前面的节点没有右孩子节点,则不是完全二叉树。
isCompleteTree2(node:any = this.root):boolean {
let queue = [];
let noright = false;
queue.push(node);
while(queue.length) {
node = queue.shift();
if(!node.left&&node.right) {
return false;
}
if((node.left||node.right) && noright) {
return true;
}
if(node.left) {
queue.push(node.left);
}
if(node.right) {
queue.push(node.right);
} else {
noright = true;
}
}
return true;
}
//镜像二叉树
invertTree(node = this.root) {
// 递归的方法
if (!node) return;
// 交换当前节点的左右子树
let tmpNode = node.left;
node.left = node.right;
node.right = tmpNode;
this.invertTree(node.left);
this.invertTree(node.right);
}
}
/**
* @param {Array} preArr 先序序列
* @param {Array} inArr 中序序列
* @param {Number} pBeg 先序序列的第一个下标
* @param {Number} pEnd 先序序列的最后一个下标
* @param {Number} iBeg 中序序列的第一个下标
* @param {Number} iEnd 中序序列的最后一个下标
*/
let myTree = new BsTree();
let tree2 = new BsTree();
function preInCreate(preArr: Array<Number>, inArr: Array<number>, pBeg: number, pEnd: number, iBeg: number, iEnd: number): TreeNode {
let node = new TreeNode(preArr[pBeg], null, null);
let lLen = 0, rLen = 0;
let splitIdx = -1;
if (tree2.root == null) {
tree2.root = node;
}
for (let i: number = iBeg; i <= iEnd; i++) {
if (inArr[i] === node.data) {
splitIdx = i;
break;
}
}
if (splitIdx > -1) {
lLen = splitIdx - iBeg;
rLen = iEnd - splitIdx;
}
if (lLen) {
node.left = preInCreate(preArr, inArr, pBeg + 1, pBeg + lLen, iBeg, iBeg + lLen - 1);
} else {
node.left = null;
}
if (rLen) { // 递归建立右子树
node.right = preInCreate(preArr, inArr, pEnd - rLen + 1, pEnd, iEnd - rLen + 1, iEnd);
} else {
node.right = null;
}
return node;
}
let preOrder = [20, 13, 7, 9, 15, 14, 42, 22, 21, 24, 57];
let inorder = [7, 9, 13, 14, 15, 20, 21, 22, 24, 42, 57];
let inLstIdx = inorder.length - 1;
let preLstIdx = preOrder.length - 1;
preInCreate(preOrder, inorder, 0, preLstIdx, 0, inLstIdx);
myTree.insert(20);
myTree.insert(13);
myTree.insert(7);
myTree.insert(9);
myTree.insert(15);
myTree.insert(14);
myTree.insert(42);
myTree.insert(22);
myTree.insert(21);
myTree.insert(24);
myTree.insert(57);
console.log(myTree.getNodeNumber());
console.log(myTree.getTreeDepth())
console.log(myTree.getLevelNodeNumber(3))
// console.log(myTree.postorderRec())