资讯专栏INFORMATION COLUMN

二叉树的实现

shengguo / 1252人阅读

摘要:概念二叉树是另一种树型结构,它的特点是每个结点至多只有两棵子树即二叉树中不存在度大于的结点,并且,二叉树的子树有左右之分其次序不能任意颠倒。查找最大值查找最小值思路传入二叉树,寻找左子树,直到找到不存在左子树的节点。

概念

二叉树(Binary Tree)是另一种树型结构,它的特点是每个结点至多只有两棵子树(即二叉树中不存在度大于 2 的结点),并且,二叉树的子树有左右之分(其次序不能任意颠倒。)

性质

二叉树的第 i 层上最多有 2 的(i-1)方个节点。(i>=1)

深度为 k 的树最多有 2 的 k 次方-1 个节点。(k>=1)

对任何一棵二叉树 T,如果其终端结点数为 n0,度为 2 的结点数为 n2,则 n0 = n2 + 1;
_ 一棵深度为 k 且有 2 的 k 次方-1 个结点的二叉树称为满二叉树
_ 深度为 k 的,有 n 个结点的二叉树,当且仅当其每一个结点都与深度为 k 的满二叉树中编号从 1 至 n 的结点一一对应时,称之为完全二叉树

初始化二叉树结构
// 创建节点
class Node {
  constructor(key) {
    this.key = key
    this.left = null
    this.right = null
  }
}
// 创建二叉树格式
class BinaryTree {
  constructor(...args) {
    this.root = null
    // 初始化依次插入数据
    args.forEach(key => {
      this.insert(key)
    })
  }
  // 实例化
  static create(args) {
    return new BinaryTree(...args)
  }
}
新增方法

思路:判断插入的节点和当前节点,若大于当前节点,去右子树插入,否则左子树插入。

insert(key) {
  const newNode = new Node(key);
  const 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);
      }
    }
  };
  if (this.root === null) {
    // 如果root不存在,将newNode设为根节点
    this.root = newNode
  } else {
    insertNode(this.root, newNode)
  }
}

调用形式

const nodes = [8, 3, 10, 1, 6, 14, 4, 7, 13]
const binaryTree = BinaryTree.create(nodes)
binaryTree.insert(55)
console.log(binaryTree.root)
遍历方法

二叉树的遍历(traversing binary tree)是指从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次且仅被访问一次。

前序遍历(DLR)
首先访问根结点,然后遍历左子树,最后遍历右子树。简记根-左-右。

用途:用于复制一颗二叉树

算法思路
若二叉树为空,则遍历结束;否则 1. 访问根结点 2. 先序遍历左子树(递归调用本算法) 3. 先序遍历右子树(递归调用本算法)

// 前序遍历
preOrderTraverse () {
    const preOrderTraverse = node => {
      if (node !== null) {
        console.log(node.key)
        preOrderTraverse(node.left)
        preOrderTraverse(node.right)
      }
    }
    preOrderTraverse(this.root)
}
中序遍历(LDR)
首先遍历左子树,然后访问根结点,最后遍历右子树。简记左-根-右。

用途:用于从小到大排序二叉树

算法思路
若二叉树为空,则遍历结束;否则 1. 中序遍历左子树(递归调用本算法) 2. 访问根结点 3. 中序遍历右子树(递归调用本算法)

//使用递归方式实现中序遍历
inOrderTraverse () {
    const inOrderTraverseNode = node => {
      if (node !== null) {
        // 如果当前节点非空,则访问左子树
        inOrderTraverseNode(node.left)
        // 直到访问到最底部的左子树才进入callback,每个节点都会有callback
        console.log(node.key)
        // 此时已经是最底部的左子树
        inOrderTraverseNode(node.right)
      }
      // 解释:首先进入8,发现左边有3,执行左边遍历,遍历完后执行3的回调,在执行3的右边的回调,
    }
    inOrderTraverseNode(this.root)
}
后序遍历(LRD)
首先遍历左子树,然后遍历右子树,最后访问根结点。简记左-右-根。

算法思路
若二叉树为空,则遍历结束;否则 1. 后序遍历左子树(递归调用本算法); 2. 后序遍历右子树(递归调用本算法) ; 3. 访问根结点 。

postOrderTraverse () {
    const postOrderTraverse = node => {
      if (node !== null) {
        postOrderTraverse(node.left)
        postOrderTraverse(node.right)
        console.log(node.key)
      }
    }
    postOrderTraverse(this.root)
  }
查找算法 查找最大值

思路:传入二叉树,寻找右子树,直到找到不存在右子树的节点。

// 查找最大值
max () {
    const maxNode = node => {
      if (node !== null) {
        if (node.right) {
          return maxNode(node.right)
        } else {
          return node.key
        }
      }
    }
    return maxNode(this.root)
}
查找最小值

思路:传入二叉树,寻找左子树,直到找到不存在左子树的节点。

