大话数据结构--第5-6章学习笔记--串与树

串这一章,主要是讲的串的匹配(主串里面找子串),暴力匹配的方法是子串在主串中按照顺序一个个的匹配,主串的游标首先是0,再是1.....遇到不匹配的地方就回溯,回到1,子串的游标回到0,然后再继续前面匹配的步骤,这样的方法很简单,但是时间复杂度会非常大。

而KMP算法以及其改进的算法,避免了主串游标的回溯,而是只变化子串的位置,降低了时间复杂度,但是KMP步骤真的好难理解啊!书上讲的蛮混乱的,我都没有怎么看懂,所幸找到了一个讲得非常好的博主的讲解: 

https://blog.csdn.net/v_july_v/article/details/7041827

写的非常好~清楚明了!

 

首先要知道的就是二叉树的定义及其三种类型。

定义:一个树,它的孩子节点至多只有两个。

三种类型:

完全二叉树(除了最后一层,其它层节点是满的,并且所有节点都尽可能的靠近左子树)

平衡二叉树(左右子树的深度差距不超过1)

二叉搜索树(左节点的值永远大于右节点)

用python实现:

class binary_tree:
    def __init__(self,value):
        self.value = value
        self.left = None
        self.right = None

对于二叉树常见的操作有与递归结合,进行遍历、计算二叉树高度,节点个数等,还有按层打印二叉树。

遍历:

遍历有三种,先根遍历,中序遍历,后根遍历。实现使用递归非常简单。

先根遍历:先根节点,再左节点,再右节点。

中序遍历:先左,后根,再右。

后根遍历:先右,再左,再根。

def pre(root):
    res = []
    bianli(root,res)
    return res
def bianli(root,res):
    if not root:
        return -1
    res.append(root.value)#中根和后根遍历就是把这句话与后面两句话的顺序进行变化即可
    bianli(root.left,res)
    bianli(root.right,res)

时间复杂度为:o(n)

二叉树与递归的结合:

二叉树在面试中是最适合于与递归相结合的,除了遍历,还有计算树的高度,计算节点的个数。

计算树的高度:

思路:递归就是一直调用自己函数本身,直到有一个出口,这个出口叫做base case,从这个出口返回到上一步。所以做递归的时候要想清楚的东西是:

出口:在这里的出口就是节点的左右节点都为None时开始返回到上一个节点。

返回的值:在这里返回的是树的高度,如果一个节点的左右节点都没有了,那么这个节点构成的高度为1,如果它有左右节点,那么这个节点构成的高度为左右节点最深的深度加上自身的一层,所以返回的应该是max(left,right)+ 1。

def getHeight(root):
    if root == None:
        return 0
    left = getHeight(root.left)
    right = getHeight(root.right)
    return max(left,right)+1

时间复杂度o(n)

计算树节点的个数:思路类似

def getNumber(root):
    if root == None:
        return 0
    left = getNumber(root.left)
    right = getNumber(root.right)
    return left + right + 1

 

递归其实对于我个人来说真的非常难.....二叉树和递归结合的题每隔一段时间我都得拿出来复习,不然记不住啊,脑子笨呜呜呜呜呜。

计算树的每个左节点节点个数:

在这个定义二叉树节点的时候就加入需要求取的选项。

class binary_tree:
    def __init__(self,value):
        self.value = value
        self.left = None
        self.right = None
        self.left_node = 0      #保存左节点数量
def get_left_node_number(root):
    if root == None:
        return 0
    left = get_left_node_number(root.left)
    right = get_left_node_number(root.right)
    root.left_node = left
    return 1+left+right

计算左右节点之间最深的差距:

class get_max_diff:
    
    def result(self):
        self.maxs = -1

    def get(self,root):
        if root == None:
            return 0
        left = self.get(root.left)
        right = self.get(root.right)
        if abs(left-right) > root.maxs:
            root.maxs = abs(left-right)
        return 1+left+right

上述几个问题base case都是root为None。如果返回的结果和叶子节点有关系的话,选择的base case就应该变成root的left和right为None。

比如找出二叉树节点最浅的深度是多少这个问题,应该找的是每个节点的叶子结点,这个叶子结点没有任何后继节点。

def get_miniunm(root):
    if root == None:
        return 0
    if root.left == None and root.right == None:
        return 1
    left = get_miniunm(root.left) if root.left else float('inf')
    right = get_miniunm(root.right) if root.right else float('inf')
    return min(left,right)+1

按层打印二叉树:

把二叉树的节点一层层的打印出来:

思路:使用两个队列来实现,一个队列存储当前节点,一个队列储存当前节点的左右节点。再利用一个数组来存储目前层的节点数值。

python实现如下:

def print_tree(root):
    if root == None:
        return 0
    q = [root]#存储当前节点
    next = []#存储当前节点的左右节点
    val = []#存储当前层所有节点的数值
    while q:
        head = q.pop(0)
        if head.left:
            next.append(head.left)
        if head.right:
            next.append(head.right)
        val.append(head.value)
        if not q:
            print(val)
            if next:
                q = next
                val = []
                next = []

除了这些问题之外还有寻找最小公共祖先之类的代码练习题目,我都在力扣网上练习的就不一一放出来啦~

二叉树还有中特殊的类型,叫哈夫曼树

哈夫曼树就是带权路径长度(wpl)最小的二叉树叫做哈弗曼树。

构成方法很简单,书p205。

书上还讲了森林和树之间的变化,我粗略的看了一下~树这一单元中,还是觉得二叉树最最最重要啦!

你可能感兴趣的:(python编程学习心得)