详谈二叉树2——python数据结构之二叉树的遍历、创建
发布日期:2021-05-07 08:52:16 浏览次数:26 分类:精选文章

本文共 17150 字,大约阅读时间需要 57 分钟。

二叉树的遍历、创建

存储结构详见

1. 遍历

\quad \quad 二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次且仅被访问一次。

\quad \quad 二叉树遍历操作的结果就是将非线性结构线性化。

2.遍历方法

树的两种重要遍历模式是

对于一棵二叉树:

  • 广度优先遍历,又称层序遍历,一般用队列实现

  • 深度优先遍历是沿着树的深度遍历树的结点,尽可能深的搜索树的分支。深度遍历主要有三种方式:前序遍历、中序遍历、后序遍历。深度优先一般用递归,一般情况下能用递归实现的算法大部分也能用堆栈实现。

二叉树的遍历方法主要有以下四种:

2.1 前序遍历

1.前序遍历:根结点–>左子树–>右子树

若二叉树为空,则空操作返回;否则:

  1. 访问根节点;
  2. 前序遍历根结点的左子树;
  3. 前序遍历根结点的右子树;

例子:在这里插入图片描述

前序遍历上图为:A B D G C E F

前序遍历——递归算法

def preorder(self,node):        """用递归实现先序遍历"""        if node is None:            return        print(node.data, end=" ")        self.preorder(node.left_child)        self.preorder(node.right_child)

前序遍历——非递归算法

伪代码:

1.栈s初始化,当前结点指针p初始化为根结点
2.循环直到当前结点指针p为空且栈为空

  • 2.1当p不为空时循环:

    • 2.1.1 访问p.data;
    • 2.1.2 将指针p的值保存到栈中——入栈
    • 2.1.3 继续遍历p的左子树,p指针移到左子树。
  • 2.2 如果栈s不为空,则

    • 2.2.1将栈顶元素弹出至p——出栈
    • 2.2.2准备遍历p的右子树,p指针移到右子树。

注:p用于结点偏历,初始时p=root

def preorederTravelsal(self, root):        """用进栈出栈的方式实现前序遍历"""        if root is None:            return None        stack = [root]        while stack:#当stack不为空时            node = stack.pop()#出栈            if node:                print(node.data, end=" ")                stack.append(node.right_child)#一边访问一边入栈                # 进栈,因栈后进先出,故入栈的顺序与前序遍历顺序相反                stack.append(node.left_child)

2.2 中序遍历

2.中序遍历:左子树–>根结点–>右子树

若二叉树为空,则空操作返回;否则:

  1. 中序遍历根结点的左子树;
  2. 访问根结点
  3. 中序遍历根结点的右子树;

在这里插入图片描述

中序遍历上图为D G B A E C F

中序遍历——递归算法

def inorder(self,node):        """用递归实现中序遍历"""        if node is None:            return        self.inorder(node.left_child)        print(node.data, end=" ")        self.inorder(node.right_child)

中序遍历——非递归算法

伪代码:
\quad \quad 在二叉树的中序遍历中,访问结点的操作发生在该结点的左子树遍历完毕并准备遍历右子树时,所以,在遍历过程中遇到某结点时并不能立即访问它,而是将它入栈,等到它的左子树遍历完毕以后,再从栈中弹出并访问之。中序遍历的非递归算法只需将前序遍历的非递归算法中的输出语句移到出栈以后。

def inorederTravelsal(self, root):        """用进栈出栈的方式实现中序遍历"""        if root is None:            return None        stack = []        tmp_node = root#tmp_node为移动指针,初始化为根结点        while tmp_node or stack:#当stack不为空时,            while tmp_node:                stack.append(tmp_node)                # 进栈,因栈后进先出,故入栈的顺序与中序遍历顺序相反                tmp_node=tmp_node.left_child            node=stack.pop()            print(node.data,end=" ")            tmp_node=node.right_child

2.3 后序遍历

3.后序遍历:左子树–>右子树–>根结点

若二叉树为空,则空操作返回;否则:

  1. 后序遍历根结点的左子树;
  2. 后序遍历根结点的右子树;
  3. 访问根结点

在这里插入图片描述

后序遍历上图为G D B E F C A
后序遍历——递归算法

def postorder(self,node):        """用递归实现后序遍历"""        if node is None:            return        self.postorder(node.left_child)        self.postorder(node.right_child)        print(node.data, end=" ")

