【数据结构】树与二叉树 基础要点+二叉树 Python 实现

来源:互联网 发布:安卓软件简单源码 编辑:程序博客网 时间:2024/06/09 16:33

这篇文章挺简单的,就是数据结构中树和二叉树的一些理论要点。因为怕自己遗忘的太快,所以写出来加深记忆。读我的blog的话,要是从头学的话不建议看了,当做复习大纲还ok。


1树的数据结构定义

D是具有相同特性的数据元素的集合。若D为空集,则称为空树。
若D仅含有一个元素,则R为空集,否则R={H},H是如下二元关系:
(1)D中存在唯一的root元素,在H关系下无前驱;
(2)若D除去root元素之外非空,则存在一个划分D1,D2,…,Dn,任意两个划分无交集,且唯一存在元素x,满足(root,x)属于H集合;
(3)对应于上述D1,D2,…,Dn的划分,存在唯一的划分H1,H2,…,Hn与之对应,且任意两个划分之间无交集,任何一个都是一个子树。

定义中强调了两点,(1)树种的关系有方向性,(2)树的D和H都有唯一划分,互无交集。

无序树即子树的各个元素没有顺序,不分 left 和right。

2二叉树的性质

如果二叉树的终端结点树为n,度为2的节点数为 n2,则 n=n2+1。(我认为这一条性质不太直观,除此之外的性质都还挺直观好理解的,尤其是完全有序二叉树)

3完全二叉树与满二叉树

满二叉树:二叉树每一层节点数都是最大的。
完全二叉树:其中的每一个节点序号都和满二叉树,也就是说只有最后一层的节点数无法达到最大。

4二叉树的存储结构

(1)顺序存储结构:只适合完全二叉树,节点较少时非常浪费空间。深度为k的二叉树,空间复杂度为 o(2**k);
(2)链式存储结构:二叉链表,每个节点有三个域,左子节点,右子节点,数据域,可以方便找到子节点,但是要找父节点则需要从根节点遍历,复杂度为o(n);
三叉链表,在二叉链表基础上添加父节点域,可以方便找到父节点,复杂度为o(1)。

5遍历二叉树

本质是将非线性的二叉树组织成规则的线性序列,然后进行线性化操作。
先序,中序,后序。
深度搜索,广度搜索。遍历的时间复杂度均为o(n),n为节点数量。
空间复杂度为o(m),m是遍历辅助栈,即树的深度。最坏情况下,树深度等于节点总数,树演变成链表,空间复杂度为o(n)。当存储结构为三叉链表时,不需要栈,空间复杂度为0。

6、线索二叉树

目的是在遍历时能够直接找到前驱和后继,而非仅仅是左右子节点的信息。

规定一个节点有5个域,数据域,左子节点,右子节点,左标志域,右标志域。当tag域为0时,子节点域指示指针,当tag域为1时,子节点域指示线索。这样方便寻找前驱和后继。
在此种线索链表中,中序的情况要比后续稍微简单一些,不需要设栈。而后续遍历则必须采用三叉链表。

线索化的实质是将空指针改为指向前驱或者后继的线索。

线索化后,在线索链表的头部添加头结点指向根节点,构成双向线索链表。

7、树与森林的存储结构

(1)双亲表示法:找父节点很容易,找孩子节点需要遍历,数组结构存储。
(2)孩子表示法:与(1)相反,由于有多个指针域,如果同构,则浪费存储空间,不同构则操作不方便。
(3)孩子兄弟表示法:将树以二叉树的形式进行存储。左子节点为孩子,右子节点为兄弟。按照分类进行的表示,展示了树和二叉树之间的转换关系。

8、树与森林的遍历

先序遍历,中序遍历。将树改为二叉树,然后采用二叉树的遍历完成数的遍历。

9、Huffman树,带权路径最优树

霍夫曼树是信息论中的一个概念,用于编码理论。叶子节点有权值,其余非叶子节点没有,权值越小,层次越深。构造huffman树的方法。

