1.概念

二叉树:树中每个节点最多只能有两个子节点,这样的树就成为"二叉树"。

完美二叉树(满二叉树):除了最下一层的叶结点外,每层节点都有2个子结点,就构成了满二叉树。

完全二叉树:除二叉树最后一层外,其他各层的节点数都达到最大个数。且最后一层从左向右的叶结点连续存在,只缺右侧若干节点。

如下图所示:

生活中的数结构现象有:族谱,上下级领导等。

二叉树的遍历:先序遍历、中序遍历、后续遍历

(1)先序遍历:访问根结点,先序遍历其左子树,先序遍历其右子树。

(2)中序遍历:中序遍历其左子树,访问根结点,中序遍历其右子树。

(3)后续遍历:后序遍历其左子树,后序遍历其右子树,访问根结点。

2.遍历二叉树

前序遍历

//递归遍历
function preOrder(root) {
  let res = [];
  function __preOrder(root) {
    if (!root) return null;
    res.push(root.val);
    __preOrder(root.left);
    __preOrder(root.right);
  }
  __preOrder(root);
  return res
}
//非递归遍历
function preOrder(root) {
  if (!root) return null;
  let nodes = [];
  let res = [];
  nodes.push(root);
  while(nodes.length) {
    let node = nodes.pop();
    res.push(node.val);
    node.right && nodes.push(node.right);
    node.left && nodes.push(node.left);
  }
  return res
}

中序二叉树

//递归遍历
function midOrder(root) {
  let res = [];
  function __midOrder(root) {
    if (!root) return null;
    __midOrder(root.left);
    res.push(root.val);
    __midOrder(root.right);
  }
  __midOrder(root);
  return res
}
//非递归遍历
function midOrder(root) {
  let nodes = [];
  let res = [];
  while (root || nodes.length) {
    if (root) {
      nodes.push(root);
      root = root.left;
    } else {
      let node = nodes.pop();
      res.push(node.val);
      root = node.right;
    }
  }
  return res
}

后序遍历

//递归遍历
function postOrder(root) {
  let res = [];
  function __postOrder(root) {
    if (!root) return null;
    __postOrder(root.left);
    __postOrder(root.right);
    res.push(root.val);
  }
  __postOrder(root);
  return res
}
//非递归遍历
function postOrder(root) {
  if (!root) return null;
  let nodes = [];
  let res = [];
  nodes.push(root);
  while (nodes.length) {
    let node = nodes.pop();
    res.unshift(node.val);
    node.left && nodes.push(node.left);
    node.right && nodes.push(node.right);
  }
  return res
}

层序遍历

//非递归遍历
function levelOrder(root){
  // write code here
  if (!root) return [];
  let res = [];
  let nodes = [];
  nodes.push(root);
  while(nodes.length) {
    const len = nodes.length;
    let tmp = [];
    for(let i=0; i<len; i++) {
      let node = nodes.shift();
      tmp.push(node.val);
      node.left && nodes.push(node.left);
      node.right && nodes.push(node.right);
    }
    res.push(tmp);
  }
  return res;
}

3.封装二叉数

