算法 | 二叉树的构建与遍历

0.简介

对于二叉树的遍历,有四种方式:层序输出,前序输出,中序输出,后序输出。但不论利用何种输出方式对二叉树进行遍历,其前提为必须提前已知一颗树。那么什么叫做已知一颗树呢?
所谓已知一棵树的意思即为:已经用数据结构定义好的树,通过该树可以知道哪个节点是根;哪个节点是左儿子,右儿子;哪个节点是左儿子的左右儿子等等这样的信息。在本文中,我们把得到这个已知树的过程称之为创建一颗树。

1.四种遍历方式示意图

2.如何构建一颗已知二叉树

利用层序输入的策略构建二叉树相对比较方便。当然也可以通过其他手段构建二叉树,但相对会比较麻烦,该种策略是最容易理解的。后续的实例中会介绍另外一种构建策略。


"""
#定义好节点类
#默认节点为空,利用重写构造函数的策略,使得每次定义一个节点,
#对应节点都包含了元素,左右儿子。
"""
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, root=None):
        self.root = root
        self.MyQueue = []
    #把一个节点添加到树中的策略(层序)
    def add(self,elem):
        #定义一个带有给定元素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)
if __name__ == '__main__':
    tree = Tree()
    tree.add(A)
    tree.add(B)
    tree.add(C)
    tree.add(D)
    tree.add(E)        
    tree.add(F)
    tree.add(G)  
3.根据已知二叉树遍历输出

层序输出:利用队列进行层序输出

def level(self):
	if self.root == None:
		return
	MyQueue = []
	node =self.root
	MyQueue.append(node)
	while MyQueue:
		node = MyQueue.pop(0)
		print node.elem
		if node.lchild:
			MyQueue.append(node.lchild)
		if node.rchild:
			MyQueue.append(node.rchild)

前序输出:根据父节点–左节点–右节点的顺序输出(利用递归)
中序输出:根据左节点–父节点–右节点的顺序输出(利用递归)
后序输出:根据左节点–右节点–父节点的顺序输出(利用递归)

def front(self):
	if self.root == None:
		return
	print self.root.elem
	self.front(self.root.lchild)
	self.front(self.root.rchild)
	
	
def middle(self):
	if self.root == None:
		return
	self.front(self.middle.lchild)
	print self.root.elem
	self.front(self.middle.rchild)
	
def post(self):
	if self.root == None:
		return
	self.front(self.middle.lchild)
	self.front(self.middle.rchild)
	print self.root.elem
4.创建二叉树并遍历输出实例

比如我们在笔试的过程中会遇到的题目:已知一颗树的前序遍历和中序遍历,输出二叉树的层序遍历。该类题目的策略就是通过树的前序遍历和中序遍历来创建一颗已知树,并通过创建得到的树进行层序的遍历输出。
解题思路:利用递归的手段通过前序和中序的结果来构建已知树。并利用广度优先的手段遍历输出(就是层序遍历)。之所以可以利用递归,因为当根据前序遍历结果可知,第一位是整颗树的根节点,而根据中序遍历中找到当前这个第一位的index,在中序遍历序列中该index之前和之后的两段被切分成了两颗子树,并且根据这两颗子树的长度可以从前序的列表中切除这两颗子树的前序遍历列表,因此我们发现对于每一个节点的操作一致,且最终的终止条件为最原始的前序为空时递归结束。

import sys

class Node:
    def __init__(self, val):
        self.val = val
        self.left, self.right = None, None


def buildTree(preTree, inTree):
    if preTree:
        root = Node(preTree[0])
        index = inTree.index(preTree[0])

        root.left = buildTree(preTree[1:index + 1], inTree[:index])
        root.right = buildTree(preTree[index + 1:], inTree[index + 1:])
        return root
    else:
        return None


n = int(sys.stdin.readline())
preTree = sys.stdin.readline().split()
inTree = sys.stdin.readline().split()
root = buildTree(preTree, inTree)

queue = [root]
nextqueue = []

try:
    while queue:
        for Node in queue:
            print Node.val
            if Node.left:
                nextqueue.append(Node.left)
            if Node.right:
                nextqueue.append(Node.right)
        queue, nextqueue = nextqueue, []
except:
    pass
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yuanCruise

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值