表达式树和查找树的 Python 实现


目录

  1. 二叉表达式树
  2. 二叉查找树

二叉表达式树

表达式树是二叉树的一种应用,其树叶是常数或变量,而节点为操作符,构建表达式树的过程与后缀表达式的计算类似,只不过在遇到运算符时不是进行计算,而是将树节点赋值为运算符,并将节点的左右叶子指向两个变量构成一个基本的二叉树后再压入栈中

Expression Tree:
*
|___________
| |
+ *
|_____ |_____
| | | |
a b c +
|__
| |
d c

下面利用代码实现一棵二叉表达式树

完整代码

 from binary_tree import BinaryTree, TreeNode
from stack.linked_list_stack import Stack class ExpressionTree(BinaryTree):
SIGN = {'+': 1, '-': 1, '*': 2, '/': 2, '(': 3} def gene_tree_by_postfix(self, expr):
s = Stack()
for i in expr:
if i in self.SIGN.keys():
right = s.pop()
left = s.pop()
node = TreeNode(i, left, right)
s.push(node)
else:
s.push(TreeNode(i))
self._root = s.pop() def test_expression_tree(ep):
t = ExpressionTree()
t.gene_tree_by_postfix(ep)
print('\n------Pre-traversal-------')
print(t) print('\n------Post-traversal------')
t.show(t.post_traversal())
print('\n-------In-traversal-------')
t.show(t.in_traversal()) if __name__ == '__main__':
ep = 'a b + c d e + * *'
'''
*
|___________
| |
+ *
|_____ |_____
| | | |
a b c +
|__
| |
d c
'''
test_expression_tree(ep.split(' '))

分段解释

首先导入二叉树类、树节点类和

 from binary_tree import BinaryTree, TreeNode
from stack.linked_list_stack import Stack

接着构建一个表达式树类,基于二叉树进行派生,依照构建表达式树的思路定义一个生成树的方法

 class ExpressionTree(BinaryTree):
SIGN = {'+': 1, '-': 1, '*': 2, '/': 2, '(': 3} def gene_tree_by_postfix(self, expr):
s = Stack()
for i in expr:
if i in self.SIGN.keys():
right = s.pop()
left = s.pop()
node = TreeNode(i, left, right)
s.push(node)
else:
s.push(TreeNode(i))
self._root = s.pop()

再定义一个测试函数,以三种遍历方式遍历显示表达式树

 def test_expression_tree(ep):
t = ExpressionTree()
t.gene_tree_by_postfix(ep)
print('\n------Pre-traversal-------')
print(t) print('\n------Post-traversal------')
t.show(t.post_traversal())
print('\n-------In-traversal-------')
t.show(t.in_traversal())

最后输入一个后缀表达式,进行测试

 if __name__ == '__main__':
ep = 'a b + c d e + * *'
'''
*
|___________
| |
+ *
|_____ |_____
| | | |
a b c +
|__
| |
d c
'''
test_expression_tree(ep.split(' '))

显示结果为

------Pre-traversal-------
*
+
a
b
*
c
+
d
e ------Post-traversal------
a
b
+
c
d
e
+
*
* -------In-traversal-------
a
+
b
*
c
*
d
+
e

2 二叉查找树

查找树是二叉树的另一个应用,其特点在于二叉树节点的值大于左子树节点值,小于右子树节点值,这在查找的时候提供了极大的便利。

Search Tree:
5
|_____
| |
2 7
|__ |__
| | | |
1 3 6 9

二叉树的主要方法及操作思路主要如下:

查找操作:递归查找,若当前值小于查找值则递归查找左子树,大于则右子树,直到查找到目标值或None

插入操作:递归插入,类似于查找,当查找到相同元素时便放弃插入,否则插入到最后查找的位置

删除操作:递归删除,主要有以下3种情况,

    1. 当删除点为叶子时,直接惰性删除,
    2. 当删除点包含一个叶子时,将节点替换成该叶子
    3. 当删除点包含两个叶子或子树时,在删除节点的右子树中查找最小叶子,替换当前节点进行删除

下面用代码实现一棵查找二叉树,

完整代码

 from binary_tree import TreeNode, BinaryTree

 class SearchTree(BinaryTree):
