1.二叉树
最多只有两个节点的树
2.二叉搜索树
是二叉树的一种,但是只允许它的左子树小于父节点,右子树大于或等于父节点
3.先序遍历,先访问根节点==》左节点==》右节点
4.中序遍历,左节点===》根节点==》右节点
5.后序遍历,左节点==》右节点==》根节点
代码实现:
var BinaryTree = function () {
var Node = function (val) {
this.val = val;
this.left = null;
this.right = null;
}
var root = null;
//向树中插入一个新的节点
var insertNode = function (node,newnode) {
if(newnode.val < node.val){
if(node.left === null){
node.left = newnode;
}else{
insertNode(node.left,newnode)
}
}else {
if(node.right === null){
node.right = newnode;
}else{
insertNode(node.right,newnode);
}
}
}
this.insert = function (val) {
var node = new Node(val);
if(root === null){
root = node;
}else{
insertNode(root,node);
}
}
//查找一个值,存在返回true,不存在返回false
var searchTree1 = function (node,val) {
if(node === null){
return false;
}
if(node.val >val){
return searchTree1(node.left,val);
}else if(node.val<val){
return searchTree1(node.right,val);
}else {
return true;
}
}
this.serach = function (val) {
return searchTree1(root,val);
}
//递归方法,中序遍历所有节点
var inorder = function (node,cb) {
if(node !== null) {
inorder(node.left,cb);
cb(node.val);
inorder(node.right,cb);
}
}
this.inOrderTraverse = function (cb) {
inorder(root,cb);
}
//递归,前序遍历所有节点
var preorder = function (node,cb) {
if(node !== null){
cb(node.val);
preorder(node.left,cb);
preorder(node.right,cb);
}
}
this.preOrderTraverse = function (cb) {
preorder(root,cb)
}
//递归,后序遍历所有节点
var postorder = function (node,cb) {
if(node !== null) {
postorder(node.left,cb);
postorder(node.right,cb);
cb(node.val);
}
}
this.postOrderTraverse = function (cb) {
postorder(root,cb)
}
//最小值
var minval = function (node) {
if(node === null){
return null;
}
while(node!=null&&node.left!=null){
node = node.left;
}
return node.val;
}
this.min = function () {
return minval(root);
}
//最大值
var maxval = function (node) {
if(node === null){
return null;
}
while(node!=null&&node.right!=null){
node = node.right;
}
return node.val;
}
this.max = function () {
return maxval(root);
}
//删除某个节点
var anxNode = function (node) {
while(node!==null&&node.left!==null){
node = node.left;
}
return node;
}
var removeNode = function (node,val) {
if(node === null){
return false;
}
if(node.val === val){
//1左右节点都为空的情况
if(node.left === null&&node.right===null){
node = null;
return node;
}
//2.左节点不为空,右节点为空的情况
else if(node.left!==null&&node.right===null){
node = node.left;
return node;
}
//3.左节点为空,右节点不为空
else if(node.left === null &&node.right!==null){
node = node.right;
return node;
}
//左右节点都不为空,此时应该找右节点的最小左节点作为替换删除节点的节点
else if(node.left!==null&&node.right!==null){
var anx = anxNode(node.right);
node.val = anx.val;
node.right = removeNode(node.right,node.val);
return node;
}
}else if(node.val < val){
node.right = removeNode(node.right,val);
return node;
}else{
node.left = removeNode(node.left,val);
return node;
}
}
this.remove = function (val) {
removeNode(root,val);
}
this.getRoot = function () {
return root;
}
}
6先序遍历
首先初始化一个栈,将根节点压入栈,
1.当栈不为空的时候取出栈顶元素node1,访问,并存入数组
2.如果node1的右节点不为空,将node1的右节点压入栈
3.如果node1的左节点不为空将它压入栈 当栈不为空时,循环1,2,3 注意应该先让右节点先入栈
代码实现:
var preOrder = function (node,cb) {
var res = [];
var stack = [];
stack.push(node);
while (stack.length){
var node1 = stack.pop();
res.push(node1.val);
cb(node1.val);
if(node1.right!==null){
stack.push(node1.right);
}
if(node1.left!==null){
stack.push(node1.left);
}
}
return res;
}
7中序遍历,非递归
思路: 将当前节点压入栈,然后将左子树当作当前节点,如果当前节点为空,将双亲节点取出来,访问该节点 并将该节点存入数组,然后将右节点当作当前节点,进行循环
var inOder = function (node,cb) {
let result = [];
let stack = [];
while(stack.length || node) { // 是 || 不是 &&
if(node) {
stack.push(node);
node = node.left;
} else {
node = stack.pop();
result.push(node.value);
cb(node.val);
node = node.right; // 如果没有右子树 会再次向栈中取一个结点即双亲结点
}
}
return result;
}
8.后序遍历的非递归算法实现
思路:
首先将根节点压入栈, 当栈不为空时执行以下循环:
如果当前节点有左子树存在且没有被访问过!touch,将touch修改为‘left'表示已经访问过了并将该节点压入栈,并令当前节点为该节点的左节点,
如果当前节点的右子树存在并且touch !=='right' 表示没有被访问过,将该节点touch赋值为'right', 将该节点压入栈,令当前节点等于他的右节点
如果当前节点左右子树都不存在,那么获取栈顶元素,删除touch属性,并将值保存在数组中, *然后在令当前节点为栈顶元素继续回溯,直到栈为空
代码:
var postOrder = function (node,cb) {
var stack = [];
var res = [];
stack.push(node);
while(stack.length){
if(node.left && !node.touch){
node.touch = 'left';
node = node.left;
stack.push(node);
continue;
}
if(node.right && node.touch !== 'right'){
node.touch = 'right';
node = node.right;
stack.push(node);
continue;
}
//当node的左右节点都为空的时候,获取栈顶元素,并且访问它
node = stack.pop();
node.touch && delete node.touch;//如果node有touch属性就删除这个属性
res.push(node.val);
cb(node.val);
node = stack.length?stack[stack.length-1]:null;
}
return res;
}
9.广度遍历(层次遍历)
主要利用队列实现的,广度遍历是从二叉树的根结点开始,自上而下逐层遍历;在同一层中,按照从左到右的顺序对结点逐一访问。
递归算法:
var bfsDigui = function (node) {
var stack = [];
var res = [];
var count = 0;
stack.push(node);
function f() {
var newnode = stack[count];
if(newnode){
res.push(newnode.val);
newnode.left && stack.push(newnode.left);
newnode.right && stack.push(newnode.right);
count++;
f();
}
}
f();
return res;
}
非递归算法,没有使用shift()方法,因为比较消耗性能:
var bfs = function (node) {
var stack = [];
var res = [];
var pointer = 0;
stack.push(node);
while(pointer<stack.length){
var node = stack[pointer];
res.push(node.val);
node.left && stack.push(node.left);
node.right &&stack.push(node.right);
pointer++;
}
return res;
}
this.bfs2 = function () {
return bfs(root);
}
}