二叉树的创世记:定义二叉树、获取二叉树、遍历二叉树(Python)

站在巨人的肩膀上,风景这边独好;
亲自爬上巨人的肩膀,才知风景为什么这么美。

最近专项复习一下数据结构的知识,准备把剑指offer上的题按数据结构刷一遍。抽空刷了几道二叉树的编程题,二叉树的核心知识和基础基本上每道题都需要。网上查看了一些代码,受用不少,但是分散在各个链接中。作为做二叉树题的核心,我把我的受用收集整理到这个文章中。

1. 二叉树的定义

当初学数据结构的时候,最怕碰到的就是二叉树了。有自己的结构体,还有好多乱七八糟的二叉树变种,什么一般的二叉树,平衡二叉树,满二叉树,完全二叉树,红黑树,2-3树… 望而生畏。慢慢做下来发现,万变不离其宗。就像面粉袋上封口的细绳,找准线头,轻轻一拽~~~
什么是二叉树?
百度百科说:二叉树是每个节点最多有两个子树的树结构。
图片说:
这里写图片描述
代码说:

class TreeNode:
    def __init__(self, x, leftNode, rightNode):
        self.left = leftNode
        self.right = rightNode
        self.val = x

不管别的有的没的,这就是最常见最常用的二叉树。其他的二叉树的变种等这种普通的二叉树玩腻了再说。

2. 二叉树的获取

第一种方式,手动生成二叉树:

class TreeNode:
    def __init__(self, x, leftNum, rightNum):
        self.left = leftNum
        self.right = rightNum
        self.val = x

class Solution:
    def generateNewTree(self):
        x = TreeNode("X",None, None)
        y = TreeNode("Y",None, None)
        d = TreeNode("D", x, y)
        e = TreeNode("E", None, None)
        f = TreeNode("F", None, None)
        c = TreeNode("C", e, f)
        b = TreeNode("B", d, None)
        a = TreeNode("A", b, c)
        return a

第二种,给定某两种遍历结果,获取原二叉树(的根节点):

class TreeNode:
    def __init__(self, x, leftNode, rightNode):
        self.left = leftNode
        self.right = rightNode
        self.val = x

class Solution:
    # 给定前序遍历和中序遍历,获得二叉树
    def getBSTwithPreTin(self, pre, tin):
        if len(pre)==0 | len(tin)==0:
            return None
        root = TreeNode(pre[0],None, None)
        for order,item in enumerate(tin):
            if root .val == item:
                root.left = self.getBSTwithPreTin(pre[1:order+1], tin[:order])
                root.right = self.getBSTwithPreTin(pre[order+1:], tin[order+1:])
                return root

3. 二叉树的三种遍历方式

基于该博客的Python版实现:

class TreeNode:
    def __init__(self, x, leftNode, rightNode):
        self.left = leftNode
        self.right = rightNode
        self.val = x

class Solution:
    def __init__(self):
        self.array = []

    # 前序遍历
    def preOrder(self, root):
        if not root:
            return self.array
        self.array.append(root.val)
        self.preOrder(root.left)
        self.preOrder(root.right)

    # 中序遍历
    def midOrder(self, root):
        if not root:
            return self.array
        self.midOrder(root.left)
        self.array.append(root.val)
        self.midOrder(root.right)

    # 后序遍历
    def postOrder(self, root):
        if not root:
            return self.array
        self.postOrder(root.left)
        self.postOrder(root.right)
        self.array.append(root.val)

4. 二叉树存在的价值

现在已经知道了什么是二叉树,怎么构建、获取二叉树,以及二叉树的三种遍历方式; 我为什么要知道这些?二叉树到底干什么用?它凭什么需要我花这么多时间学它?

二叉树的存在是折中链表和数组的优势和劣势的结果。

也许这样说不够直观,来给个表格,通过对比三种数据结构在三种操作上的时间复杂度来说明问题:

查找插入删除
链表O(N)O(1)O(1)
数组O(1)O(N)O(N)
二叉树O(logN)O(logN)O(logN)

可以看到,链表不适合频繁查找,数组不适合频繁插入/删除;而二叉树(事实上为排序二叉树),查找成本O(logN)。插入成本O(logN)。O(logN)的时间复杂度在N越大时体现越明显。
因此二叉树的应用是在频繁查找+增删的情形下优势相较于链表和数组非常明显。具体频繁应用在存储操作中,例如由排序二叉树(由于普通排序二叉树可能会有不平衡的情况)引申出来的: 红黑树—-linux中ext3文件系统管理,avl树—-windows对进程地址空间的管理(引自知乎)。

结语

最后,给出一个较为完整的二叉树的实现,内容包括:
1. 根据前序、中序遍历序列获取二叉树;
2. 根据获取到的二叉树的根节点实现三种遍历。

class TreeNode:
    def __init__(self, x, leftNode, rightNode):
        self.left = leftNode
        self.right = rightNode
        self.val = x

class Solution:
    def __init__(self):
        self.array = []

    # 给定前序遍历和中序遍历,获得二叉树
    def getBSTwithPreTin(self, pre, tin):
        if len(pre)==0 | len(tin)==0:
            return None
        root = TreeNode(pre[0], None, None)
        for order,item in enumerate(tin):
            if root .val == item:
                root.left = self.getBSTwithPreTin(pre[1:order+1], tin[:order])
                root.right = self.getBSTwithPreTin(pre[order+1:], tin[order+1:])
                return root

    # 前序遍历
    def preOrder(self, root):
        if not root:
            return self.array
        self.array.append(root.val)
        self.preOrder(root.left)
        self.preOrder(root.right)

    # 中序遍历
    def midOrder(self, root):
        if not root:
            return self.array
        self.midOrder(root.left)
        self.array.append(root.val)
        self.midOrder(root.right)

    # 后序遍历
    def postOrder(self, root):
        if not root:
            return self.array
        self.postOrder(root.left)
        self.postOrder(root.right)
        self.array.append(root.val)


if __name__ == '__main__':
    solution = Solution()
    preorder_seq = [1, 2, 4, 7, 3, 5, 10]
    middleorder_seq = [4, 7, 2, 1, 5, 3,10]
    treeRoot1 = solution.getBSTwithPreTin(preorder_seq, middleorder_seq)
    # solution.preOrder(treeRoot1)
    # solution.midOrder(treeRoot1)
    solution.postOrder(treeRoot1)
    print(solution.array)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值