Python 算法(四) 二叉树,先序,中序,后续,完全、平衡、搜索二叉树

(不重要) 终端打印一颗二叉树,便于观察

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


class PrintBinaryTree:
    def print_tree(self, head):
        print('Binary Tree: ')
        self.print_in_order(head, 0, 'H', 17)
        print()

    def print_in_order(self, head, height, to, node_len):
        if head is None:
            return None
        self.print_in_order(head.right, height+1, 'v', node_len)
        val = to + str(head.value) + to
        node_len_m = len(val)
        node_len_l = (node_len - node_len_m)/2
        node_len_r = node_len - node_len_m - node_len_l
        val = self.get_space(node_len_l) + val + self.get_space(node_len_r)
        print(self.get_space(height*node_len) + val)
        self.print_in_order(head.right, height+1, '^', node_len)

    def get_space(self, num):
        space = ' '
        buf = ''
        for i in range(int(num)):
            buf += space
        return buf

    def main(self):
        head = Node(1)
        head.left = Node(-222222222)
        head.right = Node(3)
        head.left.left = Node(2147483648)
        head.right.left = Node(55555555)
        head.right.right = Node(66)
        head.left.left.right = Node(777)
        self.print_tree(head)

        head = Node(1)
        head.left = Node(2)
        head.right = Node(3)
        head.left.left = Node(4)
        head.right.left = Node(5)
        head.right.right = Node(6)
        head.left.left.right = Node(7)
        self.print_tree(head)

        head = Node(1)
        head.left = Node(1)
        head.right = Node(1)
        head.left.left = Node(1)
        head.right.left = Node(1)
        head.right.right = Node(1)
        head.left.left.right = Node(1)
        self.print_tree(head)

PrintBinaryTree().main()


1、实现二叉树的先序、中序、后序遍历

eg: 1,2,3,4,5,6,7 的二叉树,正常输出是1,2,4,4,4,2,5,5,5,2,1,3,6,6,6,3,7,7,7,3,1

递归版本:
先序:中左右,即打印第一次出现的数字。 1,2,4,5,3,6,7…
中序: 左中右,打印第二次出现数字。4,2,5,1,6,3,7…
后续: 左右中,打印第三次出现数字。4,5,2,6,7,3,1…

非递归版本:
先序:准备一个栈,先压入第一个数,然后循环到栈为空,取出一个数,然后依次右左压入,遍历。
中序:准备一个栈,循环,先全压力左边数,然后取一个数,压入右节点的全部左边节点
后续:准备两个栈,将中右左(像先序)形式压入栈(1,3,7,6,2,5,4),然后取出压入另外一个栈,最后一起取出

from queue import LifoQueue
# 这里LifoQueue()的get()有个坑,没有数不会返回None,会一直等待

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


class PreInPosTraversalRecur:
    def pre_order_recur(self, head):
        if head is None:
            return None
        print(head.value)
        self.pre_order_recur(head.left)
        self.pre_order_recur(head.right)

    def in_order_recur(self, head):
        if head is None:
            return None
        self.in_order_recur(head.left)
        print(head.value)
        self.in_order_recur(head.right)

    def pos_order_recur(self, head):
        if head is None:
            return None
        self.pos_order_recur(head.left)
        self.pos_order_recur(head.right)
        print(head.value)


class PreInPosTraversalUnRecur:
    def pre_order(self, head):
        if head is not None:
            stack_ = LifoQueue()
            stack_.put(head)
            while not stack_.empty():
                head = stack_.get()
                print(head.value, ' ')
                if head.right is not None:
                    stack_.put(head.right)
                if head.left is not None:
                    stack_.put(head.left)

    def in_order(self, head):
        if head is not None:
            stack_ = LifoQueue()
            while not stack_.empty() or head is not None:
                if head is not None:
                    stack_.put(head)
                    head = head.left
                else:
                    head = stack_.get()
                    print(head.value, ' ')
                    head = head.right

    def pos_order(self, head):
        if head is not None:
            s1 = LifoQueue()
            s2 = LifoQueue()
            s1.put(head)
            while not s1.empty():
                head = s1.get()
                s2.put(head)
                if head.left is not None:
                    s1.put(head.left)
                if head.right is not None:
                    s1.put(head.right)
            while not s2.empty():
                print(s2.get().value)