后序遍历——非递归算法

伪代码:

在后序遍历过程中,结点要入两次栈,出两次栈:

1、第一次出栈:

只遍历完左子树,该结点不出栈,利用栈顶结点找到它的右子树,准备遍历它的右子树
2.第二次出栈:遍历完右子树,将该结点出栈,并访问它。

def postorderTravelsal(self,root):        """用进栈出栈的方式实现后序遍历"""        if root is None:            return None        stack=[]        tmp_node = root        while tmp_node or stack:            while tmp_node:                stack.append(tmp_node)                tmp_node = tmp_node.left_child            node=stack[-1]            tmp_node = node.right_child            if node.right_child is None:                node = stack.pop()                print(node.data,end=" ")                while stack and node == stack[-1].right_child:                    node=stack.pop()                    print(node.data,end=" ")

2.4层序遍历

4.层序遍历:

二叉树的层序遍历是指从二叉树的第一层(即根结点)开始,从上至下逐层遍历,则按从左到右的顺序对结点逐个访问。

在这里插入图片描述

层序遍历上图为A B C D E F G

层序遍历伪代码: 以队列的方式进行

如果根结点为空,则返回空,否则进行以下步骤:
1.队列Q初始化:根结点入队;
2.循环直至队列Q为空

  • 3.1 q=队列Q的队头元素出队;
  • 3.2 访问结点q的数据域;
  • 3.3若结点q存在左孩子,则将左孩子指针入队;
  • 3.4若结点q存在右孩子,则将右孩子指针入队;
def breadth_travel(self):# 层序遍历即广度优先遍历,用队列的方式实现        if self.root is None:            return        queue = [self.root]        while queue:            cur = queue.pop(0)            print(cur.data, end=" ")            if cur.left_child is not None:                queue.append(cur.left_child)            if cur.right_child is not None:                queue.append(cur.right_child)

二叉树遍历的性质:

  • 已知前序遍历序列和中序遍历序列,可以唯一确定一棵二叉树。
  • 已知后序遍历序列和中序遍历序列,可以唯一确定一棵二叉树。
  • 注意,已知前序和后序遍历,是不能确定一棵二叉树的。

3.树的创建

方法一

从左到右依次即层序遍历的方法手动添加树结点创建二叉树

class BTnode(object):  # 创建树结点    def __init__(self, data=-1, left_child=None, right_child=None):        self.data = data        self.left_child = left_child        self.right_child = right_childclass BiTree(object):  # 定义二叉树类,并给一个root根结点,一开始为空,随后添加结点    def __init__(self, root=None):        self.root = root    def add(self, data):  # 树的自定义添加结点操作,左右结点依次添加即按照层序遍历的方式添加        node = BTnode(data)  # 实例一个结点        if self.root is None:  # 如果树为空,即没有根结点            self.root = node  # 给树创建一个根结点            return  # 注意这个return # 遇到return推出函数        queue = [self.root]  # 这一步表示,已经有了根结点,将它取出放到队列里        while queue:  # 遍历队列,队列不为空时,执行以下序列            cur = queue.pop(0)  # 弹出队列的第一个元素(结点),pop默认pop(-1)            if cur.left_child is None:  # 如果结点左侧没有子结点                cur.left_child = node                return  # 遇到return推出函数            else:  # 如果左侧存在子结点                queue.append(cur.left_child)  # 将左侧的子结点添加到队列中            if cur.right_child is None:  # 如果结点右侧没有子结点                cur.right_child = node                return            else:                queue.append(cur.right_child)

方法二

如何用一种遍历序列生成二叉树?

为了建立一棵二叉树,将二叉树中每个结点的空值针引出一个虚结点,其值为一特定值如‘#’,以标识其为空,把这样处理后的二叉树称为原二叉树的扩展二叉树。

在这里插入图片描述

可以用前序遍历的方法建立二叉树,其原理也是用了递归的原理
设二叉树的结点均为一个字符。假设扩展二叉树的前序遍历序列由键盘输入,root为指向根结点的指针,二叉链表的建立过程是:

首先输入根结点,若输入的是#字符,则表明该二叉树为空树,即root=null;否则输入的字符应该赋给root->data,之后依次递归建立它的左子树与右子树。

