二叉树 四则运算 中序转后序 实现 java_重学数据结构之树和二叉树

本文介绍了树和二叉树的基本概念、术语及性质,并详细讲解了满二叉树和完全二叉树。通过Python实现了一个二叉树类,包括创建、遍历等方法。接着探讨了如何利用二叉树解决表达式计算问题,通过建立二叉树、转换为三元组进而计算表达式值,展示了如何求解‘1+2*3-4/5’的计算结果。
摘要由CSDN通过智能技术生成

一、树和森林

1.基本概念

树状图(Tree)又称为树,是一种复杂的数据结构。树是由 n(n>=0)个有限节点组成一个具有层次关系的集合,把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。当 n=0 时,称之为空树,否则是非空树。

树具有以下的特点:

每个节点有零个或多个子节点;

没有父节点的节点称为根节点;

每一个非根节点有且只有一个父节点;

除了根节点外,每个子节点可以分为多个不相交的子树。

2.基本术语

子女:若节点的子树非空,则节点子树的根即为该节点的子女。

双亲:若节点有子女,则该节点即为子女的双亲。

兄弟:同一节点的子女互称为兄弟。

度:节点的子女个数即为该节点的度。

分支节点:度不为0的节点即为分支节点。

叶子节点:度为0的节点即为叶子节点。

深度:节点的深度即为该节点所在的层次。

高度:规定叶子节点的高度为1,其双亲节点的高度等于它的高度加1。

森林:森林是 m(m>=0)颗树的集合。

二、二叉树

1.基本概念

一颗二叉树是节点的有限集合,该集合或者为空,或者由一个根节点和两颗分别称为左子树和右子树的、互不交叉的二叉树组成(子树有左右之分,不可颠倒)。下面是二叉树的五种形态:

d811a4596e62a34fcf3dc06c90a5ef60.png

2.基本性质

性质1:若二叉树节点的层次从1开始,则在二叉树的第 i 层最多有 2i-1个节点(i>=1)。

性质2:深度为 k 的二叉树最少有 k 个节点,最多有 2k-1个 节点(k>=1)。

性质3:对任意一颗二叉树,如果其叶子节点有 m 个,度为2的非叶子节点为 n 个,则有:m = n + 1。

设度为1的节点有 p 个,总节点数为 x,总边数为 e,则 x = m + n + p,e  = n - 1 = 2 * n + p。因此有:

2 * n + p = m + n + p - 1

n = m - 1

m = n + 1

3.满二叉树和完全二叉树

1)满二叉树:除了最后一层无任何子节点,每一层的所有节点都有两个子节点,即除了叶子节点外的所有节点均有两个子节点,这样的二叉树就称为满二叉树。

2)完全二叉树:设一个二叉树的深度为 k,即共有 k 层。除了第 k 层外,其他各层的节点数都达到最大个数,且最后一层上只缺少右边的若干节点,这样的二叉树就称为完全二叉树。

4.Python 实现

下面是用 Python 实现的一个二叉树的代码,除了实现创建二叉树,还实现了四种遍历二叉树的方法,分别是:前序遍历、中序遍历、后序遍历和层次遍历。

1 # 自定义树节点

class Node:

def __init__(self, value=None, left=None, right=None):

self.value = value

self.left = left

self.right = right

# 自定义二叉树

class BinaryTree:

def __init__(self, value=None, left=None, right=None):

"""

根据传入的参数决定树的形态

:param value: 节点值

:param left: 左子树

:param right: 右子树

"""

self.root = Node(value, left, right) if value else None

def is_empty(self):

"""

判断是否为空树

:return:

"""

return True if self.root else False

def get_root(self):

"""

获取根节点

:return:

"""

return self.root

def get_left(self):

"""

获取左子树

:return:

"""

return self.root.left if self.root else None

def get_right(self):

"""

获取右子树

:return:

"""

return self.root.right if self.root else None

def set_left(self, node: Node):

"""

设置左子树

:param node: 树节点

:return:

"""

self.root.left = node

def set_right(self, node: Node):

"""

设置右子树

:param node: 树节点

:return:

"""

self.root.right = node

def pre_traverse(self, node: Node):

"""

前序遍历

:param node: 根节点

:return:

"""

if not node:

return

print(node.value, end=" ")

self.pre_traverse(node.left)

self.pre_traverse(node.right)

def mid_traverse(self, node: Node):

"""

中序遍历

:param node: 根节点

:return:

"""

if not node:

return

self.mid_traverse(node.left)

print(node.value, end=" ")

self.mid_traverse(node.right)

def after_traverse(self, node: Node):

"""

后序遍历

:param node: 根节点

:return:

"""

if not node:

return

self.after_traverse(node.left)

self.after_traverse(node.right)

print(node.value, end=" ")

def level_traverse(self, nodes: list):

next_nodes = []

