二叉树
- 常见的数组,栈,列表都是线性结构
- 常见的树型结构有:文件夹目录,dom结构,路由的配置…
二叉树
二叉树是每个结点最多有两个子树的树形结构,每个结点的度最多是2。左边的称为 左子树
, 右边的称为 右子树
, 左子树
, 右子树
是有顺序的。
实现二叉搜索树
class Node {
constructor(element, parent) {
this.element = element; //当前节点
this.parent = parent; //节点的父亲
this.left = null; //节点的左侧是什么
this.rigth = null; //节点的右侧是什么
}
}
class Tree {
constructor(compare) {
//比较器,可以用户自己配置比较规则
this.compare = compare || this.compare;
//根节点
this.root = null;
//总共有多少个节点
this.size = 0;
}
//内部实现的比较规则,如果用户自己配置了比较规则,则用用户自己的比较规则
compare(e1, e2) {
return e1 > e2;
}
//向树中添加节点
add(element) {
//判断根节点是否存在
if (this.root == null) {
//添加为根节点
this.root = new Node(element, null);
this.size++;
} else { //已经存在根节点了
//获取对比的参照物
let currentNode = this.root;
//父亲节点
let parent = null;
//对比的结果
let compare = null;
while (currentNode) {
parent = currentNode;
compare = this.compare(currentNode.element, element);
if (compare) {
//小于参照物
currentNode = currentNode.left;
} else {
//大于参照物
currentNode = currentNode.rigth;
}
}
//将节点挂到树上
const node = new Node(element, parent);
if (compare) {
parent.left = node;
} else {
parent.rigth = node;
}
this.size++;
}
}
}
const t = new Tree((e1, e2) => {
return e1.id > e2.id;
});
//自定义比较规则
t.add({
id: 10,
name: '章三1'
});
t.add({
id: 8,
name: '章三2'
});
t.add({
id: 6,
name: '章三3'
});
t.add({
id: 19,
name: '章三4'
});
t.add({
id: 15,
name: '章三5'
});
t.add({
id: 22,
name: '章三6'
});
t.add({
id: 20,
name: '章三7'
});
console.dir(t, {
depth: 1000
});
二叉树的遍历
常见的四种遍历方式
- 前序:
preorder traversal
, 先根节点,再左子树,最后右子树 - 中序:
inorder traversal
, 先左子树,再根节点,最后右子树,遍历出来的结果是有序的 - 后序:
postorder traversal
, 先左子树,再右子树,最后根节点 - 层序:
levelorder traversal
, 从上到下,从左到有一次遍历
前序遍历
递归实现
preOrderTraversal(cb) {
const traversal = node => {
if (node == null) return;
//先抛出根节点
cb(node);
//先遍历左边,再遍历右边
traversal(node.left);
traversal(node.rigth);
}
traversal(this.root);
}
循环实现
preOrderTraversal(cb) {
const queue = [this.root];
while (queue.length) {
const node = queue.pop();
cb(node);
if (node.rigth) {
queue.push(node.rigth);
}
if (node.left) {
queue.push(node.left);
}
}
}
中序遍历
inOrderTraversal(cb) {
const traversal = node => {
if (node == null) return;
traversal(node.left);
cb(node);
traversal(node.rigth);
}
traversal(this.root)
}
后序遍历
postOderTraversal(cb) {
const traversal = node => {
if (node == null) return;
traversal(node.left);
traversal(node.rigth);
cb(node);
}
traversal(this.root)
}
层序遍历
levelOrderTraversal(cb) {
const stack = [this.root];
while (stack.length) {
const node = stack.shift();
cb(node);
if (node.left) {
stack.push(node.left);
}
if (node.rigth) {
stack.push(node.rigth);
}
}
}
树的反战
reversalTree() {
if (this.root == null) return;
const stack = [this.root];
let currentNode = null;
let index = 0
while (currentNode = stack[index++]) {
const temp = currentNode.left;
currentNode.left = currentNode.rigth;
currentNode.rigth = temp;
if (currentNode.left) {
stack.push(currentNode.left);
}
if (currentNode.rigth) {
stack.push(currentNode.rigth)
}
}
return this.root;
}
完整代码
class Node {
constructor(element, parent) {
this.element = element; //当前节点
this.parent = parent; //节点的父亲
this.left = null; //节点的左侧是什么
this.rigth = null; //节点的右侧是什么
}
}
class Tree {
constructor(compare) {
//比较器,可以用户自己配置比较规则
this.compare = compare || this.compare;
//根节点
this.root = null;
//总共有多少个节点
this.size = 0;
}
//内部实现的比较规则,如果用户自己配置了比较规则,则用用户自己的比较规则
compare(e1, e2) {
return e1 > e2;
}
//向树中添加节点
add(element) {
//判断根节点是否存在
if (this.root == null) {
//添加为根节点
this.root = new Node(element, null);
this.size++;
} else { //已经存在根节点了
//获取对比的参照物
let currentNode = this.root;
//父亲节点
let parent = null;
//对比的结果
let compare = null;
while (currentNode) {
parent = currentNode;
compare = this.compare(currentNode.element, element);
if (compare) {
//小于参照物
currentNode = currentNode.left;
} else {
//大于参照物
currentNode = currentNode.rigth;
}
}
//将节点挂到树上
const node = new Node(element, parent);
if (compare) {
parent.left = node;
} else {
parent.rigth = node;
}
this.size++;
}
}
// preOrderTraversal(cb) {
// const traversal = node => {
// if (node == null) return;
// //先抛出根节点
// cb(node);
// //先遍历左边,再遍历右边
// traversal(node.left);
// traversal(node.rigth);
// }
// traversal(this.root);
// }
preOrderTraversal(cb) {
const queue = [this.root];
while (queue.length) {
const node = queue.pop();
cb(node);
if (node.rigth) {
queue.push(node.rigth);
}
if (node.left) {
queue.push(node.left);
}
}
}
inOrderTraversal(cb) {
const traversal = node => {
if (node == null) return;
traversal(node.left);
cb(node);
traversal(node.rigth);
}
traversal(this.root)
}
postOderTraversal(cb) {
const traversal = node => {
if (node == null) return;
traversal(node.left);
traversal(node.rigth);
cb(node);
}
traversal(this.root)
}
levelOrderTraversal(cb) {
const stack = [this.root];
while (stack.length) {
const node = stack.shift();
cb(node);
if (node.left) {
stack.push(node.left);
}
if (node.rigth) {
stack.push(node.rigth);
}
}
}
reversalTree() {
if (this.root == null) return;
const stack = [this.root];
let currentNode = null;
let index = 0
while (currentNode = stack[index++]) {
const temp = currentNode.left;
currentNode.left = currentNode.rigth;
currentNode.rigth = temp;
if (currentNode.left) {
stack.push(currentNode.left);
}
if (currentNode.rigth) {
stack.push(currentNode.rigth)
}
}
return this.root;
}
}
const t = new Tree((e1, e2) => {
return e1.id > e2.id;
});
//自定义比较规则
t.add({ id: 10, name: '章三1' });
t.add({ id: 8, name: '章三2' });
t.add({ id: 6, name: '章三3' });
t.add({ id: 19, name: '章三4' });
t.add({ id: 15, name: '章三5' });
t.add({ id: 22, name: '章三6' });
t.add({ id: 20, name: '章三7' });
console.dir(t.reversalTree(), { depth: 1000 });
// t.levelOrderTraversal((node) => {
// console.log(node.element)
// })