class BTnode(object):# 创建树结点    def __init__(self, data=None, left_child=None, right_child=None):        self.data = data        self.left_child = left_child        self.right_child = right_childclass BiTree(object):#创建树类    def __init__(self, data_list):#data_list为想要创建二叉树的扩展二叉树的前序遍历序列        #初始化即将传入的列表的迭代器        self.it = iter(data_list)#对一个对象调用iter()可以得到他的迭代器。    def createBiTree(self, bt=None):#用前序遍历的方法创建二叉树        try:            #步进获取下一个元素            next_data = next(self.it)#next方法:返回迭代器的下一个元素            #如果当前列表元素为'#', 则认为其为 None            if next_data is "#":                bt = None            else:                bt = BTnode(next_data)                bt.left_child = self.createBiTree(bt.left_child)                bt.right_child = self.createBiTree(bt.right_child)        except Exception as e:            print(e)        return bt

例子:创建上图中的二叉树,并将遍历结果输出。

class BTnode(object):# 创建树结点    def __init__(self, data=None, left_child=None, right_child=None):        self.data = data        self.left_child = left_child        self.right_child = right_childclass BiTree(object):#创建树类    def __init__(self, data_list):#data_list为想要创建二叉树的扩展二叉树的前序遍历序列        #初始化即将传入的列表的迭代器        self.it = iter(data_list)#对一个对象调用iter()可以得到他的迭代器。    def createBiTree(self, bt=None):#用前序遍历的方法创建二叉树        try:            #步进获取下一个元素            next_data = next(self.it)#next方法:返回迭代器的下一个元素            #如果当前列表元素为'#', 则认为其为 None            if next_data is "#":                bt = None            else:                bt = BTnode(next_data)                bt.left_child = self.createBiTree(bt.left_child)                bt.right_child = self.createBiTree(bt.right_child)        except Exception as e:            print(e)        return bt    """递归实现三种遍历"""    def preorder(self, node):        """用递归实现先序遍历"""        if node is None:            return        print(node.data, end=" ")        self.preorder(node.left_child)        self.preorder(node.right_child)    def inorder(self, node):        """用递归实现中序遍历"""        if node is None:            return        self.inorder(node.left_child)        print(node.data, end=" ")        self.inorder(node.right_child)    def postorder(self, node):        """用递归实现后序遍历"""        if node is None:            return        self.postorder(node.left_child)        self.postorder(node.right_child)        print(node.data, end=" ")    #综合打印    def printTrave(self, bt):        print("先序遍历: ", end="")        self.preorder(bt)        print('\n')        print("中序遍历: ", end="")        self.inorder(bt)        print('\n')        print("后序遍历: ", end="")        self.postorder(bt)        print('\n')#换行data = input("Please input the node value: ")data_list = list(data)btree = BiTree(data_list)root = btree.createBiTree()btree.printTrave(root)

执行上面语句后会出现

Please input the node value: AB#D##C##

输入扩展二叉树的前序遍历序列即可。

得到以下结果:

先序遍历: A B D C 中序遍历: B D A C 后序遍历: D B C A Process finished with exit code 0

完整代码一

添加结点的方式创建二叉树以及四种遍历