if nodes:

for node in nodes:

print(node.value, end=" ")

if node.left:

next_nodes.append(node.left)

if node.right:

next_nodes.append(node.right)

self.level_traverse(next_nodes)

当然光有这些方法还是不够的,因为要一个个的创建节点还是很麻烦,我们可以将一个树节点定义成一个三元组:

(树节点的值,左子树,右子树)

而左子树和右子树也都可以用这种三元组来表示,例如下面是一颗二叉树的三元组表示:

(F, (C, A, (D, B, None)), (E, H, (G, M, None)))

9691b1afc11e93c0aa0a8a89e44e2e54.png

因此还需要实现一个将这种三元组表达形式转换成二叉树的方法:

1 def create(self, data: tuple):

"""

创建一个二叉树

:param data: 例如(1,(2,4,5),(3,6,7))

"""

self.root = self.parse(data)

def parse(self, data: tuple):

"""

解析传入的三元组,创建二叉树

:param data: 三元组

:return:

"""

if data:

node = Node(data[0])

node.left = self.parse(data[1]) if type(data[1]) == tuple else Node(data[1])

node.right = self.parse(data[2]) if type(data[2]) == tuple else Node(data[2])

return node

三、树的应用

1.表达式计算问题

1)问题描述

一个结构正确的二元表达式对应于一个满二叉树,例如下面这样一颗二叉树:

7f3b623d5624c78c7191a703193af909.png

这样一颗二叉树前序遍历得到“-+1*23/45”,后序遍历得到“123*+45/-”,正是波兰表达式的形式,而其中序遍历结果就是“1+2*3-4/5”,基本就是相应数学表达式的正确形式,只是缺少了表达计算顺序的括号。输入一个简单的只包含四则运算的数学计算表达式,求出其计算后的结果。

2)问题分析

对于任意一个二元表达式(如“a+b”)都可以用一个三元组来表示(如“('+', a, b)”),而像上面示例中的表达式,就可以用下面这种三元组表示:

("-", ("+", 1, ("*", 2, 3)), ("/", 4, 5))

这种三元表达式都包含一个操作符设为 op,两个操作数分别为 x 和 y,因而可以写出下面的计算方法:

1 if op == "+":

return x + y

if op == "-":

return x - y

if op == "*":

return x * y

if op == "/":

return x / y if y else 0

那么现在的问题就是如何将数学表达式转换成二叉树,再就根据二叉树得到三元组,最后就能使用上面的方法把表达式的值求出来了。因为我们都知道在没有括号的情况下,乘除的优先级是高于加减的,而利用二叉树求解表达式时会从下往上,从叶子节点往根节点进行计算,所以要把加减号放在上面,乘除号放在下面。

3)二叉树求解

下面是根据输入的表达式字符串建立二叉树的具体代码:

1 def build_tree(input_string):

"""

根据输入的表达式字符串建立二叉树

:param input_string: 输入表达式

:return:

"""

if "+" in input_string or "-" in input_string:

for i in range(len(input_string)):

if input_string[i] in ["+", "-"] and "+" not in input_string[i + 1:] and "-" not in input_string[i + 1:]:

node = Node(input_string[i], build_tree(input_string[:i]), build_tree(input_string[i + 1:]))

return node

elif "*" in input_string or "/" in input_string:

for i in range(len(input_string)):

if input_string[i] in ["*", "/"]:

node = Node(input_string[i], build_tree(input_string[:i]), build_tree(input_string[i + 1:]))

return node

else:

return Node(input_string)

在生成二叉树之后,还要根据这个二叉树得到三元组,下面就是使用递归算法得到三元组的代码:

1 def trans(self, node: Node, data: tuple):

"""

将二叉树转换成三元组

:param node: 节点

:param data: 三元组

:return:

"""

left = self.trans(node.left, data) if node.left.left else node.left.value

right = self.trans(node.right, data) if node.right.left else node.right.value

data = (node.value, left, right)

return data

现在已经能生成二叉树并得到表达式的三元组了,再就是求值了,下面是使用递归算法计算三元表达式的值的代码:

1 def solution(e):

"""

计算表达式的值

:param e: 转化成三元组表达的计算表达式

:return:

"""

if type(e) == tuple:

op, a, b = e[0], solution(e[1]), solution(e[2])

x, y = float(a), float(b)

if op == "+":

return x + y

if op == "-":

return x - y

if op == "*":

return x * y

if op == "/":

return x / y if y else 0

else:

return e

求解计算表达式的代码已经完成了,下面是使用这些代码来求"1+2*3-4/5"的代码示例:

1 s = build_tree("1+2*3-4/5")

tree = Tree()

tree.root = s

exp = tree.trans(s, ())

print(solution(exp))

# 6.2

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[重学数据结构之树和二叉树]http://www.zyiz.net/tech/detail-135672.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值