二叉树
一、复习
1.1、队列与堆
队列的操作比较讨巧,查找最大值或最小值的效率也较高,堆用于查最大值也是效率很高
主要应掌握出队入队,以及出堆,Python中的deque模块与heapq模块能够分别建立队列和堆
二、二叉树
2.1、定义
-
一棵深度为k,且有2^k-1个节点的二叉树,称为满二叉树。这种树的特点是每一层上的节点数都是最大节点数。而在一棵二叉树中,除最后一层外,若其余层都是满的,并且最后一层或者是满的,或者是在右边缺少连续若干节点,则此二叉树为完全二叉树。具有n个节点的完全二叉树的深度为floor(log2n)+1。深度为k的完全二叉树,至少有2k-1个叶子节点,至多有2k-1个节点。
-
二叉树是递归定义的,其结点有左右子树之分,逻辑上二叉树有五种基本形态:
(1)空二叉树——如图(a);
(2)只有一个根结点的二叉树——如图(b);
(3)只有左子树——如图©;
(4)只有右子树——如图(d);
(5)完全二叉树——如图(e)。

(1)完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
(2)满二叉树——除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
(3)平衡二叉树——平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
2.2、遍历
- 前序遍历:按照根节点->左子树->右子树的顺序访问二叉树
- 中序遍历:按照左子树->根节点->右子树的顺序访问
- 后序遍历:按照左子树->右子树->根节点的顺序访问
- 层次遍历:按照每一层,从上到下,从左到右顺序访问
2.3、Python中应用
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Node(object):
def __init__(self,val):
self.val = val
self.left = None
self.right = None
class Tree(object):
def __init__(self):
self.root = None
def add(self,val):
node=Node(val)
if self.root is None:
self.root = node
else:
q = [self.root]
while True:
pop_node = q.pop(0)
if pop_node.left is None:
pop_node.left = node
return
elif pop_node.right is None:
pop_node.right = node
return
else:
q.append(pop_node.left)
q.append(pop_node.right)
def preorder(self,root): #前序遍历
if root is None:
return []
result_0 = [root.val]
leftval_0 = self.preorder(root.left)
rightval_0 = self.preorder(root.right)
return result_0 + leftval_0 + rightval_0
def inorder(self,root): # 中序遍历
if root is None:
return []
result_1 = [root.val]
leftval_1 = self.inorder(root.left)
rightval_1 = self.inorder(root.right)
return leftval_1 + result_1 + rightval_1
def postorder(self,root): # 后序遍历
if root is None:
return []
result_2 = [root.val]
leftval_2 = self.postorder(root.left)
rightval_2 = self.postorder(root.right)
return leftval_2 + rightval_2 + result_2
def traverse(self): #普通的层次遍历 只是简单按顺序把结点列出来,没有分层
if self.root is None:
return []
q = [self.root]
i = 0
while True:
q = [self.root]
res = [self.root.item]
while q != []:
pop_node = q.pop(0)
if pop_node.child1 is not None:
q.append(pop_node.child1)
res.append(pop_node.child1.item)
if pop_node.child2 is not None:
q.append(pop_node.child2)
res.append(pop_node.child2.item)
return res
t = Tree()
for m in range(10):
t.add(m)
print t.traverse()
print t.preorder(t.root)
print t.inorder(t.root)
print t.postorder(t.root)
2.3.1、leetcode
98. Validate Binary Search Tree
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def isValidBST(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
list = self.inorder(root)
for i in range(len(list)-1): # 直接利用中序遍历得到的序列进行比对(因为该题二叉树的中序遍历序列一定为递增数列)
if list[i]>=list[i+1]:
return False
return True
def inorder(self,root): # 中序遍历
if root is None:
return []
result_1 = [root.val]
leftval_1 = self.inorder(root.left)
rightval_1 = self.inorder(root.right)
return leftval_1 + result_1 + rightval_1
class Solution(object):
def __init__(self):
self.flag = True
def isValidBST(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
self.judge(root,None,None)
return self.flag
def judge(self,root,min,max): #这个很牛逼,我并不能看得很懂哈哈哈,应该是从中序遍历推广来的
if root is None:
return
if (min != None and root.val<=min.val) or (max != None and root.val >= max.val):
self.flag = False
return
self.judge(root.left,min,root) # 对于左子树而言,最大值是左子树的根节点root
self.judge(root.right,root,max) #对于右子树而言,最小值是右子树的根节点root
class Solution(object):
def __init__(self):
import sys
self.last = -sys.maxint #python中最小的数(本来是最大,加了个负号就变成了最小)
def isValidBST(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
if root is None:
return True
if self.isValidBST(root.left) == False: # 一边进行中序遍历,一边进行比较(中序遍历是递增数列),所以要设置全局变量,每遍历得到一个值便比较一次
return False
if root.val <= self.last:
return False
self.last = root.val
if self.isValidBST(root.right) == False:
return False
return True
class Solution(object):
def isValidBST(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
stack = []
p = root
pre = None
while p!=None or stack!=[]: #迭代的思路,用栈压入左子树,然后取出判断
while p!=None : # 据大佬说跟中序遍历的思路是共通的
stack.append(p)
p = p.left
t = stack.pop()
if pre!=None and t.val<=pre.val: # 利用中序遍历序列的递增关系,一直中序遍历一直判断
return False
pre = t
p = t.right
return True
- 结果




102. Binary Tree Level Order Traversal
class Solution(object):
def levelOrder(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
q = [(root,0)] # 右边存的是层数,根节点是第0层
res = [[]] # 初始化res
if root == None :
return []
k = 0 # k为层数
while q: #一边不断按顺序将结点输入队列q,然后再从队头将各个结点出队
t = q.pop(0)
res[t[1]].append(t[0].val) # 按层数将对应值输入到res列表中
if t[0].left :
q.append((t[0].left,t[1]+1)) # 输入队列q时,记得把层数+1
if t[0].right :
q.append((t[0].right,t[1]+1)) # 输入队列q时,记得把层数+1
if t[0].left or t[0].right : # 有子节点,说明有下一层,层数要加一,同时res也要插入新的层
if k == t[1]: #如果标示的层数与从队列取出的结点所指示的层数相同,则说明确实有下一层
res.append([])
k += 1
return res
- 结果

107. Binary Tree Level Order Traversal II
class Solution(object):
def levelOrderBottom(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
q = [(root,-1)] #与上题不同,这里根节点是-1,标示res中的末尾
res = [[]]
if root == None :
return []
k = -1 # 层数的反序
while q: #与上题不同,这里不断在res的头部不断插入新的层数,因为是反序,所以不再从res的尾部插入新层
t = q.pop(0)
res[t[1]].append(t[0].val)
if t[0].left :
q.append((t[0].left,t[1]-1)) # 与上题相反,这里-1
if t[0].right :
q.append((t[0].right,t[1]-1)) # 与上题相反,这里-1
if t[0].left or t[0].right :
if k == t[1]:
res.insert(0,[]) # res的头部插入新层
k -= 1
return res
- 结果

本文回顾了队列和堆的基本概念,重点讲解了二叉树的定义、类型(满二叉树、完全二叉树、平衡二叉树)以及四种遍历方式。在Python中,介绍了使用二叉树解决LeetCode上的问题,如验证二叉搜索树和层次遍历等。

被折叠的 条评论
为什么被折叠?



