排序二叉树的javascript实现及遍历

排序二叉树,满足节点的值大于左子树上的所有节点的值,且小于右子树上所有节点的值。

排序二叉树的实现

function BinaryTree () {
  // 节点的构造函数
  var Node = function (key) {
    this.key = key
    this.left = null
    this.right = null
  }
  // 根节点默认为null
  var root = null
  // 插入节点
  var insertNode = function (node, newNode) {
    if (newNode.key < node.key) {
      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 (key) {
    var newNode = new Node(key)
    if (root === null) {
      root = newNode
    } else {
      insertNode(root, newNode)
    }
  }

  // 中序遍历,通过中序遍历可以升序打印排序二叉树
  // 左 -> 父 -> 右
  var inOrderTraverseNode = function (node, callback) {
    if (node.left) {
      inOrderTraverseNode(node.left, callback)
    }
    callback(node.key)
    if (node.right) {
      inOrderTraverseNode(node.right, callback)
    }
  }

  this.inOrderTraverse = function (callback) {
    inOrderTraverseNode(root, callback)
  }
  
  // 前序遍历 父 -> 左 -> 右
  // 可以通过前序遍历 复制二叉树,(通过插入的方式复制一个已经存在的二叉树,时间复杂度更高 n*log(n))
  var preOrderTraverseNode = function (node, callback) {
    callback(node.key)
    if (node.left) {
      preOrderTraverseNode(node.left, callback)
    }
    if (node.right) {
      preOrderTraverseNode(node.right, callback)
    }
  }

  this.preOrderTraverse = function (callback) {
    preOrderTraverseNode(root, callback)
  }

  // 后续遍历 左 -> 右 -> 父 
  var postOrderTraverseNode = function (node, callback) {
    if (node.left) {
      postOrderTraverseNode(node.left, callback)
    }
    if (node.right) {
      postOrderTraverseNode(node.right, callback)
    }
    callback(node.key)
  }

  this.postOrderTraverse = function (callback) {
    postOrderTraverseNode(root, callback)
  }
  // 前序,中序,后序遍历,都是父->左->父->右->父,关键是什么时候打印父
  // 前序 父* ->  左  ->  父  ->  右  ->父
  // 中序 父  ->  左  ->  父* ->  右  ->父
  // 后序 父  ->  左  ->  父  ->  右  ->父*
  // 前中后序遍历都属于深度优先遍历

  // 层序遍历,属于广度优先遍历,通过一个队列实现
  this.levelOrderTraverse = function (callback) {
    var queue = [root]
    while (queue.length > 0) {
      var node = queue.pop()
      callback(node.key)
      if (node.left) queue.unshift(node.left)
      if (node.right) queue.unshift(node.right)
    }
  }

  // 查找最小值
  // 循环实现 最‘左边’的节点
  var minkey = function (node) {
    while (node.left) {
      node = node.left
    }
    return node.key
  }
  // 查找最小值的方法
  this.min = function () {
    return minkey(root)
  }

  // 查找最大值, 最‘右边’的节点
  var maxkey = function (node) {
    while (node.right) {
      node = node.right
    }
    return node.key
  }
  // 查找最大值的方法
  this.max = function () {
    return maxkey(root)
  }

  // 查找指定值
  var searchNode = function (node, key) {
    if (key === node.key) {console.log('ok');return true}
    else if (key < node.key && node.left) {return searchNode(node.left, key)}
    else if (node.right) {return searchNode(node.right, key)}
    return false
  }
  // 查找指定值的方法
  this.search = function (key) {
    return searchNode(root, key)
  }

  // 删除节点
  // 查找最小值,返回最小值的节点
  var minNode = function (node) {
    while (node.left) {
      node = node.left
    }
    return node
  }
  // 在某个子树中删除某个节点,参数1:子树的根节点, 参数2:删除值为多少的节点, 返回删除该节点后的子树根节点
  var removeNode = function (node, key) {
    // 该节点就是要删除的节点
    if (key === node.key) {
      // 该节点只有左孩子
      if (node.left && ! node.right) {
        node = node.left
      // 该节点只有右孩子
      } else if (node.right && ! node.left) {
        node = node.right
      // 该节点为叶子节点
      } else if ((! node.left) && (! node.right)) {
        node = null
      // 该节点同时具有左右子节点
      } else if (node.left && node.right) {
        var minNodeTmp = minNode(node.right)
        node.key = minNodeTmp.key
        node.right = removeNode(node.right, minNodeTmp.key)
      }
    // 要删除的节点 小于 该节点,在左子树中继续找
    } else if (key < node.key && node.left) {
      node.left = removeNode(node.left, key)
    // 要删除的节点 大于 该节点,在右子树中继续找
    } else if (node.right) {
      node.right = removeNode(node.right, key)
    }
    
    // 正常情况都返回这个node本身
    // 特殊情况返回null或需要接到上一层的节点,表示删除
    return node
  }
  // 删除节点的方法
  this.remove = function (key) {
    removeNode(root, key)
  }

  // 判断是否是完全二叉树,
  // 完全二叉树成立条件:层序遍历二叉树,找到某个节点,其左子节点为null,或左右子节点都为null,那么之后的节点都必须为叶子节点
  this.isCompleteTree = function () {
    var queue = [root], findEnd = false
    while (queue.length > 0) {
      var node = queue.pop()
      // 某个节点无左子节点且有右子节点 不是完全二叉树
      if (!(node.left) && node.right ) return false
      // 找到一个节点,有一个子节点为null(左null右不为null不为完全二叉树,已经排除),则后面的节点必须为叶子节点。通过一个flag保存这个状态
      if ((!node.left) || (!node.right)) findEnd = true
      // 如果已经找到了子节点存在null的节点,而当前节点又不是叶子节点,那么不是完全二叉树
      if (findEnd && (node.left || node.right)) return false
	
	  // 层序遍历,左右子节点的入队列
      if (node.left) queue.unshift(node.left)
      if (node.right) queue.unshift(node.right)
    }
    return true
  }

}

插入节点

var nodes = [8, 3, 10, 1, 6, 14, 4, 7, 13]
var binaryTree = new BinaryTree()
nodes.forEach(function (key) {
  binaryTree.insert(key)
})

得到的排序二叉树如图:
在这里插入图片描述
满足排序二叉树的条件

遍历

var inOrderResult = [], preOrderResult = [], postOrderResult = [], levelOrderResult= []

binaryTree.inOrderTraverse(function (key) {inOrderResult.push(key)})
console.log('中序遍历:', inOrderResult.join(' => '))

binaryTree.preOrderTraverse(function (key) {preOrderResult.push(key)})
console.log('前序遍历:', preOrderResult.join(' => '))

binaryTree.postOrderTraverse(function (key) {postOrderResult.push(key)})
console.log('后序遍历:', postOrderResult.join(' => '))

binaryTree.levelOrderTraverse(function (key) {levelOrderResult.push(key)})
console.log('层序遍历:', levelOrderResult.join(' => '))

输出结果:

中序遍历: 1 => 3 => 4 => 6 => 7 => 8 => 10 => 13 => 14
前序遍历: 8 => 3 => 1 => 6 => 4 => 7 => 10 => 14 => 13
后序遍历: 1 => 4 => 7 => 6 => 3 => 13 => 14 => 10 => 8
层序遍历: 8 => 3 => 10 => 1 => 6 => 14 => 4 => 7 => 13

判断是否为完全二叉树

console.log(binaryTree.isCompleteTree()) // false

当我们插入和删除一些节点后:

binaryTree.insert(-1)
binaryTree.insert(2)
binaryTree.insert(9)
binaryTree.remove(13)

console.log(binaryTree.isCompleteTree()) // true

在这里插入图片描述
此时为完全二叉树

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值