之前练习笔试的时刻刷题一向用的java,也参考某篇文章写过java版的二叉树罕见算法,由于立时要转正口试了,这几天都在预备口试,就把之前的翻出来用javascript从新写了一遍,二叉树基础都是递归处置惩罚的,也比较简单,就当作热身。背面也写了几种罕见的排序算法,并用快排求第K大值,别的假如之前java版的作者看到的话能够留言,我会标明文章援用。
Javacript二叉树罕见算法完成
节点组织函数和二叉树组织函数
function Node(key) {
this.key = key;
this.left = null;
this.right = null;
}
function binaryTree() {
this.root = null;
}
插进去节点天生二叉树
binaryTree.prototype.insert = function(root, key) {
var node = new Node(key);
if (root === null) { //树根节点为空则将此节点作为根节点
this.root = node;
} else if (node.key < root.key) { //小于左孩子节点则要么作为左子节点要么递归插进去左部门
if (root.left === null) {
root.left = node;
} else {
this.insert(root.left, key);
}
} else { //大于右孩子节点则要么作为右子节点要么递归插进去到右部份
if (root.right === null) {
root.right = node;
} else {
this.insert(root.right, key);
}
}
}
先序遍历
//先序遍历递归要领
binaryTree.prototype.preOrder = function(node) {
if (node !== null) {
console.log(node.key); //先打印当前结点
this.inOrder(node.left); //打印左结点
this.inOrder(node.right); //打印右结点
}
}
//先序遍历非递归要领
//首先将根节点入栈,假如栈不为空,掏出节点打印key值,然后顺次取右节点和左节点入栈,顺次反复
binaryTree.prototype.preOrder2 = function(node) {
let stack = [];
stack.push(node);
while (stack.length > 0) {
let n = stack.pop();
console.log(n.key);
if (n.right != null) {
stack.push(n.right);
}
if (n.left != null) {
stack.push(n.left);
}
}
}
中序遍历
//中序遍历递归要领
binaryTree.prototype.inOrder = function(node) {
if (node !== null) {
this.inOrder(node.left);
console.log(node.key);
this.inOrder(node.right);
}
}
//中序遍历非递归要领
//顺次取左节点入栈直到左下角节点入栈终了,弹出节点打印key,假如该节点有右子节点,将其入栈
binaryTree.prototype.inOrder2 = function(node) {
let stack = [];
while (node != null || stack.length) {
if (node != null) {
stack.push(node);
node = node.left;
} else {
let n = stack.pop();
console.log(n.key);
node = n.right;
}
}
}
后序遍历
binaryTree.prototype.postOrder = function(node) {
if (node !== null) {
this.inOrder(node.left);
this.inOrder(node.right);
console.log(node.key);
}
}
求树的深度
binaryTree.prototype.treeDepth = function(node) {
if (node === null) {
return 0;
}
let left = this.treeDepth(node.left);
let right = this.treeDepth(node.right);
return (left > right) ? (left + 1) : (right + 1);
}
推断两棵树结构是不是雷同
binaryTree.prototype.structCmp = function(root1, root2) {
if (root1 == null && root2 == null) { //根节点都为空返回true
return true;
}
if (root1 == null || root2 == null) { //根节点一个为空一个不为空返回false
return false;
}
let a = this.structCmp(root1.left, root2.left); //都有孩子节点则递归推断左侧是不是是雷同而且右侧也雷同
let b = this.structCmp(root1.right, root2.right);
return a && b; //左子树雷同而且右子树雷同
}
获得第k层节点个数
binaryTree.prototype.getLevelNum = function(root, k) {
if (root == null || k < 1) {
return 0;
}
if (k == 1) {
return 1;
}
return this.getLevelNum(root.left, k - 1) + this.getLevelNum(root.right, k - 1); //从左子树角度看,根节点第k层就是相对于左子树k-1层,把左子树右子树k-1层相加即可
}
求二叉树的镜像
binaryTree.prototype.mirror = function(node) {
if (node == null) return;
[node.left, node.right] = [node.right, node.left]; //交流摆布子树并顺次递归
this.mirror(node.left);
this.mirror(node.right);
}
近来大众先人节点
binaryTree.prototype.findLCA = function(node, target1, target2) {
if (node == null) {
return null;
}
if (node.key == target1 || node.key == target2) { //假如当前结点和个中一个节点相称则当前结点为大众先人
return node;
}
let left = this.findLCA(node.left, target1, target2);
let right = this.findLCA(node.right, target1, target2);
if (left != null && right != null) { //假如摆布子树都没找到则目的节点分别在摆布子树,根节点为其先人
return node;
}
return (left != null) ? left : right; // 找到的话返回
}
测试用
var tree = new binaryTree();
let arr = [45, 5, 13, 3, 23, 7, 111];
arr.forEach((node) => {
tree.insert(tree.root, node);
});
var tree2 = new binaryTree();
let arr2 = [46, 6, 14, 4, 24, 8, 112];
arr2.forEach((node) => {
tree2.insert(tree2.root, node);
});
tree.preOrder(tree.root);
tree.preOrder2(tree.root);
tree2.inOrder(tree2.root);
tree.inOrder2(tree.root);
let depth = tree.treeDepth(tree.root);
console.log(depth);
let isstructCmp = tree2.structCmp(tree.root, tree2.root);
console.log(isstructCmp);
let num = tree.getLevelNum(tree.root, 4);
console.log(num);
tree.mirror(tree.root);
tree.inOrder(tree.root);
let n = tree.findLCA(tree.root, 111, 3);
console.log(n);
疾速排序求第K大值
疾速排序
function quickSort(array) {
if(array.length <= 1){
return array;
}
let middle = Math.floor(array.length / 2)
let pivot = array.splice(middle, 1);
let left =[], right = [];
for(let i = 0; i < array.length; i++) {
if(array[i] < pivot) {
left.push(array[i]);
} else {
right.push(array[i]);
}
}
return quickSort(left).concat(pivot, quickSort(right));
}
疾速排序革新求第K大值
头脑是通过快排把数组切割成左中右三部份,将K与右侧数组(固然选左侧数组也能够)长度作比较,假如右侧数组长度为K-1,则中心元素即为第K大值,假如右侧数组长度大于即是K,则第K大元素肯定在右侧,则只需要对右侧数组递归求K大值,假如右侧数组长度小于K-1,则第K大值在左侧,在左数组求第k-1-right.length大值即可
function getK(array, k) {
if(array.length <= 1){
return array;
}
let middle = Math.floor(array.length / 2)
let pivot = array.splice(middle, 1);
let left =[], right = [];
for(let i = 0; i < array.length; i++) {
if(array[i] < pivot) {
left.push(array[i]);
} else {
right.push(array[i]);
}
}
if(right.length == k - 1){
return pivot;
} else if (right.length >= k) {
return getK(right, k);
} else {
return getK(left, k-right.length-1);
}
}
别的此要领也不是最好解法,另有一种比较好的解法是应用竖立K个元素的最小堆,新元素替代堆顶元素并调整堆,末了获得的K个元素即为最大的K个元素,时候复杂度NlogK