def main():
    head = Node(1)
    head.left = Node(2)
    head.right = Node(3)
    head.left.left = Node(4)
    head.left.right = Node(5)
    head.right.left = Node(6)
    head.right.right = Node(7)
    PreInPosTraversalRecur().pre_order_recur(head)
    print('-'*20)
    PreInPosTraversalRecur().in_order_recur(head)
    print('-' * 20)
    PreInPosTraversalRecur().pos_order_recur(head)
    print('*' * 20)
    print('*' * 20)
    PreInPosTraversalUnRecur().pre_order(head)
    print('-' * 20)
    PreInPosTraversalUnRecur().in_order(head)
    print('-' * 20)
    PreInPosTraversalUnRecur().pos_order(head)

main()

### 2、在二叉树中找到一个节点的后继节点 该结构比普通二叉树结构多一个指向父节点的parent指针。 假设有一棵Node类型的节点的二叉树,树中每个节点的parent指针都正确地指向自己的父节点,头节点的parent指向null。 只给一个在二叉树中的某个节点 node,请实现返回node的后继节点的函数。在二叉树的中序遍历的序列中, node的下一个节点叫作node的后继节点。

思路:

  • 当x有一个右节点,后继节点就是右节点的最左节点。
  • 没有右节点,往父节点找,现节点是父节点的左节点结束,父节点即后继节点
  • 后继节点: 在中序遍历(左中右)的下一个节点
  • 前驱节点:反之,有左节点,即左节点的最右节点,无左节点,现节点是父节点(前驱点)的右节点
class Node:
    def __init__(self, value, left=None, right=None, parent=None):
        self.value = value
        self.left = left
        self.right = right
        self.parent = parent

class SuccessorNode:
    def get_successor_node(self, node):
        if node is None:
            return Node
        if node.right is not None:
            return self.get_left_most(node.right)
        else:
            parent = node.parent
            while parent is not None and parent.left != node:
                node = parent
                parent = node.parent
            return parent

    def get_left_most(self, node):
        if node is None:
            return node
        while node.left is not None:
            node = node.left
        return node

    def main(self):
        head = Node(6)
        head.parent = None
        head.left = Node(3)
        head.left.parent = head
        head.left.left = Node(1)
        head.left.left.parent = head.left
        head.left.left.right = Node(2)
        head.left.left.right.parent = head.left.left
        head.left.right = Node(4)
        head.left.right.parent = head.left
        head.left.right.right = Node(5)
        head.left.right.right.parent = head.left.right
        head.right = Node(9)
        head.right.parent = head
        head.right.left = Node(8)
        head.right.left.parent = head.right
        head.right.left.left = Node(7)
        head.right.left.left.parent = head.right.left
        head.right.right = Node(10)
        head.right.right.parent = head.right


        test = head.left.left
        print(test.value , " next: " , self.get_successor_node(test).value)
        test = head.left.left.right
        print(test.value , " next: " , self.get_successor_node(test).value)
        test = head.left
        print(test.value , " next: " , self.get_successor_node(test).value)
        test = head.left.right
        print(test.value , " next: " , self.get_successor_node(test).value)
        test = head.left.right.right
        print(test.value , " next: " , self.get_successor_node(test).value)
        test = head
        print(test.value , " next: " , self.get_successor_node(test).value)
        test = head.right.left.left
        print(test.value , " next: " , self.get_successor_node(test).value)
        test = head.right.left
        print(test.value , " next: " , self.get_successor_node(test).value)
        test = head.right
        print(test.value , " next: " , self.get_successor_node(test).value)
        test = head.right.right  # 10's next is null
        print(test.value , " next: " , self.get_successor_node(test))

SuccessorNode().main()

3、判断一个课二叉树是否是平衡二叉树

平衡二叉树:任何节点,左右子树高度差不超过1,解决效率问题。

思路:

  • 准备可变列表res,对于任何一个节点,判断左右是否平衡,不平衡即左右高度相差大于1,修改变量为False,平衡就返回最大高度,然后递归上一级节点判断。
