RubyLouvre / algorithmbook

没有经过整理的知识才是徒然浪费时间,伤透脑筋!
109 stars 67 forks source link

二叉树 #4

Open RubyLouvre opened 6 years ago

RubyLouvre commented 6 years ago
class Node{
   constructor(data){
       this.parent = null
       this.data = data;
       this.left = null;
       this.right = null
   }
}
class Tree{
  constructor(){
     this.root = null;
  }
  insert(data){}
  remove(data){}
  size(){}
  getNodeSize()
  height(){}
  getNodeHeight(){}
}
RubyLouvre commented 6 years ago

二叉树的插入

       insert(data) {
                var dir = this._insertLeft = !this._insertLeft;
                function insertIt(node, data) {
                    if (node.data === data) {
                        return false;
                    } else if (!node.left) {
                        node.left = new Node(data);
                        node.left.parent = node;
                        return true;
                    } else if (!node.right) {
                        node.right = new Node(data);
                        node.right.parent = node;
                        return true;
                    } else {
                        if (dir === true) {
                            return insertIt(node.left, data);//递归
                        } else {
                            return insertIt(node.right, data);//递归
                        }
                    }
                }
                var ret = false;
                if (!this.root) {
                    this.root = new Node(data);
                    ret = true;
                } else {
                    ret = insertIt(this.root, data);
                }
                if (ret) {
                    this._size++
                }
                return ret;
            }
RubyLouvre commented 6 years ago

二叉树的删除

remove(data) {
    var p = this.find(data);
    if (p) {
        this.removeNode(p);//方便递归
        this._size--;
    }
}

removeNode(node) {
    //replace表示删除之后顶替上来的结点
    //parent为replace结点的父结点
    // 如果删除的结点左右孩子都有
    if (node.left != null && node.right != null) {
        var succ = null;
        for (succ = node.right; succ.left != null; succ = succ.left); //找到后继
        node.data = succ.data; //覆盖值
        this.removeNode(succ); //递归删除,只可能递归一次
    } else {
        // 叶子或只有一个孩子的情况
        var child = node.left || node.right || null
        this.transplant(node, child);
    }

}
RubyLouvre commented 6 years ago

前驱与后缀

function precursor(node){
   var ret;
   if(node.left){//如果有左子树
      var ret = node.left
      while(ret.right){//在左子树查找最大的右结点
         ret = ret.right
      }
      return ret;
   }else{
      var p = node.parent;
      while(p && p.left === node){
        node = p;//找到一个父节点,是其父节点的父节点的左孩子
        p = p.parent;
      }
      return p;
   }
}

function successor(node){
   if(node.right){//如果有右子树
      var ret = node.left
      while(ret.left){//在右子树查找最大的左结点
         ret = ret.left
      }
      return ret;
   }else{
      var p = node.parent;
      while(p && p.right === node){
        node = p;//找到一个父节点,是其父节点的父节点的右孩子
        p = p.parent;
      }
      return p;
   }  
}
RubyLouvre commented 6 years ago

打印每一层的节点

 printNodeByLevel(callback) {
                var queue = []
                var out = []
                var node = this.root;
                if (node) {
                    queue.push(node)
                    queue.push(0)
                }
                while (queue.length) {
                    node = queue.shift()//先进先出
                    if (node) {
                        callback(node)
                        if (node.left) {
                            queue.push(node.left)
                        }
                        if (node.right) {
                            queue.push(node.right)
                        }
                    } else if(queue.length){
                        queue.push(0)
                        console.log("=======")
                    }
                }
            }
//-----------

         var tree = new SBT(); //10, 50, 40, 30, 20, 60, 55, 54, 53, 52, 51, 56
        [10, 50, 47, 30, 200, 60, 55, 504, 53, 52, 51, 56].forEach(function (el, i) {
            tree.insert(el)
        })
       var array = []
        tree.printNodeByLevel(function(node){
            if(node !== 0){
                array.push(node.data)
            }else{
                console.log(array.join(","))
                array.length = 0
            }
        })
        console.log(array.join(","))
        array.length = 0

image

RubyLouvre commented 6 years ago