// 查找最小值
min () {
    const minNode = node => {
      if (node !== null) {
        if (node.left) {
          return minNode(node.left)
        } else {
          return node.key
        }
      }
    }
    return minNode(this.root)
}
查找任意值

思路:根据传入的 key 与当前节点比较,如果大于当前 key 则去右子树查找,否则去左子树查找。

// 查找指定值
search (key) {
  const searchNode = function(node, key) {
    if (node === null) {
      return false
    }
    if (key < node.key) {
      return searchNode(node.left, key)
    } else if (key > node.key) {
      return searchNode(node.right, key)
    } else {
      return true
    }
  }
  return searchNode(this.root, key)
}
删除算法

思路:如果删除的 key 小于当前节点,去左子树种查找,否则去右子树查找。找到节点后,判断是否存在子节点,若不存在,直接删除,若只存在左节点或者右节点,将当前节点替换为它的子节点。若左右节点都存在,将右节点中的最小值(左子树)移除并替换为删除的节点位置(为了满足二叉树的左子树小于右子树)

remove (key) {
  // 用于查找最小节点
  const findMinNode = node => {
    if (node) {
      // 如果node的左孩子存在
      while (node && node.left !== null) {
        // 将node设为node的左孩子再次进入循环
        node = node.left
      }
      // 直到返回没有左孩子的node
      return node
    }
  }
  const removeNode = (node, key) => {
    if (node === null) {
      return false
    }
    if (key < node.key) {
      // 当前node大于删除key,去左孩子中查找
      node.left = removeNode(node.left, key)
      return node
    } else if (key > node.key) {
      // 当前node小于删除key,去右孩子中查找
      node.right = removeNode(node.right, key)
    } else {
      // key和当前node相等
      if (node.left === null && node.right === null) {
        node = null
        return node
      }
      // 任意一边没有值,取另一边
      if (node.left === null) {
        node = node.right
        return node
      } else if (node.right === null) {
        node = node.left
        return node
      }
      // 同时存在左孩子和右孩子
      // 找出右边的最小值
      const aux = findMinNode(node.right)
      // 将最小值替换为删除的key
      node.key = aux.key
      // 在右孩子中删除最小值
      node.right = removeNode(node.right, aux.key)
      return node
    }
  }
  const result = removeNode(this.root, key)
  console.log(result)
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95618.html

相关文章

  • 【数据结构初阶之叉树】:叉树相关的性质和经典的习题(用C语言实现,附图详解)

    摘要:当集合为空时,称该二叉树为空二叉树。也就是说,如果一个二叉树的层数为,且结点总数是,则它就是满二叉树。完全二叉树完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。 ...

    Martin91 评论0 收藏0
  • Java数据结构与算法——叉树及操作(包括叉树遍历)

    摘要:本篇主要介绍二叉树的概念二叉树的表示二叉树的操作三种遍历方式实现求二叉树的子树求节点的父节点二叉树高度,可能是考试中的,也可能是面试中的。通常二叉树的遍历根据根节点的遍历次序分为先根遍历中根遍历后根遍历。 声明:码字不易,转载请注明出处,欢迎文章下方讨论交流。 前言:Java数据结构与算法专题会不定时更新,欢迎各位读者监督。本篇主要介绍二叉树的概念、二叉树的表示、二叉树的操作(三种遍历...

    muddyway 评论0 收藏0
  • 【数据结构初阶】第八篇——二叉树的链式结构(二叉树的前、中和后序遍历+层序遍历+链式结构的实现+相关

    摘要:代码实现如下二叉树的创建与销毁二叉树的创建问题通过前序遍历的数组给定一串字符串,代表的是空树,其他的都是节点。 ⭐️本篇博客我要来和大家一起聊一聊数据结构中的二...

    BigNerdCoding 评论0 收藏0
  • js 中二叉树的深度遍历与广度遍历(递归实现与非递归实现)

    摘要:树中结点的最大层次称为树的深度或高度。二叉树有深度遍历和广度遍历,深度遍历有前序中序和后序三种遍历方法。二叉树的前序遍历可以用来显示目录结构等中序遍历可以实现表达式树,在编译器底层很有用后序遍历可以用来实现计算目录内的文件及其信息等。 树的简介 栈、队列、链表等数据结构,都是顺序数据结构。而树是非顺序数据结构。树型结构是一类非常重要的非线性结构。直观地,树型结构是以分支关系定义的层次结...

    Yuanf 评论0 收藏0
  • js数据结构和算法(三)叉树

    摘要:同样结点树的二叉树,完全二叉树的深度最小。二叉树每个结点最多有两个孩子,所以为它设计一个数据域和两个指针域是比较自然的想法,我们称这样的链表叫做二叉链表。 二叉树的概念 二叉树(Binary Tree)是n(n>=0)个结点的有限集合,该集合或者为空集(空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。 showImg(https://seg...

    DesGemini 评论0 收藏0

发表评论

0条评论

shengguo

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<