"""
Search Tree:
5
|_____
| |
2 7
|__ |__
| | | |
1 3 6 9
"""
def find(self, item):
if self._root is None:
return None def _find(item, node):
if not node:
return node
if item < node.value:
return _find(item, node.left)
elif item > node.value:
return _find(item, node.right)
else:
return node
return _find(item, self._root) def find_min(self, node=None):
if self._root is None:
return None
if not node:
node = self._root
if node.left:
return self.find_min(node.left)
return node def find_max(self, node=None):
if self._root is None:
return None
if not node:
node = self._root
if node.right:
return self.find_max(node.right)
return node def find_previous(self, item):
if self._root is None:
return None def _find(item, node):
if not node.left and not node.right:
return None
if item < node.value:
if item == node.left.value:
return node
return _find(item, node.left)
elif item > node.value:
if item == node.right.value:
return node
return _find(item, node.right)
return _find(item, self._root) def insert(self, item):
if self._root is None:
self._root = TreeNode(item)
return def _insert(item, node):
if not node:
return TreeNode(item)
if item < node.value:
node.left = _insert(item, node.left)
elif item > node.value:
node.right = _insert(item, node.right)
else: pass
return node
self._root = _insert(item, self._root) def delete(self, item):
if self._root is None:
return def _delete(item, node):
if not node: # Node no found
# return None
raise Exception('Element not in tree.')
if item < node.value:
node.left = _delete(item, node.left)
elif item > node.value:
node.right = _delete(item, node.right)
else: # Node found
if node.left and node.right:
# Minimum node in right sub-tree has no left sub-node, can be used to make replacement
# Find minimum node in right sub-tree
min_node = self.find_min(node.right)
# Replace current node with min_node
node.value = min_node.value
# Delete min_node in right sub-tree
node.right = _delete(min_node.value, node.right)
else:
if node.left:
node = node.left
elif node.right:
node = node.right
else:
node = None
return node
self._root = _delete(item, self._root) def test(t):
print('\nInit Search tree:')
for i in [6, 2, 8, 1, 4, 3, 1]:
t.insert(i)
t.show()
print('\nFind min value:')
print(t.find_min())
print('\nFind max value:')
print(t.find_max())
print('\nFind certain value:')
print(t.find(3))
print('\nFind certain value (not exist):')
print(t.find(7))
print('\nFind previous value of certain value:')
print(t.find_previous(3))
print('\nFind previous value of certain value (not exist):')
print(t.find(7))
print('\nDelete certain value (with one sub-node):')
t.delete(4)
t.show()
print('\nMake tree empty:')
t.make_empty()
t.show()
print('\nInit Search tree:')
for i in [6, 2, 8, 1, 5, 3, 4]:
t.insert(i)
t.show()
print('\nDelete certain value (with two sub-node):')
t.delete(2)
t.show()
print('\nDelete certain value (not exist):')
try:
t.delete(7)
except Exception as e:
print(e) if __name__ == '__main__':
test(SearchTree())

分段解释
首先导入二叉树类、树节点类,并定义查找二叉树

 from binary_tree import TreeNode, BinaryTree

 class SearchTree(BinaryTree):
"""
Search Tree:
5
|_____
| |
2 7
|__ |__
| | | |
1 3 6 9
"""

定义find方法,用于查找元素,以及find_min和find_max方法,用于查找最值,find_previous可以查找到节点的父节点

     def find(self, item):
if self._root is None:
return None def _find(item, node):
if not node:
return node
if item < node.value:
return _find(item, node.left)
elif item > node.value:
return _find(item, node.right)
else:
return node
return _find(item, self._root) def find_min(self, node=None):
if self._root is None:
return None
if not node:
node = self._root
if node.left:
return self.find_min(node.left)
return node def find_max(self, node=None):
if self._root is None:
return None
if not node:
node = self._root
if node.right:
return self.find_max(node.right)
return node def find_previous(self, item):
if self._root is None:
return None def _find(item, node):
if not node.left and not node.right:
return None
if item < node.value:
if item == node.left.value:
return node
return _find(item, node.left)
elif item > node.value:
if item == node.right.value:
return node
return _find(item, node.right)
return _find(item, self._root)

定义insert方法,用于插入元素,定义delete方法,用于删除元素,遵循前面的删除方法。

     def insert(self, item):