class BTnode(object):  # 创建树结点    def __init__(self, data=-1, left_child=None, right_child=None):        self.data = data        self.left_child = left_child        self.right_child = right_childclass BiTree(object):  # 定义二叉树类,并给一个root根结点,一开始为空,随后添加结点    def __init__(self, root=None):        self.root = root    def add(self, data):  # 树的自定义添加结点操作,左右结点依次添加即按照层序遍历的方式添加        node = BTnode(data)  # 实例一个结点        if self.root is None:  # 如果树为空,即没有根结点            self.root = node  # 给树创建一个根结点            return  # 注意这个return # 遇到return推出函数        queue = [self.root]  # 这一步表示,已经有了根结点,将它取出放到队列里        while queue:  # 遍历队列,队列不为空时,执行以下序列            cur = queue.pop(0)  # 弹出队列的第一个元素(结点),pop默认pop(-1)            if cur.left_child is None:  # 如果结点左侧没有子结点                cur.left_child = node                return  # 遇到return推出函数            else:  # 如果左侧存在子结点                queue.append(cur.left_child)  # 将左侧的子结点添加到队列中            if cur.right_child is None:  # 如果结点右侧没有子结点                cur.right_child = node                return            else:                queue.append(cur.right_child)    def breadth_travel(self):# 层序遍历即广度优先遍历,用队列的方式实现        if self.root is None:            return        queue = [self.root]        while queue:            cur = queue.pop(0)            print(cur.data, end=" ")            if cur.left_child is not None:                queue.append(cur.left_child)            if cur.right_child is not None:                queue.append(cur.right_child)    """递归实现三种遍历"""    def preorder(self,node):        """用递归实现先序遍历"""        if node is None:            return        print(node.data, end=" ")        self.preorder(node.left_child)        self.preorder(node.right_child)    def inorder(self,node):        """用递归实现中序遍历"""        if node is None:            return        self.inorder(node.left_child)        print(node.data, end=" ")        self.inorder(node.right_child)    def postorder(self,node):        """用递归实现后序遍历"""        if node is None:            return        self.postorder(node.left_child)        self.postorder(node.right_child)        print(node.data, end=" ")    """非递归,用栈的方式实现前、中、后序遍历"""    def preorederTravelsal(self, root):        """用进栈出栈的方式实现前序遍历"""        if root is None:            return None        stack = [root]        while stack:#当stack不为空时            node = stack.pop()#出栈            if node:                print(node.data, end=" ")                stack.append(node.right_child)                # 进栈,因栈后进先出,故入栈的顺序与前序遍历顺序相反                stack.append(node.left_child)    def inorederTravelsal(self, root):        """用进栈出栈的方式实现中序遍历"""        if root is None:            return None        stack = []        tmp_node = root        while tmp_node or stack:#当stack不为空时            while tmp_node:                stack.append(tmp_node)                # 进栈,因栈后进先出,故入栈的顺序与前序遍历顺序相反                tmp_node=tmp_node.left_child            node=stack.pop()            print(node.data,end=" ")            tmp_node=node.right_child    def postorderTravelsal(self,root):        """用进栈出栈的方式实现后序遍历"""        if root is None:            return None        stack=[]        tmp_node = root        while tmp_node or stack:            while tmp_node:                stack.append(tmp_node)                tmp_node = tmp_node.left_child            node=stack[-1]            tmp_node = node.right_child            if node.right_child is None:                node = stack.pop()                print(node.data,end=" ")                while stack and node == stack[-1].right_child:                    node=stack.pop()                    print(node.data,end=" ")if __name__ == '__main__':    t = BiTree()    for i in range(10):        t.add(i)    print("层序遍历:", end=" ")#end=" "意思是末尾不换行,加空格    t.breadth_travel()    print()#换行    print("递归前序遍历:", end=" ")    t.preorder(t.root)    print()    print("递归中序遍历:", end=" ")    t.inorder(t.root)    print()    print("递归后序遍历:", end=" ")    t.postorder(t.root)    print()    print("栈式前序遍历:", end=" ")    t.preorederTravelsal(t.root)    print()    print("栈式中序遍历:", end=" ")    t.inorederTravelsal(t.root)    print()    print("栈式后序遍历:", end=" ")    t.postorderTravelsal(t.root)

结果:

层序遍历: 0 1 2 3 4 5 6 7 8 9 递归前序遍历: 0 1 3 7 8 4 9 2 5 6 递归中序遍历: 7 3 8 1 9 4 0 5 2 6 递归后序遍历: 7 8 3 9 4 1 5 6 2 0 栈式前序遍历: 0 1 3 7 8 4 9 2 5 6 栈式中序遍历: 7 3 8 1 9 4 0 5 2 6 栈式后序遍历: 7 8 3 9 4 1 5 6 2 0 Process finished with exit code 0

完整代码二

扩展二叉树前序遍历序列创建二叉树以及四种遍历

