首先明确二叉搜索树的概念
- 二叉搜索树又叫二叉排序树,它的定义是: 1 空树是二叉搜索树 2:如果左子树存在,那么左子树的所有节点值均小于根节点; 如果右子树存在,右子树的所有节点值均大于根节点值。 3: 子树也是二叉排序树。 下面就是一颗二叉搜索树。
- 二叉搜索树的特点:基于此的常见考点就是下面的。
- 中序遍历是由小到大排序的(因此对于此二叉树转化双向排序列表、寻找第k小的数值、排序类问题都是非常重要的) ;
- 后续遍历最后的节点是根节点,那么左边的部分的前一部分比根节点小,后一部分比根节点大,这就能找到左右子树。(基于这个的我们可以重构二叉树、也可以判定给定一个后序遍历它是不是某一颗二叉树的后序遍历)
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
思路就是直接按照上面的性质 + 二叉树的基本中序遍历 得到第k小的数值。本质上考察的就是二叉树+变形。
def KthNode(self, pRootOfTree, k):
# 注意k == 0,表示没开始数
if pRootOfTree == None or k == 0:
return None
tempNode = pRootOfTree
stack = []
while tempNode or stack:
while tempNode:
stack.append(tempNode)
tempNode = tempNode.left
tempNode = stack.pop()
if k == 1:
return tempNode
k -= 1
tempNode = tempNode.right
return None
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
思路就是上述性质发现中序遍历结果连起来刚好是题目的要求,那么我们就考虑将头节点和左右子树连接器,那么就是二叉树递归中序列遍历的基础上,连接左右子树然后当前最右节点。但是发现对于左子树可以,返回最大值,下次直接拼接后面的就可以。但是对于右子树,我们需要返回最左侧,才能和根结点拼起来。想来想去,最后发现返回根节点即可,然后返回的如果是左子树,就右根结点移动到最右侧,如果是右子树,就由根节点移动到最左侧,然后结合当前的根结点拼起来,再次返回当前根节点,这就是整个思路。
可以发现能解除此题 就是 性质 + 二叉树的基本模板。属于上一个博客的第二点。
# 首先发现搜索二叉树的中序遍历就是由小到大排序的
# 本质上就是将二叉树的中序遍历构造一个双向列表,且不申请新的内存空间
class Solution:
def Convert(self, pRootOfTree):
# write code here
if pRootOfTree == None:
return None
def midWatch(pRootOfTree):
if pRootOfTree == None:
return None
left = midWatch(pRootOfTree.left)
pNode = pRootOfTree
right = midWatch(pRootOfTree.right)
if left:
while left.right:
left = left.right
left.right = pNode
if right:
while right.left:
right = right.left
right.left = pNode
pNode.right = right
pNode.left = left
return pNode
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
题目思路:就是上述搜索二叉树的性质2,通过后序遍历能重构二叉树,那么考虑不能重构的原因就是左子树里面有比根结点大的 or 右子树里面有比根节点小的,这就是思路。那么思路来了,直接按照 上一个博客讲的那个递归方法就可以构造不断获取左右子树的list进行判断了。本质上还是 性质 + 模板 + 递归的模板。
def VerifySquenceOfBST(self, sequence):
# write code here
# 可以为空;子树也是二叉搜索树; 但本程序不符合
# 如左右子树不空,那么左子树的值均小于根节点,右子树的值均大于根节点
if sequence == []:
return False
# 这东西是数据结构,为什么要有这种树呢?根本的原因就是为了加快查询的速度,才引入了这种树。
def digui(sequence):
if len(sequence) <= 1: # 1个节点或者没有节点为True
return True
node = sequence[-1]
i = 0
# 用while循环可以分隔开2个元素的list
while i < len(sequence) - 1:
if sequence[i] > node:
break
i += 1
# 注意切片在范围溢出时候返回空数组,不会发生indexErroe错误
seqSmall = sequence[:i]
seqLarge = sequence[i:-1]
# 下面几行可以优化,从时间复杂度上考虑的话,问题不大
for j in seqSmall:
if j > node:
return False
for k in seqLarge:
if k < node:
return False
return digui(seqSmall) and digui(seqLarge)
return digui(sequence)
对上面的一种补充:可以发现二叉搜索树是二叉树的一种特殊形式,它具备二叉树的那些基础模板,我们可以用二叉树的基础模板去实现这样的二叉搜索树,同时它又具有自己独特的特性,如上面讲述的2个点,本质上而言,二叉搜索树是二叉树的一种应用。因此它的解题思路和二叉树的基本思路模板大同小异。只会在其基础上进行一些扩展,往往反应在代码上就是逻辑的一些思想上的不同,但基本的实现架构师一样的。