if self._root is None:
self._root = TreeNode(item)
return def _insert(item, node):
if not node:
return TreeNode(item)
if item < node.value:
node.left = _insert(item, node.left)
elif item > node.value:
node.right = _insert(item, node.right)
else: pass
return node
self._root = _insert(item, self._root) def delete(self, item):
if self._root is None:
return def _delete(item, node):
if not node: # Node no found
# return None
raise Exception('Element not in tree.')
if item < node.value:
node.left = _delete(item, node.left)
elif item > node.value:
node.right = _delete(item, node.right)
else: # Node found
if node.left and node.right:
# Minimum node in right sub-tree has no left sub-node, can be used to make replacement
# Find minimum node in right sub-tree
min_node = self.find_min(node.right)
# Replace current node with min_node
node.value = min_node.value
# Delete min_node in right sub-tree
node.right = _delete(min_node.value, node.right)
else:
if node.left:
node = node.left
elif node.right:
node = node.right
else:
node = None
return node
self._root = _delete(item, self._root)

最后运行测试函数对查找二叉树进行测试,

初始化一棵树

 def test(t):
print('\nInit Search tree:')
for i in [6, 2, 8, 1, 4, 3, 1]:
t.insert(i)
t.show()

当前树状态为

Init Search tree:
6 | 6
2 | __|__
1 | | |
4 | 2 8
3 | __|__
8 | | |
| 1 4
| __|
| |
| 3

几种查找元素的基本方法

     print('\nFind min value:')
print(t.find_min())
print('\nFind max value:')
print(t.find_max())
print('\nFind certain value:')
print(t.find(3))
print('\nFind certain value (not exist):')
print(t.find(7))
print('\nFind previous value of certain value:')
print(t.find_previous(3))
print('\nFind previous value of certain value (not exist):')
print(t.find(7))

得到结果

Find min value:
1 Find max value:
8 Find certain value:
3 Find certain value (not exist):
None Find previous value of certain value:
4 Find previous value of certain value (not exist):
None

删除带有一个子节点的元素,惰性删除

     print('\nDelete certain value (with one sub-node):')
t.delete(4)
t.show()

得到结果

Delete certain value (with one sub-node):
6 | 6
2 | __|__
1 | | |
3 | 2 8
8 | __|
| | | |
| 1 | 4
| |
| |
| 3

接着清空树,并重新初始化一棵树

     print('\nMake tree empty:')
t.make_empty()
t.show()
print('\nInit Search tree:')
for i in [6, 2, 8, 1, 5, 3, 4]:
t.insert(i)
t.show()

得到结果

Make tree empty:
None Init Search tree:
6 | 6
2 | __|__
1 | | |
5 | 2 8
3 | __|__
4 | | |
8 | 1 5
| __|
| |
| 3
| |__
| |
| 4

接着删除具有两个子节点的元素2

     print('\nDelete certain value (with two sub-node):')
t.delete(2)
t.show()

得到结果

Delete certain value (with two sub-node):
6 | 6
3 | __|__
1 | | |
5 | 3 8
4 | __|__
8 | | |
| 1 5
| __|
| |
| 4

最后,尝试删除一个不存在的元素,则会引起报错

     print('\nDelete certain value (not exist):')
try:
t.delete(7)
except Exception as e:
print(e)

得到结果

Delete certain value (not exist):
Element not in tree.

相关阅读


1. 二叉树

2.

3. 后缀表达式的计算