class BTnode(object):# 创建树结点    def __init__(self, data=None, left_child=None, right_child=None):        self.data = data        self.left_child = left_child        self.right_child = right_childclass BiTree(object):#创建树类    def __init__(self, data_list):#data_list为想要创建二叉树的扩展二叉树的前序遍历序列        #初始化即将传入的列表的迭代器        self.it = iter(data_list)#对一个对象调用iter()可以得到他的迭代器。    def createBiTree(self, bt=None):#用前序遍历的方法创建二叉树        try:            #步进获取下一个元素            next_data = next(self.it)#next方法:返回迭代器的下一个元素            #如果当前列表元素为'#', 则认为其为 None            if next_data is "#":                bt = None            else:                bt = BTnode(next_data)                bt.left_child = self.createBiTree(bt.left_child)                bt.right_child = self.createBiTree(bt.right_child)        except Exception as e:            print(e)        return bt    def breadth_travel(self):#层序遍历即广度优先遍历,用队列的方式实现        if self.root is None:            return        queue = [self.root]        while queue:            cur = queue.pop(0)            print(cur.data, end=" ")            if cur.left_child is not None:                queue.append(cur.left_child)            if cur.right_child is not None:                queue.append(cur.right_child)    """递归实现三种遍历"""    def preorder(self, node):        """用递归实现先序遍历"""        if node is None:            return        print(node.data, end=" ")        self.preorder(node.left_child)        self.preorder(node.right_child)    def inorder(self, node):        """用递归实现中序遍历"""        if node is None:            return        self.inorder(node.left_child)        print(node.data, end=" ")        self.inorder(node.right_child)    def postorder(self, node):        """用递归实现后序遍历"""        if node is None:            return        self.postorder(node.left_child)        self.postorder(node.right_child)        print(node.data, end=" ")    """非递归,用栈的方式实现前、中、后序遍历"""    def preorederTravelsal(self, root):        """用进栈出栈的方式实现前序遍历"""        if root is None:            return None        stack = [root]        while stack:  # 当stack不为空时            node = stack.pop()  # 出栈            if node:                print(node.data, end=" ")                stack.append(node.right_child)                # 进栈,因栈后进先出,故入栈的顺序与前序遍历顺序相反                stack.append(node.left_child)    def inorederTravelsal(self, root):        """用进栈出栈的方式实现中序遍历"""        if root is None:            return None        stack = []        tmp_node = root        while tmp_node or stack:  # 当stack不为空时            while tmp_node:                stack.append(tmp_node)                # 进栈,因栈后进先出,故入栈的顺序与前序遍历顺序相反                tmp_node = tmp_node.left_child            node = stack.pop()            print(node.data, end=" ")            tmp_node = node.right_child    def postorderTravelsal(self, root):        """用进栈出栈的方式实现后序遍历"""        if root is None:            return None        stack = []        tmp_node = root        while tmp_node or stack:            while tmp_node:                stack.append(tmp_node)                tmp_node = tmp_node.left_child            node = stack[-1]            tmp_node = node.right_child            if node.right_child is None:                node = stack.pop()                print(node.data, end=" ")                while stack and node == stack[-1].right_child:                    node = stack.pop()                    print(node.data, end=" ")    #综合打印    def printTrave(self, bt):        print("递归先序遍历: ", end="")        self.preorder(bt)        print('\n')        print("递归中序遍历: ", end="")        self.inorder(bt)        print('\n')        print("递归后序遍历: ", end="")        self.postorder(bt)        print('\n')#换行        print("栈式非递归先序遍历: ", end="")        self.preorederTravelsal(bt)        print('\n')        print("栈式非递归中序遍历: ", end="")        self.inorederTravelsal(bt)        print('\n')        print("栈式非递归后序遍历: ", end="")        self.postorderTravelsal(bt)if __name__ == '__main__':    data = input("Please input the node value: ")    data_list = list(data)    btree = BiTree(data_list)    root = btree.createBiTree()    btree.printTrave(root)

结果:

Please input the node value: AB#D##C##递归先序遍历: A B D C 递归中序遍历: B D A C 递归后序遍历: D B C A 栈式非递归先序遍历: A B D C 栈式非递归中序遍历: B D A C 栈式非递归后序遍历: D B C A Process finished with exit code 0

总结:

\quad \quad 二叉树的遍历,有递归和非递归的完成方式;

\quad \quad 二叉树的添加结点和广度遍历都是使用队列实现的,二叉树深度遍历的三种方式都是使用栈结构完成的;

\quad \quad 递归方式遍历必须传参,而且传入的参数就是根结点;

\quad \quad 非递归方式的遍历可以传参也可以不传参,选择传的话,就是传入根结点,不传参是直接获取到构造方法中封装的根结点(类变量:根结点)

上一篇:leetcode(力扣)刷题题解网站
下一篇:详谈二叉树1——定义、特点、性质、存储结构

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2025年04月14日 08时57分36秒