10、回溯法与树的遍历

八皇后算法,骑士游历,迷宫,选最优解,jump game中处理0元素(我的另一篇blog里面涉及这个问题,但是我没有处理掉这个问题jump game 的python代码),以后有时间把这几个问题全部解决掉。

11、树的计数

具有n个节点的不同形态的树共有多少颗,这是一个数学问题。结果不方便打出来,就算了吧。结果不重要,推导的思路才重要。

首先考虑二叉树的情况。root节点的左右子树的子节点数量为 i 和 n-i-1,然后递归就好了。

给定前序遍历和中序遍历,可以唯一确定一颗树。

我自己写了一个最简单版本的二叉树数据结构的实现,还不是平衡的。这个数据结构中还有漏洞:广度优先我没实现了,树深度还没算出来写上去,等随后有时间实现一下吧。

class Node(object):    '''    二叉树的链式表示,但不是线索二叉树,线索二叉树还要加上结点的前驱和后继    '''    def __init__(self, name=-1, left=0, right=0, value=None):        self.value = value  # 树结点的值        self.left = left        self.right = right        self.name = name  # 用于标记树中的结点,唯一,不可重复,必须有才行class BinaryTree(object):    def __init__(self):        self.root = 0    def init_bin_tree(self, data):        '''        data 是 BinaryTree 的一个实例,并且制定将这个实例放在根节点下        '''        self.root = data    def is_empty(self):  # 判断树是否为空,如果根节点指针都没有指向它,说明树为空        if self.root == 0:            return True        else:            return False    def clear_binary_tree(self):        self.root = 0    def add_node(self, name, rorl, value=value):        """为树添加节点,给某个结点name添加子节点,rorl确定是左还是右"""        node = Node(name=name, value=value)        parent_node = self.get_node(name, self.root)        if rorl == 'r' and parent_node.right == 0:            parent_node.right = node        elif rorl == 'l' and parent_node.left == 0:            parent_node.left = node        else:            print "Wrong rorl parameter or the r or l child node has already existed."    def replace_node(self, name, rorl, value=value):        """为树替换某个节点,给某个结点name添加子节点,rorl确定是左还是右"""        node = Node(name=name, value=value)        parent_node = self.get_node(name, self.root)        if rorl == 'r' and parent_node.right != 0:            parent_node.right = node        elif rorl == 'l' and parent_node.left != 0:            parent_node.left = node        else:            print "Wrong rorl parameter or the r or l child node is empty."    def traverse_parent_first(self, node):  # 先序遍历,node 一定要给到 self.node        if node == 0:            return        print "Node(" + node.name + ")"        self.traverse_parent_first(node.left)        self.traverse_parent_first(node.right)    def traverse_parent_middle(self, node):  # 中序遍历,node 给到根节点        if node == 0:            return        self.traverse_parent_first(node.left)        print "Node(" + node.name + ")"        self.traverse_parent_first(node.right)    def traverse_parent_last(self, node=self.root):  # 中序遍历,node 给到根节点        if node == 0:            return        self.traverse_parent_last(node.left)        self.traverse_parent_last(node.right)        print "Node(" + node.name + ")"    def traverse_deep_first(self, node):  # 深度优先遍历        if node == 0:            return        print "Node(" + node.name + ")"        if node.left != 0:            self.traverse_deep_first(node.left)        if node.right != 0:            self.traverse_deep_first(node.right)    def get_root(self):        if self.is_empty():            print "The binary tree is empty."            return        else:            return self.root    def get_value(self, name):        node = self.get_node(name, self.root)        if node:            return node.value    def get_node(self, name, node):  # 获取 name 结点,node必须是根节点        if node == 0:            return        if node.name == name:            return node        if name.left != 0:            return self.get_node(name, node.left)        if name.right != 0:            return self.get_node(name, node.right)    def traverse_broad_first(self, node):  # 广度优先遍历,还没想好        pass