(不重要) 终端打印一颗二叉树,便于观察
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()