zoukankan      html  css  js  c++  java
  • 数据结构之二叉树

    二叉树是一种简单的树形结构,其每个节点的分支节点数有0,1或2个。如下图T1,T2和T3是三棵二叉树。显然二叉树是一种递归的结构。

    不包含任何节点的二叉树为空树,只有一个节点的二叉树称为单点树,一个节点的子节点的个数称为该节点的。如果每个分支节点的度都为2,则称之为满二叉树。T4,T5就是两棵满二叉树。

    如果一棵二叉树,除最后一层外,其它层的节点都是满的,而最后一层节点在最左边连续排列,空位都在右边,这样的二叉树叫做完全二叉树,如T6、T7所示。

    想要遍历一棵二叉树,有两种不同的策略:深度优先遍历和宽度优先遍历。

    其中深度优先遍历策略有三种不同的方式:

    先根序遍历:按根节点、左子树、右子树的顺序遍历。

    中根序遍历:按左子树、根节点、右子树的顺序遍历。

    后根序遍历:按左子树、右子树、根节点的顺序遍历。

    代码:

    用python实现树的构造和几种遍历算法,虽然不难,不过还是把代码作了一下整理总结。实现功能:

    • 树的构造
    • 递归实现先序遍历、中序遍历、后序遍历
    • 堆栈实现先序遍历、中序遍历、后序遍历
    • 队列实现层次遍历
    #coding=utf-8
    
    class Node(object):
        """节点类"""
        def __init__(self, elem=-1, lchild=None, rchild=None):
            self.elem = elem
            self.lchild = lchild
            self.rchild = rchild
    
    
    class Tree(object):
        """树类"""
        def __init__(self):
            self.root = Node()
            self.myQueue = []
    
        def add(self, elem):
            """为树添加节点"""
            node = Node(elem)
            if self.root.elem == -1:  # 如果树是空的,则对根节点赋值
                self.root = node
                self.myQueue.append(self.root)  
    else: treeNode = self.myQueue[0] # 此结点的子树还没有齐。 if treeNode.lchild == None: treeNode.lchild = node self.myQueue.append(treeNode.lchild) else: treeNode.rchild = node self.myQueue.append(treeNode.rchild) self.myQueue.pop(0) # 如果该结点存在右子树,将此结点丢弃。
    # x.pop()默认弹出最后一个元素;x.pop(num)为弹出索引为num的元素
    def front_digui(self, root): """利用递归实现树的先序遍历""" if root == None: return print root.elem, self.front_digui(root.lchild) self.front_digui(root.rchild) def middle_digui(self, root): """利用递归实现树的中序遍历""" if root == None: return self.middle_digui(root.lchild) print root.elem, self.middle_digui(root.rchild) def later_digui(self, root): """利用递归实现树的后序遍历""" if root == None: return self.later_digui(root.lchild) self.later_digui(root.rchild) print root.elem, def front_stack(self, root): """利用堆栈实现树的先序遍历""" if root == None: return myStack = [] node = root while node or myStack: while node: #从根节点开始,一直找它的左子树 print node.elem, myStack.append(node) node = node.lchild node = myStack.pop() #while结束表示当前节点node为空,即前一个节点没有左子树了 node = node.rchild #开始查看它的右子树 def middle_stack(self, root): """利用堆栈实现树的中序遍历""" if root == None: return myStack = [] node = root while node or myStack: while node: #从根节点开始,一直找它的左子树 myStack.append(node) node = node.lchild node = myStack.pop() #while结束表示当前节点node为空,即前一个节点没有左子树了 print node.elem, node = node.rchild #开始查看它的右子树 def later_stack(self, root): """利用堆栈实现树的后序遍历""" if root == None: return myStack1 = [] myStack2 = [] node = root myStack1.append(node) while myStack1: #这个while循环的功能是找出后序遍历的逆序,存在myStack2里面 node = myStack1.pop() if node.lchild: myStack1.append(node.lchild) if node.rchild: myStack1.append(node.rchild) myStack2.append(node) while myStack2: #将myStack2中的元素出栈,即为后序遍历次序 print myStack2.pop().elem, def level_queue(self, root): """利用队列实现树的层次遍历""" if root == None: return myQueue = [] node = root myQueue.append(node) while myQueue: node = myQueue.pop(0) print node.elem, if node.lchild != None: myQueue.append(node.lchild) if node.rchild != None: myQueue.append(node.rchild) if __name__ == '__main__': """主函数""" elems = range(10) #生成十个数据作为树节点 tree = Tree() #新建一个树对象 for elem in elems: tree.add(elem) #逐个添加树的节点 print '队列实现层次遍历:' tree.level_queue(tree.root) print ' 递归实现先序遍历:' tree.front_digui(tree.root) print ' 递归实现中序遍历:' tree.middle_digui(tree.root) print ' 递归实现后序遍历:' tree.later_digui(tree.root) print ' 堆栈实现先序遍历:' tree.front_stack(tree.root) print ' 堆栈实现中序遍历:' tree.middle_stack(tree.root) print ' 堆栈实现后序遍历:' tree.later_stack(tree.root)
    总结:
    树的遍历主要有两种,一种是深度优先遍历,像前序、中序、后序;另一种是广度优先遍历,像层次遍历。在树结构中两者的区别还不是非常明显,但从树扩展到有向图,到无向图的时候,深度优先搜索和广度优先搜索的效率和作用还是有很大不同的。
    深度优先一般用递归,广度优先一般用队列。一般情况下能用递归实现的算法大部分也能用堆栈来实现。
     
    一般用队列来构造树,毕竟树是类似广度优先的;如果非要用递归(类似深度优先)来构造的话,最好在终止条件里设置树深,否则构造的树会偏向左单子树或者右单子树。
  • 相关阅读:
    飞思卡尔IMX6处理器的GPIO配置方式
    批处理清除VisualStudio解决方案文件夹
    总结过去10年的程序员生涯,给程序员小弟弟小妹妹们的一些总结性忠告
    详解Linux2.6内核中基于platform机制的驱动模型 (经典)
    [驱动注册]platform_driver_register()与platform_device_register()
    机器人系统常用仿真软件介绍效果与评价指标
    WINCE的批处理
    项目开发中的人月及如何计算
    常用的六个富文本编辑器
    如何获取公众号里面的歌曲
  • 原文地址:https://www.cnblogs.com/nicetoseeyou/p/10439411.html
Copyright © 2011-2022 走看看