class Node:
    def __init__(self, value, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right


class IsBalancedTree:
    def is_balance(self, head):
        res = [True]
        self.get_height(head, 1, res)
        return res[0]

    def get_height(self, head, level, res):
        if head is None:
            return level
        lh = self.get_height(head.left, level + 1, res)
        if not res[0]:
            return level
        rh = self.get_height(head.right, level + 1, res)
        if not res[0]:
            return level
        if abs(lh - rh) > 1:
            res[0] = False
        print(level)
        return max(lh, rh)

    def main(self):
        head = Node(1)
        head.left = Node(2)
        head.right = Node(3)
        head.left.left = Node(4)
        head.left.right = Node(5)
        head.right.left = Node(6)
        head.right.right = Node(7)
        head.right.right.right = Node(8)
        # head.right.right.right.right = Node(9)

        print(self.is_balance(head))

IsBalancedTree().main()



4、判断一棵树是否是搜索二叉树、判断一棵树是否是完全二叉树

搜索二叉树:对于任何一个节点的值,左子树小,右子树大。即二叉树的中序遍历依次升序

完全二叉树:从左开始添加

  • 1、按层遍历,如果一个节点有右节点,没左节点,直接返回False
  • 2、如果一个节点不是左右节点都有,有左没右或者都没有,后面所有节点都必须是叶节点,否则直接返回False
  • 3、满足1和2就是完全二叉树
from queue import LifoQueue


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


class IsBSTAndCBT:
    def is_BST(self, head):
        if head is None:
            return True
        res = True
        pre = None
        cur1 = head
        while cur1 is not None:
            cur2 = cur1.left
            if cur2 is not None:
                while cur2.right is not None and cur2.right != cur1:
                    cur2 = cur2.right
                if cur2.right is None:
                    cur2.right = cur1
                    cur1 = cur1.left
                    continue
                else:
                    cur2.right = None
            if pre is not None and pre.value > cur1.value:
                res = False
            pre = cur1
            cur1 = cur1.right
        return res

    def is_BST2(self, head):
        import sys
        min_v = -sys.maxsize - 1
        res = [True]
        if head is not None:
            stack_ = LifoQueue()
            while not stack_.empty() or head is not None:
                if head is not None:
                    stack_.put(head)
                    head = head.left
                else:
                    head = stack_.get()
                    if head.value <= min_v:
                        res[0] = False
                        break
                    min_v = head.value
                    print(head.value, ' ')
                    head = head.right
        return res[0]

    def is_CBT(self, head):
        from collections import deque
        if head is None:
            return True
        queue = deque()
        leaf = False  # 开启只有叶节点的标志
        queue.append(head)
        while len(queue) != 0:
            head = queue.popleft()  # 按层遍历,当某层leaf为True,后面所有节点必须为叶节点
            # print(head.value, leaf, len(queue))
            l = head.left
            r = head.right
            if (leaf and (l is not None or r is not None)) or (l is None and r is not None):
                return False
            if l is not None:
                queue.append(l)
            if r is not None:
                queue.append(r)
            else:
                leaf = True
        return True

    def main(self):
        head = Node(4)
        head.left = Node(2)
        # head.left = Node(20)
        head.right = Node(6)
        head.left.left = Node(1)
        head.left.right = Node(3)
        head.right.left = Node(5)

        print(self.is_BST(head))
        print(self.is_BST2(head))
        print(self.is_CBT(head))

IsBSTAndCBT().main()

5、已知一棵完全二叉树,求其节点的个数

要求:时间复杂度低于O(N),N为这棵树的节点个数

思路:

  • 1、通过头节点的最深左节点,获取树的高度h
  • 2、如果头节点的右节点的最深左节点高度为h,即头节点的左边为满二叉树,节点数为2^h-1+1。然后遍历右边
  • 3、不满足2,头节点右边为满二叉树,节点数2^(h-1)-1+1。左边遍历
class Node:
    def __init__(self, value, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right


class CompleteTreeNodeNumber:
    def node_num(self, head):
        if head is None:
            return 0
        return self.bs(head, 1, self.most_left_level(head, 1))

    def bs(self, node, level, h):
        if level == h:  # level 标志现在节点的高度
            return 1
        if self.most_left_level(node.right, level+1) == h:
            return 2**(h-level) + self.bs(node.right, level+1, h)
        else:
            return 2**(h-level-1) + self.bs(node.left, level+1, h)

    def most_left_level(self, node, level):
        while node is not None:  # 这里node可能为None
            level += 1
            node = node.left
        return level-1

    def main(self):
        head = Node(1)
        head.left = Node(2)
        head.right = Node(3)
        head.left.left = Node(4)
        head.left.right = Node(5)
        # head.right.left = Node(6)
        print(self.node_num(head))

CompleteTreeNodeNumber().main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值