文章目录
二叉搜索树的后序遍历序列
二叉搜索树
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树。
后续遍历结果:1 5 3 9 12 10 7
二叉搜索树的后续遍历具有以下特点:
- 最后一个元素为数的根节点
- 存个一个分界线,分界线左边的所有元素都小于根节点,分界线右边的所有元素都大于根节点(上图的分界线就在3 9 之间)
- 经过第二步的分割,形成两个切片[1 5 3]、[9,12,10],切片同样符合上述规律
根据上面的特点,在考虑两种特殊情况,1.无左孩子,2.无右孩子
# -*- coding:utf-8 -*-
class Solution:
def VerifySquenceOfBST(self, sequence):
# write code here
if not sequence:
return False
if len(sequence) == 1:
return True
count1 = 0
count2 = 0
for i in range(len(sequence)):
#左右孩子节点都不为空
if sequence[i] < sequence[-1] and sequence[i+1] > sequence[-1]:
#左子树的所有节点必须小于根节点
for j in range(i+1):
if sequence[j] > sequence[-1]:
return False
#右子树所有节点必须大于根节点
for k in range(i+1,len(sequence)-1):
if sequence[k] < sequence[-1]:
return False
return self.VerifySquenceOfBST(sequence[:i+1]) and self.VerifySquenceOfBST(sequence[i+1:-1])
#仅有左孩子
if sequence[i] < sequence[-1]:
count1 += 1
#仅有右孩子
if sequence[i] > sequence[-1]:
count2 += 1
if count1 == len(sequence)-1 or count2 == len(sequence)-1:
return self.VerifySquenceOfBST(sequence[:-1])
return False
从上往下打印二叉树–广度遍历
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回从上到下每个节点值列表,例:[1,2,3]
def PrintFromTopToBottom(self, root):
# write code here
answer = []
if not root:
return answer
li = [root]
while li:
cur = li.pop(0)
answer.append(cur.val)
if cur.left:
li.append(cur.left)
if cur.right:
li.append(cur.right)
return answer
重建二叉树
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
if len(pre) == 0:
return None
if len(pre) == 1:
return TreeNode(pre[0])
root = TreeNode(pre[0])
# i = tin.index(pre[0])
#
# tin_lchild = tin[:i]
# len_lchild = len(tin_lchild)
# pre_lchild = pre[1:1+len_lchild]
#
# tin_rchild = tin[i+1:]
# len_rchild = len(tin_rchild)
# pre_rchild = pre[1+len_lchild:]
root.left = self.reConstructBinaryTree(pre[1:1+len(tin[:tin.index(pre[0])])], tin[:tin.index(pre[0])])
root.right = self.reConstructBinaryTree(pre[1+len(tin[:tin.index(pre[0])]):], tin[tin.index(pre[0])+1:])
return root
笔记
递归★★★★★
class soultion:
def nove(self,n,a,b,c):
print(n,a,b,c)
if n == 1:
print(a,'------------>',c)
else:
self.nove(n-1,a,c,b)
self.nove(1,a,b,c)
self.nove(n-1,b,a,c)
if __name__ == "__main__":
a = soultion()
b = a.nove(3, 'A', 'B', 'C')
print(b)
上述程序的执行结构图如下所示:
四个字母分别代表传入的(n,a,b,c)
传入顺序:由左到右,由上到下。
判断对称二叉树
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetrical(self, pRoot):
# write code here
if pRoot is None:
return True
return self.check(pRoot.left,pRoot.right)
def check(self,l,r):
if l == None and r == None:
return True
elif (l != None and r == None) or (l == None and r != None) or (l.val != r.val):
return False
return self.check(l.left,r.right) and self.check(l.right,r.left)
二叉树的下一个节点
题目分析:
# -*- coding:utf-8 -*-
# class TreeLinkNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
# self.next = None
class Solution:
def GetNext(self, pNode):
# write code here
#有右子树
if pNode.right != None:
r = pNode.right
while r.left:
r = r.left
return r
#无右子树
else:
#如果是根节点(无父节点)
if pNode.next == None:
return None
#如果不是根节点(有父节点)
else:
#如果是父节点的左孩子
if pNode == pNode.next.left:
return pNode.next
#如果是父节点的右孩子
else:
while pNode.next.next.left != pNode.next:
pNode = pNode.next
#没有符合条件的即是尾节点
if pNode.next.next == None:
return None
return pNode.next.next
把二叉树打印成多行
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回二维列表[[1,2],[4,5]]
def Print(self, pRoot):
# write code here
#用两个列表分别保存当前行节点和下一行节点
current = [pRoot]
next_layer = []
result = []
if pRoot is None:
return result
while current:
for i in current:
if i.left:
next_layer.append(i.left)
if i.right:
next_layer.append(i.right)
#每一层输出一行,重点在于下面的append([]),[]就表示了每层一行
result.append([i.val for i in current])
current,next_layer = next_layer,[]
return result
按之字形顺序打印二叉树
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def Print(self, pRoot):
# write code here
current = [pRoot]
next_layer = []
result = []
deep = 0
if pRoot is None:
return result
while current:
deep += 1
for i in current:
if i.left:
next_layer.append(i.left)
if i.right:
next_layer.append(i.right)
if deep % 2 != 0:
result.append([i.val for i in current])
else:
#下面这两句话的含义是一样的,都是逆序遍历current[]
#result.append([current[len(current)-i-1].val for i in range(len(current))])
result.append([i.val for i in current[::-1]])
current,next_layer = next_layer,[]
return result
序列化二叉树
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.count = -1
def Serialize(self, root):
# write code here
# 下面的两种判断方式相同
# if root is None:
if not root:
#必须添加分隔符,否则两位数转化为字符串时会出现错误
return "#,"
#如果当前节点是父节点,则会继续递归
#如果当前节点是叶节点,则会返回“.val , # , #"
return str(root.val)+ ',' + self.Serialize(root.left) + self.Serialize(root.right)
def Deserialize(self, s):
# write code here
self.count += 1
#只是第一次进入函数时对字符串进行分割
#split操作返回的是一个列表,如果每次都进行split操作会报错
#因为第一次往后s变成了列表,列表没有split操作
if self.count == 0:
s = s.split(',')
if self.count >= len(s):
return None
root = None
if s[self.count] != "#":
root = TreeNode(int(s[self.count]))
root.left = self.Deserialize(s)
root.right = self.Deserialize(s)
return root
split示例
二叉搜索树的第k个结点
二叉搜索树
二叉搜索树也叫二叉排序树,它可以是一棵空树。它具有一下特点
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别为二叉搜索树
- 没有键值(key)相等的节点
- 二叉搜索树的中序遍历结果是排好序的
二叉搜索树如下所示:
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回对应节点TreeNode
def __init__(self):
self.li = []
self.serch_flag = False
self.node = None
def KthNode(self, pRoot, k):
# write code here
if k <= 0 or not pRoot:
return None
self.li = self.Tinorder(pRoot)
if len(self.li) < k:
return None
self.node = self.Serch(pRoot, self.li[k - 1])
return self.node
#二叉搜索树的中序遍历结果是排序好的
def Tinorder(self, pRoot):
"""中序遍历"""
if not pRoot:
return
self.Tinorder(pRoot.left)
self.li.append(pRoot.val)
self.Tinorder(pRoot.right)
return self.li
def Serch(self, pRoot, num):
"""数值搜索"""
if not pRoot:
return
if pRoot.val == num:
self.node = pRoot
self.Serch(pRoot.left,num)
self.Serch(pRoot.right,num)
return self.node
本题扩展–任意二叉树的第K个节点
思路:
- 首先利用前序遍历将二叉树存入列表
- 再对列表进行快速排序
- 然后在寻找节点
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回对应节点TreeNode
def __init__(self):
self.li = []
#self.serch_flag = False
self.node = None
def KthNode(self, pRoot, k):
# write code here
if k <= 0 or not pRoot:
return None
self.li = self.Perorder(pRoot)
if len(self.li) < k:
return None
self.li = self.Quick_sort(self.li, 0, len(self.li) - 1)
self.node = self.Serch(pRoot, self.li[k - 1])
return self.node
def Perorder(self, pRoot):
"""先序遍历"""
if not pRoot:
return
self.li.append(pRoot.val)
self.Perorder(pRoot.left)
self.Perorder(pRoot.right)
return self.li
def Quick_sort(self, alist, first, last):
"""快速排序"""
# 终止条件
if first >= last:
return alist
mid_value = alist[first]
low = first
high = last
while low < high:
while low < high and alist[high] >= mid_value:
high -= 1
alist[low] = alist[high]
while low < high and alist[low] < mid_value:
low += 1
alist[high] = alist[low]
alist[low] = mid_value
self.Quick_sort(alist, first, low - 1)
self.Quick_sort(alist, low + 1, last)
return alist
def Serch(self, pRoot, num):
"""数值搜索"""
if not pRoot:
return
if pRoot.val == num:
#self.serch_flag = True
self.node = pRoot
self.Serch(pRoot.left,num)
self.Serch(pRoot.right,num)
return self.node
数据流中的中位数
方法一–锥排序
思路:
- 建立一个大顶锥,一个小顶锥,小顶锥用来存大的半数数据,大顶锥用来存小半数数据(小顶堆中的元素都大于等于大顶堆中的元素)
- 当数目为偶数的时候,将这个值插入大顶堆中,再将大顶堆中根节点(即最大值)插入到小顶堆中
- 当数目为奇数的时候,将这个值插入小顶堆中,再将小顶堆中根节点(即最小值)插入到大顶堆中
- 取中位数的时候,如果当前个数为偶数,显然是取小顶堆和大顶堆根结点的平均值;如果当前个数为奇数,显然是取小顶堆的根节点
# -*- coding:utf-8 -*-
#导入优先队列算法
from heapq import *
#在heapq中只有小顶锥,大顶锥则用取反实现
class Solution:
def __init__(self):
#创建一个堆,可以使用list来初始化为 []
self.heaps = [], []
self.count = 0
def Insert(self, num):
# write code here
small, large = self.heaps
if self.count % 2 == 0:
#heapq.heappush(heap, item)
#将 item 的值加入 heap 中,保持堆的不变性。
#heapq.heappushpop(heap, item)
#将 item 放入堆中,然后弹出并返回 heap 的最小元素。
"""
如果是偶数:
先将取反放入大顶锥
再将大顶锥的追锥顶pop出,并取反放入小顶锥
(由于大顶锥用来存小半数数据,且大顶锥是小顶锥取反实现,
因此大顶锥里面的数全为原始数据的相反数)
"""
#-num的负号表示大顶锥里面的数全为原始数据的相反数
#-heappushpop的负号表示小顶锥里面的数全为原始数据(即相反数的相反数)
heappush(small, -heappushpop(large, -num))
else:
"""
如果是奇数:
先将放入小顶锥
再将大顶锥的追锥顶pop出,并取反放入大顶锥
"""
heappush(large, -heappushpop(small, num))
self.count+=1
def GetMedian(self,ss):
# write code here
small,large = self.heaps
if self.count % 2 != 0:
return float(small[0])
return (small[0] - large[0]) / 2.0
方法二
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
#用来记录数据流的个数
self.count = 0
self.li = []
def Insert(self, num):
# write code here
self.li.append(num)
self.li.sort()
self.count+=1
#题目有问题,缺少一个参数。需要自己加上
def GetMedian(self,AA):
# write code here
if self.count % 2 == 0:
#牛客网python版本为2+,被除数需要写成小数形式
#python2 5/2 = 2
#python3 5/2 = 2.5
return (self.li[self.count//2-1]+self.li[self.count//2])/2.0
else:
return self.li[self.count//2]
树的子结构
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def HasSubtree(self, pRoot1, pRoot2):
# write code here
result = False
if pRoot1 != None and pRoot2 != None:
if pRoot1.val == pRoot2.val:
#此方法中下面的语句可以用下面的这一句话代替
# return self.Perorder(pRoot1,pRoot2) or self.HasSubtree(pRoot1.left,pRoot2) or self.HasSubtree(pRoot1.right,pRoot2)
result = self.Perorder(pRoot1,pRoot2)
if not result:
result = self.HasSubtree(pRoot1.left,pRoot2)
if not result:
result = self.HasSubtree(pRoot1.right,pRoot2)
return result
def Perorder(self, pRoot1, pRoot2):
if not pRoot2:
return True
if not pRoot1:
return False
#下面的四句话可以写成
#if pRoot1.val != pRoot2.val:
# return False
#return self.Perorder(pRoot1.left,pRoot2.left) and self.Perorder(pRoot1.right,pRoot2.right)
if pRoot1.val == pRoot2.val:
return self.Perorder(pRoot1.left,pRoot2.left) and self.Perorder(pRoot1.right,pRoot2.right)
else:
return False
二叉树的镜像
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
# write code here
if not root:
return
if root.left or root.right:
root.left,root.right = root.right,root.left
self.Mirror(root.left)
self.Mirror(root.right)
return root
二叉树中和为某一值的路径
叶节点:没有子节点的节点
思路:
用一临时列表记入当前先序遍历的整条路径,若此路径节点值的和等于expectNumber,则将路径加入最终返回的列表之中。
注意:当一父节点的两个子节点所在的路径都遍历完时,需要将父节点从临时列表中删除。
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回二维列表,内部每个列表表示找到的路径
def __init__(self):
self.li = []
#用于保存遍历的路径
self.tem = []
def FindPath(self, root, expectNumber):
# write code here
#当root为空时,直接返回空列表
if not root:
return self.li
#当此节点为叶节点,开始判断sum(self.tem)是否等于expectNumber
if not root.left and not root.right:
self.tem.append(root.val)
if sum(self.tem) == expectNumber:
self.li.append(self.tem)
#数组长度大于1时,才能进行下面的切片操作
#当self.tem = self.tem[:-1]用self.tem.pop()代替时,会出现问题
if len(self.tem) > 1:
self.tem = self.tem[:-1]
else:
self.tem.pop()
return self.li
#下面三句话相当前序遍历
self.tem.append(root.val)
if root.left:
self.FindPath(root.left, expectNumber)
if root.right:
self.FindPath(root.right, expectNumber)
#遍历完一次,返回上一层时需要将父节弹出
self.tem.pop()
return self.li
二叉树与双向链表
思路
二叉搜索树的中序遍历为排序列表
在中序遍历的基础上进行稍微改动即可。
#二叉搜索树的中序遍历为排序列表
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.last_node = None
def Convert(self, pRootOfTree):
# write code here
self.Tinorder(pRootOfTree)
while pRootOfTree and pRootOfTree.left:
pRootOfTree = pRootOfTree.left
return pRootOfTree
def Tinorder(self,cur):
if not cur:
return
self.Tinorder(cur.left)
#当前节点的左节点指向上一节点
cur.left = self.last_node;
#只有当上一个节点不为空时,上一节点的右节点才能指向当前节点
if self.last_node:
self.last_node.right = cur;
self.last_node = cur;
self.Tinorder(cur.right)