//封装二叉搜索树
function Bintree() {


    //节点
    function Node(key) {
        this.key = key;
        this.left = null;
        this.right = null;
    }

    //根节点
    this.root = null;

    //插入节点
    Bintree.prototype.insert = function(key) {

        //1.创建新节点
        let newNode = new Node(key);


        //2.判断是否有根节点
        if (this.root == null) {
            //2.1让新节点作为根节点
            this.root = newNode;
        } else {
            //2.2调用节点比较插入的函数
            this.insertNode(this.root, newNode);
        }
    }


    //内部插入节点算法的函数
    this.insertNode = function(node, newNode) {

        //1.向右查找(新节点的key值大于当前节点的key值)
        if (newNode.key >= node.key) {
            //1.1判断当前节点是否存在右孩子节点
            if (node.right == null) {
                //1.2不存在就直接赋值
                node.right = newNode;
            } else {
                //1.3右孩子节点存在的话就递归调用该函数,将其作为当前节点和新节点继续比较
                this.insertNode(node.right, newNode);
            }
        } else {
            //2.向左查找(新节点的key值小于当前节点的key值)
            //2.1判断当前节点是否存在左孩子节点
            if (node.left == null) {
                //2.2不存在就直接赋值
                node.left = newNode;
            } else {
                //2.3左孩子节点存在的话就递归调用该函数,将其作为当前节点和新节点继续比较
                this.insertNode(node.left, newNode);
            }
        }


    }

    //先序遍历(根 左 右)
    Bintree.prototype.preorderTraversal = function(handler) {
        this.preorderTraversalNode(this.root, handler)
    }

    this.preorderTraversalNode = function(node, handler) {
        if (node !== null) {
            //1.处理经过的节点
            handler(node.key)
                //2.处理经过节点的左孩子节点
            this.preorderTraversalNode(node.left, handler)
                //3.处理经过节点的右孩子节点
            this.preorderTraversalNode(node.right, handler)
        }
    }

    //中序遍历(左 根 右)
    Bintree.prototype.inorderTraversal = function(handler) {
        this.inorderTraversalNode(this.root, handler)
    }

    this.inorderTraversalNode = function(node, handler) {
        if (node !== null) {
            //1.处理经过节点的左孩子节点
            this.inorderTraversalNode(node.left, handler)
                //2.处理经过的节点
            handler(node.key)

            //3.处理经过节点的右孩子节点
            this.inorderTraversalNode(node.right, handler)
        }
    }

    //后序遍历(左 右 根)
    Bintree.prototype.postorderTraversal = function(handler) {
        this.postorderTraversalNode(this.root, handler)
    }

    this.postorderTraversalNode = function(node, handler) {
        if (node !== null) {
            //1.处理经过节点的左孩子节点
            this.postorderTraversalNode(node.left, handler)
                //2.处理经过节点的右孩子节点
            this.postorderTraversalNode(node.right, handler)

            //3.处理经过的节点
            handler(node.key)
        }
    }

    //查找最值
    Bintree.prototype.max = function() {
        let node = this.root;
        let key = null;
        while (node !== null) {
            key = node.key;
            node = node.right;
        }

        return key;
    }

    Bintree.prototype.min = function() {
        let node = this.root;
        let key = null;
        while (node !== null) {
            key = node.key;
            node = node.left;
        }

        return key;
    }

    //搜索一个key是否存在
    Bintree.prototype.search = function(key) {
        let node = this.root;

        while (node != null) {
            if (key < node.key) {
                node = node.left;
            } else if (key > node.key) {
                node = node.right;
            } else {
                return true;
            }
        }

        return false;
    }

    //删除节点
    Bintree.prototype.remove = function(key) {

        let current = this.root; //要移动的当前节点(去找到要删除的节点)
        let parent = null; //当前节点的父节点
        let isLeftChild = null; //判断当前节点是左孩子还是右孩子

        //1.找到要删除的节点,没有找到就false
        while (current.key !== key) {
            //1.1向左移动
            if (key < current.key) {
                parent = current;
                current = current.left;
                isLeftChild = true;
            } else {
                //1.2向右移动
                parent = current;
                current = current.right;
                isLeftChild = false;
            }
            //1.3没有找到要删除的节点
            if (current == null) return false;

        }

        //2.根据对应情况删除节点

        //2.1删除的节点没有子节点
        if (current.left == null && current.right == null) {
            //2.1.1删除的节点是根节点
            if (current == this.root) {
                this.root = null;
                //2.1.2是叶子节点
            } else if (isLeftChild) {
                parent.left = null;
            } else {
                parent.right = null;
            }

        }


        //2.2删除的节点只有一个子节点
        //2.2.1删除的节点只有左子节点
        else if (current.right == null) {
            //2.2.1.1删除的节点是根节点
            if (current == this.root) {
                this.root = current.left;
                //2.2.1.2判断删除的节点是父节点的左孩子还是右孩子
            } else if (isLeftChild) {
                parent.left = current.left;
            } else {
                parent.right = current.left;
            }
            //2.2.2删除的节点只有右子节点
        } else if (current.left == null) {
            if (current == this.root) {
                this.root = current.right;
            } else if (isLeftChild) {
                parent.left = current.right;
            } else {
                parent.right = current.right;
            }
        }

        //2.3删除的节点有两个子节点
        else {
            //2.3.1获取后继节点
            let successor = this.getSuccessor(current);
            //2.3.2如果是根节点
            if (this.root == current) {
                this.root = successor;
            } else if (isLeftChild) {
                parent.left = successor;

            } else {
                parent.right = successor;
            }
            //因为找的是后继,删除节点的左子树一定都是后继节点的左子树
            successor.left = current.left;


        }


    }

    //找后继(删除节点的右子树中最小的节点)的方法
    this.getSuccessor = function(delNode) {
        let successorParent = delNode; //后继节点的父节点
        let successor = delNode; //后继节点
        let current = delNode.right; //移动指针

        while (current !== null) {
            successorParent = successor;
            successor = current;
            current = current.left;
        }

        if (successor !== delNode.right) {
            successorParent.left = successor.right;
            successor.right = delNode.right;
        }

        return successor;
    }
}

// 测试代码
var bst = new Bintree()

// 插入数据
bst.insert(11)
bst.insert(7)
bst.insert(15)
bst.insert(5)
bst.insert(3)
bst.insert(9)
bst.insert(8)
bst.insert(10)
bst.insert(13)
bst.insert(12)
bst.insert(14)
bst.insert(20)
bst.insert(18)
bst.insert(25)

//测试先序遍历
let resultStr = ""
    //调用preorderTraversal传入整理输出key的函数
bst.preorderTraversal(function(key) {
    resultStr += key + ' '
})
console.log(resultStr);

//测试中序遍历
resultStr = ''
bst.inorderTraversal(function(key) {
    resultStr += key + ' '
})
console.log(resultStr);

//测试后序遍历
resultStr = ''
bst.postorderTraversal(function(key) {
    resultStr += key + ' '
})
console.log(resultStr);

//测试获取最大值
console.log(bst.max());

//测试搜索key
console.log(bst.search(18));
console.log(bst.search(77));

//测试删除
bst.remove(9)
bst.remove(7)
bst.remove(15)
resultStr = ''
bst.postorderTraversal(function(key) {
    resultStr += key + ' '
})
console.log(resultStr);