水平打印

        class Node {
            constructor(data) {
                this.data = data;
                this.size = 1
                this.left = null;
                this.right = null;
                this.parent = null;
            }
            update() {
                var leftSize = this.left ? this.left.size : 0
                var rightSize = this.right ? this.right.size : 0
                this.size = leftSize + rightSize + 1;
            }

        };

        class SBT {
            constructor() {
                this.root = null;
                this._size = 0;
            }
            transplant(child, parent) {
                if (!parent) {
                    this.root = child;
                } else {
                    if (parent.data > child.data) {
                        parent.left = child
                    } else {
                        parent.right = child
                    }
                }
                if (child) {
                    child.parent = parent;
                }
            }
            leftRotate(node) {
                if (!node.right) {
                    return;
                }
                var child = node.right;
                node.right = child.left;
                if (child.left) {
                    //过继孩子
                    child.left.parent = node; //父属性修正1
                }
                this.transplant(child, node.parent) //父属性修正2
                node.parent = child; //父属性修正3
                child.left = node; //旋转
                //其他属性更新
                child.size = node.size;//child.update(),但直接赋值更快
                node.update();
            }
            rightRotate(node) {
                if (!node.left) {
                    return;
                }
                var child = node.left;
                node.left = child.right;
                if (child.right) {
                    //过继孩子
                    child.right.parent = node; //父属性修正1
                }
                this.transplant(child, node.parent) //父属性修正2
                node.parent = child; //父属性修正3
                child.right = node; //旋转
                //其他属性更新
                child.size = node.size;//child.update(),但直接赋值更快
                node.update();
            }
            maintain(node, rightDeeper) {
                var left = node.left;
                var right = node.right;
                if (!rightDeeper) {
                    if (!left) {
                        return
                    }
                    var rightSize = right && right.size || 0
                    var llSize = left.left && left.left.size || 0
                    var lrSize = left.right && left.right.size || 0
                    if (llSize > rightSize) {
                        this.rightRotate(node);
                    } else if (lrSize > rightSize) {
                        this.leftRotate(left);
                        this.rightRotate(node);
                    } else {
                        return;
                    }

                } else {
                    if (!right) {
                        return
                    }
                    var leftSize = left && left.size || 0
                    var rrSize = right.right && right.right.size || 0
                    var rlSize = right.left && right.left.size || 0
                    if (rrSize > leftSize) {
                        this.leftRotate(node);
                    } else if (rlSize > leftSize) {
                        this.rightRotate(right);
                        this.leftRotate(node);
                    } else {
                        return;
                    }
                }
            }

            size() {
                return this.root ? this.root.size : 0
            }
            find(data) {
                var node = this.root;
                while (node) {
                    var diff = data - node.data
                    if (diff == 0) {
                        break
                    } else if (diff < 0) {
                        node = node.left;
                    } else {
                        node = node.right;
                    }
                }
                if (node) {
                    return node
                }
                return null
            }
            insert(data) {
                if (!this.root) {
                    this.root = new Node(data);
                    this._size++;
                    return true;
                }
                var node = this.root,
                    parent, paths = [];
                while (node) {
                    paths.push(node);
                    var diff = data - node.data;
                    parent = node;
                    if (diff == 0) {
                        return false;
                    } else if (diff < 0) {
                        node = node.left;
                    } else {
                        node = node.right;
                    }
                }
                var node = new Node(data);
                node.parent = parent
                this._size++;
                if (diff < 0) {
                    parent.left = node;
                } else {
                    parent.right = node;
                }
                for (var i = paths.length - 1; i >= 0; i--) {
                    parent = paths[i];
                    parent.size++;
                    this.maintain(parent, data >= parent.data);
                }
                return true;
            }
            remove(data) {
                if (!this.root) {
                    return false
                }
                var node = this.find(data);
                if (node) {
                    //两个孩子的情况
                    if (node.left && node.right) {
                        var succ = this.maxNode(node.left); //求后继
                        node.data = succ.data;
                        node = succ; //转为一个孩子的情况
                    }
                    //一个或零个孩子的情况
                    this._size--;
                    var child = node.left || node.right || null;
                    var parent = node.parent,
                        p = parent,
                        paths = []
                    while (p) {
                        paths.push(p)
                        p = p.parent;
                    }
                    if (parent.left == node) {
                        parent.left = child
                    } else {
                        parent.right = child
                    }
                    if (child) {
                        child.parent = parent; //parent的size发生变化
                    }
                    while (p = paths.shift()) {
                        p.size--;
                        this.maintain(p, data >= p.data);
                    }
                }
            }
            maxNode(node) {
                var node = node || this.root;
                while (node.right) {
                    node = node.right
                }
                return node;
            }

            preOrder(callback) {//中左右
                var stack = []
                var node = this.root;
                while (node != null || stack.length) {//将所有孩子压栈
                    if (node != null) {
                        callback(node);//先于left之前访问
                        stack.push(node);
                        node = node.left
                    } else {
                        node = stack.pop();
                        node = node.right
                    }
                }
            }
            inOrder(callback) {//左中右
                var stack = []
                var node = this.root;
                while (node != null || stack.length) {//将所有孩子压栈
                    if (node != null) {
                        stack.push(node);
                        node = node.left
                    } else {
                        node = stack.pop();
                        callback(node);//先于right前访问
                        node = node.right
                    }
                }
            }
            postOrder(callback) {//左右中
                var stack = []
                var out = []
                var node = this.root;
                while (node || stack.length) {//将所有孩子压栈
                    if (node) {
                        stack.push(node);
                        out.push(node);
                        node = node.right;//先放右孩子 
                    } else {
                        node = stack.pop();
                        node = node.left//先放左孩子 
                    }
                }
                while (out.length) {
                    callback(out.pop())
                }
            }
            height() {
                return this.getNodeHeight(this.root);
            }
            printNodeByLevel(callback) {
                var queue = []
                var out = []
                var node = this.root;
                if (node) {
                    queue.push(node)
                    queue.push(0)
                }
                while (queue.length) {
                    node = queue.shift()//先进先出
                    if (node) {
                        callback(node)
                        if (node.left) {
                            queue.push(node.left)
                        }
                        if (node.right) {
                            queue.push(node.right)
                        }
                    } else if (queue.length) {
                        queue.push(0)
                        callback(0)
                    }
                }
            }
            //获取指定结点的度
            getNodeHeight(node) {
                if (node === null) {//递归出口
                    return 0;
                }
                var leftChildHeight = this.getNodeHeight(node.left);
                var rightChildHeight = this.getNodeHeight(node.right);
                var max = Math.max(leftChildHeight, rightChildHeight);
                return max + 1; //加上自己本身
            }
            breadthFirstTraval(callback) {
                var queue = []
                var out = []
                var node = this.root;
                node && queue.push(node)
                while (queue.length) {
                    node = queue.shift()//先进先出
                    callback(node)
                    if (node.left) {
                        queue.push(node.left)
                    }
                    if (node.right) {
                        queue.push(node.right)
                    }
                }
            }

            printNodeByLevel(callback) {
                var queue = []
                var out = []
                var node = this.root;
                if (node) {
                    queue.push(node)
                    queue.push(0)
                }
                while (queue.length) {
                    node = queue.shift()//先进先出
                    if (node) {
                        callback(node)
                        if (node.left) {
                            queue.push(node.left)
                        }
                        if (node.right) {
                            queue.push(node.right)
                        }
                    } else if (queue.length) {
                        callback(0)
                        queue.push(0) //用于分隔当前层
                    }
                }
            }
            toString() {
                //辅助方法,让数据居中对齐
                const brickLen = 6, SW = " ", LINE = "_"
                function displayData(node) {
                    var s = "(" + node.data + ")", right = true, isLeaf = !node.left && !node.right
                    for (var i = s.length; i < brickLen; i++) {
                        if (right) {
                            s = s + (isLeaf ? SW : LINE);
                        } else {
                            s = (isLeaf ? SW : LINE) + s;
                        }
                        right = !right
                    }
                    return s;
                }
                //创建4个字符的空白或下划线
                function createPadding(s, n) {
                    var ret = "";
                    n = n || brickLen;
                    for (var i = 0; i < n; i++) {
                        ret += s;
                    }
                    return ret;
                }
                //====================================
                //添加索引值
                var index = 0;
                tree.inOrder(function (el) {
                    el.index = index++;
                })
                // 收集每一层的结点
                var allLevelNodes = [];
                var array = [];
                tree.printNodeByLevel(function (node) {
                    if (node !== 0) {
                        array.push(node);
                    } else {
                        allLevelNodes.push(array);
                        array = [];
                    }
                })
                if (array.length) {
                    allLevelNodes.push(array);
                }
                //brickes中有数据的层,branches只是用来放斜线的层,都是二维数组
                var brickes = [];
                var branches = [];
                for (var i = 0, n = allLevelNodes.length; i < n; i++) {
                    if (!brickes[i]) {
                        brickes[i] = [];
                        branches[i] = [];
                    }
                    var cbrick = brickes[i];
                    var cbranch = branches[i];
                    var level = allLevelNodes[i];
                    while (level.length) {
                        var el = level.shift();
                        var j = el.index;
                         //确保cbrick[j]与cbranch[j]等长
                        cbrick[j] = displayData(el);
                        cbranch[j] = createPadding(SW, cbrick[j].length);

                        if (el.parent) {
                            var pbrick = brickes[i - 1];
                            var pbranch = branches[i - 1];
                            var pindex = el.parent.index;
                            if (el == el.parent.left) {//左子树
                                for (var k = j + 1; k < pindex; k++) {
                                    pbrick[k] = createPadding(LINE);
                                }
                                for (var k = j + 1; k < pindex; k++) {
                                    pbranch[k] = createPadding(SW);
                                }
                                pbranch[j] = createPadding(SW, brickLen - 1) + "/"
                            } else {//右子树
                                for (var k = pindex + 1; k < j; k++) {
                                    pbrick[k] = createPadding(LINE);
                                }
                                for (var k = pindex + 1; k < j; k++) {
                                    pbranch[k] = createPadding(SW);
                                }
                                pbranch[j] = "\\" + createPadding(SW, brickLen - 1)
                            }
                        }
                        j--;
                        inner:
                        while (j > -1) { //添加空白
                            if (cbrick[j] == null) {//将非空节点变成空字符串
                                cbrick[j] = createPadding(SW);
                                cbranch[j] = createPadding(SW)
                            } else {
                                break inner;
                            }
                            j--;
                        }
                    }

                }
                return brickes.map(function (el, i) {
                    return el.join("") + "\n" + branches[i].join("")
                }).join("\n")

            }
        }

        var tree = new SBT(); //10, 50, 40, 30, 20, 60, 55, 54, 53, 52, 51, 56
        [10, 50, 47, 30, 200, 60, 55, 504, 53, 52, 51, 56].forEach(function (el, i) {
            tree.insert(el)
        })

        console.log(tree + "")

image