function BinarySerachTree() {
  // 创建结点构造函数
  function Node(key) {
    this.key = key
    this.left = null
    this.right = null
  }
  // 保存根的属性
  this.root = null

  BinarySerachTree.prototype.insert = function (key) {
    var newNode = new Node(key)
    if (this.root === null) {
      this.root = newNode
    } else {
      this.insertNode(this.root, newNode)
    }
  }
  BinarySerachTree.prototype.insertNode = function (node, newNode) {
    if (newNode.key < node.key) {
      if (node.left === null) {
        node.left = newNode
      } else {
        this.insertNode(node.left, newNode)
      }
    } else {
      if (node.right === null) {
        node.right = newNode
      } else {
        this.insertNode(node.right, newNode)
      }
    }
  }

  //前序遍历
  BinarySerachTree.prototype.preOrderTraversal = function (handler) {
    this.preOrderTranversalNode(this.root, handler)
  }
  BinarySerachTree.prototype.preOrderTranversalNode = function (node, handler) {
    if(node!==null){
      handler(node.key)
      this.preOrderTranversalNode(node.left, handler)
      this.preOrderTranversalNode(node.right, handler)
    }
  }

  // 中序遍历
  BinarySerachTree.prototype.inOrderTraversal = function (handler) {
    this.inOrderTraversalNode(this.root, handler)
  }
  BinarySerachTree.prototype.inOrderTraversalNode = function (node, handler) {
    if (node !== null) {
      this.inOrderTraversalNode(node.left, handler)
      handler(node.key)
      this.inOrderTraversalNode(node.right, handler)
    }
  }

  // 后续遍历
  BinarySerachTree.prototype.postOrderTraversal = function (handler) {
    this.postOrderTraversalNode(this.root, handler)
  }

  BinarySerachTree.prototype.postOrderTraversalNode = function (node, handler) {
    if (node !== null) {
      this.postOrderTraversalNode(node.left, handler)
      this.postOrderTraversalNode(node.right, handler)
      handler(node.key)
    }
  }

  BinarySerachTree.prototype.min = function () {
    var node = this.root
    while (node.left !== null) {
      node = node.left
    }
    return node.key
  }

  BinarySerachTree.prototype.max = function () {
    var node = this.root
    while (node.right !== null) {
      node = node.right
    }
    return node.key
  }

  BinarySerachTree.prototype.search = function (key) {
    node = this.root
    while(node!==null){
      if(node.key>key){
        node = node.left
      }else if(node.key<key){
        node = node.right
      }else{
        return true
      }
    }
    return false
  }

  // 删除结点
  BinarySerachTree.prototype.remove = function (key) {
    // 1.定义临时保存的变量
    var current = this.root
    var parent = this.root
    var isLeftChild = true
    // 2.开始查找节点
    while (current.key !== key) {
      parent = current
      if (key < current.key) {
        isLeftChild = true
        current = current.left
      } else {
        isLeftChild = false
        current = current.right
      }
      // 如果发现current已经指向null, 那么说明没有找到要删除的数据
      if (current === null) return false
    }

    if (current.left === null && current.right === null) {  // 3.删除的结点是叶结点
      if (current === this.root) {
        this.root = null
      } else if (isLeftChild) {
        parent.left = null
      } else {
        parent.right = null
      }
    } else if (current.right === null) {   // 4.删除有一个子节点的节点
      if (current === this.root) {
        this.root = current.left
      } else if (isLeftChild) {
        parent.left = current.left
      } else {
        parent.right = current.left
      }
    } 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
      }
    } else {   //5.删除有两个节点的节点
      // 1.获取后继节点
      var successor = this.getSuccessor(current)
      // 2.判断是否是根节点
      if (current === this.root) {
        this.root = successor
      } else if (isLeftChild) {
        parent.left = successor
      } else {
        parent.right = successor
      }
      // 3.将删除节点的左子树赋值给successor
      successor.left = current.left
    }
    return true
  }

  // 找后继(向右找最小的节点)的方法
  BinarySerachTree.prototype.getSuccessor = function (delNode) {
    // 1.使用变量保存临时的节点
    var successorParent = delNode
    var successor = delNode
    var current = delNode.right // 要从右子树开始找
    // 2.寻找节点
    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 BinarySerachTree()
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)
bst.insert(6)
var resultString = ""
bst.preOrderTraversal(function (key) {
  resultString += key + " "
})
console.log(resultString)  // 11 7 5 3 6 9 8 10 15 13 12 14 20 18 25
resultString = ""
bst.inOrderTraversal(function (key) {
  resultString += key + " "
})
console.log(resultString) // 3 5 6 7 8 9 10 11 12 13 14 15 18 20 25
resultString = ""
bst.postOrderTraversal(function (key) {
  resultString += key + " "
})
console.log(resultString) // 3 5 6 7 8 9 10 11 12 13 14 15 18 20 25
console.log(bst.search(10)) // true
console.log(bst.search(21)) // false
posted on 2021-03-15 19:30  李起桉  阅读(58)  评论(0编辑  收藏  举报