Js 实现 二叉树
定义二叉树
二叉树中,相对较小的值保存在左节点上,较大的值保存在右节点中
/*用来生成一个节点*/
function TreeNode(val, left, right) {
this.val = (val===undefined ? 0 : val)
this.left = (left===undefined ? null : left)
this.right = (right===undefined ? null : right)
}
/*用来生成一个二叉树*/
function BST() {
this.root = null;
this.insert = insert;
}
将数据插入二叉树
(1)设根节点为当前节点。
(2)如果待插入节点保存的数据小于当前节点,则设新的当前节点为原节点的左节点;反
之,执行第4步。
(3)如果当前节点的左节点为null,就将新的节点插入这个位置,退出循环;反之,继续
执行下一次循环。
(4)设新的当前节点为原节点的右节点。
(5)如果当前节点的右节点为null,就将新的节点插入这个位置,退出循环;反之,继续
执行下一次循环。
function insert(val) {
var n = new TreeNode(val, null, null);
if (this.root == null) {
this.root = n;
}
else {
var current = this.root;
var parent;
while (true) {
parent = current;
if (val < current.val) {
current = current.left;//待插入节点保存的数据小于当前节点,则设新的当前节点为原节点的左节点
if (current == null) {//如果当前节点的左节点为null,就将新的节点插入这个位置,退出循环;反之,继续执行下一次while循环。
parent.left = n;
break;
}
}
else {
current = current.right;//待插入节点保存的数据小于当前节点,则设新的当前节点为原节点的左节点
if (current == null) {
parent.right = n;
break;
}
}
}
}
}
递归实现
- 中序遍历
打印顺序: 左 根 右
作用:用于排序一个数组,从小到大升序排列。
var inorderTraversal = function(root) {
let res = []
order(root, res);
return res;
};
const order = function(root, res) {
if(!root) return;
order(root.left, res);
res.push(root.val);
order(root.right, res);
}
- 前序遍历
打印顺序: 根 左 右
作用:复制一个已有的二叉树结构,性能是最高的。比重新创造一个新的二叉树的效率高十倍多。
var preorderTraversal = function(root) {
let res = []
order(root, res);
return res;
};
const order = function(root, res) {
if(!root) return;
res.push(root.val);
order(root.left, res);
order(root.right, res);
}
- 后序遍历
打印顺序: 左 右 根
作用:用于操作系统和文件系统的遍历上。
var postorderTraversal = function(root) {
let res = []
order(root, res);
return res;
};
const order = function(root, res) {
if(!root) return;
order(root.left, res);
order(root.right, res);
res.push(root.val);
}
迭代实现
- 中序遍历
var inorderTraversal = function(root) {
const res = [];
if(root === null){
return res;
}
const stack = [root];
// 从根节点起,把其之下所有的左子树节点放进stack中
while(stack.length > 0){
// 从stack中每次弹出一个节点,把它的值存到结果数组里,并判断这个当前节点有没有左子树?
while(root.left !== null){
// 如果有左子树的话,重复进行while一下,把其之下的左子树全部放进去
root = root.left;
stack.push(root);
}
let cur = stack.pop();
res.push(cur.val);
if(cur.right !== null){
root = cur.right;
stack.push(root);
}
}
return res;
};
- 前序遍历
var preorderTraversal = (root) => {
const res = [];
const stack = [];
// 首先让左子节点尽可能地压入栈
while(root){
res.push(root.val);
if(root.right){
stack.push(root.right);
}
root=root.left;
}
// 循环结束时,栈顶的节点是位于树底部最左的一个左子节点,让它出栈,带出它的右子节点入栈(如果有)。
while(stack.length){
root = stack.pop();
res.push(root.val);
if(root.right){
stack.push(root.right);
}
root = root.left;
// 让这个右子节点,也要重复前面的逻辑『让左节点尽可能的压入栈』
while(root){
res.push(root.val);
if(root.right){
stack.push(root.right);
}
root=root.left;
}
}
return res;
}
- 后序遍历
var postorderTraversal = (root) => {
var res = [];
var stack = []; // 栈
var cur = root;
var lastVisitedNode = null;
while(cur || stack.length > 0) {
if(cur !== null){
stack.push(cur);
cur = cur.left;
} else {
cur = stack.pop();
if(cur.right === null || lastVisitedNode === cur.right) {
res.push(cur.val);
lastVisitedNode = cur;
cur = null;
} else {
stack.push(cur);
cur = cur.right;
}
}
}
return res;
}
层次遍历
广度优先 采用队列
var levelOrder = function(root) {
if (!root) return [];
let res = [];
let quene = [root];
while (quene.length > 0) {
let arr = [];
let len = quene.length;
while (len--) {
const node = quene.shift();
arr.push(node.val);
if (node.left) quene.push(node.left);
if (node.right) quene.push(node.right);
}
res.push(arr)
}
return res;
};