云计算百科
云计算领域专业知识百科平台

数据结构与算法-二叉树

线性结构与非线性结构

数据的结构根据其节点关系,可以分为线性结构与非线性结构。

线性结构,也叫顺序结构,是指数据存储和访问的顺序关系。在线性结构中一个节点最多只能有一个前驱节点和一个后继结点。

在非线性结构中,一个节点可以有多个前驱节点和一个后继节点,没有后继节点的节点。

线性结构与非线性结构的区别:

特征线性结构非线性结构
数据关系 数据元素之间存在一对一的关系 数据元素之间有一对一也有一对多的关系
组织方式 顺序排列,像一条直线 层次或网状排列,像树或图
遍历方式 只需要一次顺序遍历即可访问所有元素 需要进行复杂的算法进行遍历,如:广度优先、深度有优先
举例 数组、链表 树、图

概念:树是一种典型的非线性结构,是由n(n>=0)个节点组成的有限集合,当n=0时称为空树。对于非空树,有且仅有一个根节点(root),其没有父节点,其余节点均可以分为m(m>=0)个同级无任何关系的子集和,每一个集合又可以是一个树,被称为根的子树。

特点:

  • 每个节点都可以有零个或者多个子节点
  • 没有父节点的节点称为根节点
  • 每一个非根节点有且仅有一个父节点
  • 除根节点外,每个子节点可以分为多个不相交的子树。
  • 树的基本术语:

  • 节点(Node):树的基本单位,包含数据域和指针域。
  • 边(Edge):连接两个节点的线。
  • 根节点(Root):树的最顶层节点。
  • 父节点(Parent):有子节点的节点。
  • 子节点(Child):被父节点指向的节点。
  • 叶子节点(Leaf):没有子节点的节点。
  • 内部节点(Internal node):至少有一个子节点的非根节点。
  • 度(Degree):一个节点含有的子树的个数
  • 层次(Level):从根开始定义,根为第一层,根的子树为第二层,以此类推。
  • 高度/深度(Height/Depth):树中节点的最大层次。
  • 二叉树

    概念:二叉树的树的一种特殊结构,二叉树中的每个节点做多只能有两个子节点,分别称为左子树和右子树。

    常见类型:

  • 满二叉树:所有层次的所有节点,要么都有两个子节点,要么都是叶子节点。
  • 完全二叉树:除了最后一层,其他节点都是满的,最后一层节点从左向右依次添加。
  • 平衡二叉树:任意节点的高度差不能大于1。
  • 排序二叉树:左侧子节点小于父节点,右侧节点大于父节点。
  • 二叉搜索树:是一种特殊的二叉树,满足一下条件:
    • 左侧的子节点小于父节点。
    • 右侧的子节点大于父节点。
  • 性质:

  • 树的第i层至多有2**(i – 1)个节点。
  • 深度为k的二叉树至多有2**k – 1个节点。
  • 对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0= N2+1。
  • 最多有n个节点的完全二叉树的深度必为:log₂(n+1)。
  • 对完全二叉树,若从上至下、从左至右编号,则编号为i的节点,其左孩子编号必为2i,其右孩子编号必为2i+1 , 其父节点的编号必为i//2(i=1 时为根,除外)。
  • 二叉树的遍历

    由于二叉树是非线性结构,不能用常规的顺序方法遍历,这里我们介绍两种复杂算法来遍历二叉树。

    树的添加、遍历方法

    class TreeNode:
    def __init__(self, item):
    self.item = item
    self.left = None
    self.right = None
    class BinaryTree:
    def __init__(self, root):
    self.root = root
    def add(self, item):
    """
    添加一个新节点
    :param item:要添加的节点
    :return:None
    """

    # 若根节点为空,则将新节点作为根节点
    if self.root is None:
    self.root = TreeNode(item)
    else:
    # 创建一个数组存储待添加节点
    queue = [self.root]
    # 当队列不为空时,循环
    while len(queue) > 0:
    # 从节点队列中取出一个节点
    node = queue.pop(0)
    # 判断该节点的左子树是否为空
    if node.left is None:
    # 为空则该节点的左子树
    node.left = TreeNode(item)
    break
    else:
    # 当前节点左子树不为空,则将左子树添加到队列中
    queue.append(node.left)
    # 判断该节点的右子树是否为空
    if node.right is None:
    # 为空则该节点的右子树
    node.right = TreeNode(item)
    break
    else:
    # 当前节点右子树不为空,则将右子树添加到队列中
    queue.append(node.right)
    def breadth_travel(self):
    """
    广度优先遍历
    :return: None
    """

    if self.root is None:
    return
    # 创建一个队列,将根节点添加到队列中
    queue = [self.root]
    while len(queue):
    # 从队列中取出第一个节点
    node = queue.pop(0)
    # 打印该节点数据
    print(node.item, end=' ')
    # 左子结点不为空,则将左子节点加入队列中
    if node.left is not None:
    queue.append(node.left)
    # 右子结点不为空,则将右子节点加入队列中
    if node.right is not None:
    queue.append(node.right)

    def preorder_travel(self, root):
    """
    深度优先遍历-前序遍历(输出顺序依次是:根 -> 左节点 -> 右节点)
    :param root: 根节点
    :return:
    """

    if root is None:
    return
    print(root.item, end=' ')
    self.preorder_travel(root.left)
    self.preorder_travel(root.right)

    def inorder_travel(self, root):
    """
    深度优先遍历-中序遍历(输出顺序依次是:左节点 -> 根 -> 右节点)
    :param root:根节点
    :return:
    """

    if root is None:
    return
    self.inorder_travel(root.left)
    print(root.item, end=' ')
    self.inorder_travel(root.right)

    def postorder_travel(self, root):
    """
    深度优先遍历-中序遍历(输出顺序依次是:左节点 -> 右节点 -> 根)
    :param root:根节点
    :return:
    """

    if root is None:
    return
    self.postorder_travel(root.left)
    self.postorder_travel(root.right)
    print(root.item, end=' ')

    广度优先(BFS)和深度优先(DFS)的区别:

    特性BFSDFS
    空间复杂度 O(b^d)(b为分支因子,d为深度) O(bd)
    完备性 总能找到解(如果存在) 在无限图中可能不完备
    最优性 找到的路径是最短路径 不一定是最短路径
    内存消耗 通常较大 通常较小
    实现方式 通常非递归 递归或非递归
    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 数据结构与算法-二叉树
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!