Python与数据结构[3] -> 树/Tree[1] -> 表达式树和查找树的 Python 实现的更多相关文章

  1. 浅谈算法和数据结构: 七 二叉查找树 八 平衡查找树之2-3树 九 平衡查找树之红黑树 十 平衡查找树之B树

    http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html 前文介绍了符号表的两种实现,无序链表和有序数组,无序链表在插入的 ...

  2. 数据结构和算法学习笔记十五:多路查找树(B树)

    一.概念 1.多路查找树(multi-way search tree):所谓多路,即是指每个节点中存储的数据可以是多个,每个节点的子节点数也可以多于两个.使用多路查找树的意义在于有效降低树的深度,从而 ...

  3. Python与数据结构[1] -> 栈/Stack[0] -> 链表栈与数组栈的 Python 实现

    栈 / Stack 目录 链表栈 数组栈 栈是一种基本的线性数据结构(先入后出FILO),在 C 语言中有链表和数组两种实现方式,下面用 Python 对这两种栈进行实现. 1 链表栈 链表栈是以单链 ...

  4. (python数据分析)第03章 Python的数据结构、函数和文件

    本章讨论Python的内置功能,这些功能本书会用到很多.虽然扩展库,比如pandas和Numpy,使处理大数据集很方便,但它们是和Python的内置数据处理工具一同使用的. 我们会从Python最基础 ...

  5. 浅谈算法和数据结构: 十 平衡查找树之B树

    前面讲解了平衡查找树中的2-3树以及其实现红黑树.2-3树种,一个节点最多有2个key,而红黑树则使用染色的方式来标识这两个key. 维基百科对B树的定义为“在计算机科学中,B树(B-tree)是一种 ...

  6. 转 浅谈算法和数据结构: 十 平衡查找树之B树

    前面讲解了平衡查找树中的2-3树以及其实现红黑树.2-3树种,一个节点最多有2个key,而红黑树则使用染色的方式来标识这两个key. 维基百科对B树的定义为"在计算机科学中,B树(B-tre ...

  7. Python -- 堆数据结构 heapq - I love this game! - 博客频道 - CSDN.NET

    Python -- 堆数据结构 heapq - I love this game! - 博客频道 - CSDN.NET Python -- 堆数据结构 heapq 分类: Python 2012-09 ...

  8. 数据结构---平衡查找树之B树和B+树(转)

    本文转载自:http://www.cnblogs.com/yangecnu/p/Introduce-B-Tree-and-B-Plus-Tree.html 前面讲解了平衡查找树中的2-3树以及其实现红 ...

  9. 七大查找算法(Python)

    查找算法 -- 简介 查找(Searching)就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素.    查找表(Search Table):由同一类型的数据元素构成的集合    ...

随机推荐

  1. Codeforces Round #401 (Div. 1) C(set+树状数组)

    题意: 给出一个序列,给出一个k,要求给出一个划分方案,使得连续区间内不同的数不超过k个,问划分的最少区间个数,输出时将k=1~n的答案都输出 比赛的时候想的有点偏,然后写了个nlog^2n的做法,T ...

  2. xinetd不太详的详解

    xinetd不太详的详解 http://blog.sina.com.cn/s/blog_88cdde9f01019fg5.html ################################## ...

  3. thymeleaf 布局layout

    以前写过一篇使用thymeleaf实现div中加载html 大部分内容都没问题,只是部分知识已经过时了. 重新记录: 依赖依然是 <dependency> <groupId>n ...

  4. [洛谷P3203][HNOI2010]弹飞绵羊

    题目大意:有$n$个节点,第$i$个节点有一个弹力系数$k_i$,当到达第$i$个点时,会弹到第$i+k_i$个节点,若没有这个节点($i+k_i>n$)就会被弹飞.有两个操作: $x:$询问从 ...

  5. 洛谷 P3084 [USACO13OPEN]照片Photo 解题报告

    [USACO13OPEN]照片Photo 题目描述 农夫约翰决定给站在一条线上的\(N(1 \le N \le 200,000)\)头奶牛制作一张全家福照片,\(N\)头奶牛编号\(1\)到\(N\) ...

  6. React context基本用法

    React的context就是一个全局变量,可以从根组件跨级别在React的组件中传递.React context的API有两个版本,React16.x之前的是老版本的context,之后的是新版本的 ...

  7. 如何抓取开了gzip的网页

    有时候用 file_get_contents() 函数抓取网页会发生乱码现象.有两个原因会导致乱码,一个是编码问题,一个是目标页面开了Gzip. 编码问题好办,把抓取到的内容转下编码即可($conte ...

  8. __cdecl,__stdcall,__fastcall,__pascal,__thiscall 的区别

    关于函数的调用规则(调用约定),大多数时候是不需要了解的,但是如果需要跨语言的编程,比如VC写的dll要delphi调用,则需要了解. microsoft的vc默认的是__cdecl方式,而windo ...

  9. ext4文件系统由文件的inode号定位其inode Table

    在ubuntu中(以16.06为例),stat filename 可以查看文件的inode数值,但是如何确定该inode项具体在哪个块组下的inode Table中不是那么容易,接下来通过一步步计算来 ...

  10. Install the AWS Command Line Interface on Linux

    Install the AWS Command Line Interface on Linux You can install the AWS Command Line Interface and i ...