最近复习一遍数据结构与算法,做一些笔记,大家可以一起复习。
一、树的一些容易混淆的定义:
结点层:根结点的层定义为1;根的孩子为第二层结点,依此类推;
树的深度(或高度):树中最大的结点层;
满二叉树:这个定义国内和国外有较大的区别:
国内教程定义:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。如图1:
图1
国外(国际)定义:a binary tree T is full if each node is either a leaf or possesses exactly two childnodes.
大意为:如果一棵二叉树的结点要么是叶子结点,要么它有两个子结点,这样的树就是满二叉树。(一棵满二叉树的每一个结点要么是叶子结点,要么它有两个子结点,但是反过来不成立,因为完全二叉树也满足这个要求,但不是满二叉树),如图2:
图2
满二叉树的任意节点,要么度为0,要么度为2.换个说法即要么为叶子结点,要么同时具有左右孩子。霍夫曼树是符合这种定义的,满足国际上定义的满二叉树,但是不满足国内的定义。
完全二叉树:若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
完美二叉树(可能国外才有):当所有的叶子节点都在同一层就是完美二叉树,毫无间隙填充了 h 层。对应国内满二叉树。
二、树数据结构python实现
我们将定义一个具有根值属性的类,以及左和右子树, 这个表示更接近于面向对象的编程范例。
属性:根、左右子树
方法:设置根、左右子树,获取根和左右子树
#定义二叉树类
class BinaryTree(object):
def __init__(self, root, left = None, right = None):
self.root = root
self.left = left
self.right = right
def getRoot(self):
return self.root
def setRoot(self, root):
self.root = root
def getLeft(self):
return self.left
def getRight(self):
return self.right
#向树中添加左子树
def insertLeft(self, newNode):
if self.left == None:
self.left = BinaryTree(newNode)
else: #左子树具有节点,放到下一层
t = BinaryTree(newNode)
t.left = self.left
self.left = t
#向树中添加右子树
def insertRight(self, newNode):
if self.right == None:
self.right = BinaryTree(newNode)
else:
t = BinaryTree(newNode)
t.right = self.right
self.right = t
三、二叉树的遍历
不知道你有没有发现,二叉树其实是一种递归结构,因为单独拿出来一个 subtree 子树出来,其实它还是一棵树。那遍历它就很方便啦,我们可以直接用递归的方式来遍历它。但是当处理顺序不同的时候,树又分为三种遍历方式:
- 先(根)序遍历: 先处理根,之后是左子树,然后是右子树
- 中(根)序遍历: 先处理左子树,之后是根,最后是右子树
- 后(根)序遍历: 先处理左子树,之后是右子树,最后是根
设置在类中的方法:
#遍历树
def preorder(self):
print(self.root)
if self.left:
self.left.preorder()
if self.right:
self.right.preorder()
外部函数的方法:
#前序遍历树的外部函数
def preorder(tree):
if tree:
print(tree.getRoot())
preorder(tree.getLeft())
preorder(tree.getRight())
#后序遍历树的外部函数
def postorder(tree):
if tree:
postorder(tree.getLeft())
postorder(tree.getRight())
print(tree.getRoot())
#中序遍历树的外部函数
def midorder(tree):
if tree:
midorder(tree.getLeft())
print(tree.getRoot())
midorder(tree.getRight())
以上哪种方式实现前序最好? 答案是在这种情况下,实现前序作为外部函数可能更好。原因是你很少只是想遍历树。在大多数情况下,将要使用其中一个基本的遍历模式来完成其他任务。 事实上,我们将在下面的例子中看到后序遍历模式与我们前面编写的用于计算分析树的代码非常接近。 因此,我们用外部函数实现其余的遍历。
github代码:https://github.com/makang101/python-data-structure
参考:
problem-solving-with-algorithms-and-data-structure-using-python 中文版
数据结构(C语言版)严蔚敏