二叉树(binary tree)
这里都是定义的处理函数,在主程序中,怎么输入一颗二叉树?
书本描述:按序输入一颗二叉树的界定啊的数据(什么叫按序输入)
树的遍历目的:访问树的每一个节点,可用方法:前序,中序,后序法
百度:二叉树的深度优先遍历和广度优先遍历
小米面试手写判断一颗树是否为平衡二叉树(当时自己都不知道怎么用程序将二叉树构建出来...)
二叉树不能形成回路,如环状链表会造成回路现象,不符合树的定义
树在内存中的存储方式以链表为主,同样可以使用数组存储
二叉树的两个特殊情况:
①满二叉树:高度为h(高度肯定是包含根节点n)的树,其节点(所有点,包括根节点)个数为2^h-1(减1是因为根节点只有一个,而其他层都是2的次幂)
②完全二叉树:除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐
通过列表构建二叉树(首先都没二叉树就谈不上后面的操作了)
构建二叉树的方法很多:弄清楚通过列表是怎么构建出的二叉树(书本方法和博客方法不同)
二叉查找数:根值在左子树值和右子树值之间,左子树值<根值<右子树值
需要构造出2的幂次的数组,按照从上到下,从左到右的顺序,将二叉树的每个节点值依次加入到列表对应的索引处。如果二叉树某处不存在左节点或者右节点,则列表对应位置加入0(博客上都是用的“#”表示)
链表方法(首选方法):对于节点的增加和删除很容易,但很难找到父节点
1、返回树的最大深度
思路:
比较左子树和右子树的,获取最大值
递归+1向下迭代,直到返回空
传入参数为root,第二次迭代传入参数为root.left和root.right
class Node():
def __init__(self,val):
self.data=val
self.left=None
self.ringht=None
class solution:
def tree_deep(self,root):#会传入根节点
if root==None:
return 0
else:
l=1+self.tree_deep(root.left)#这里如果不加self,就无法调用tree_deep方法,去掉self后,tree_deep下后 红色波浪线
r=1+self.tree_deep(root.right)#不停迭代知道计算出结果
return max(l,r)
1、left,right都是自己定义的,也有定义成lchild和rchild的
2、程序执行过程
当执行到右子树的节点后,即不要考虑左边了,到第一个递归处,继续递归
2、二叉查找数/二叉搜索树(BST,binary search tree)
一个二叉搜索树具有如下特征:
•节点的左子树只包含小于当前节点的值。
•节点的右子树只包含大于当前节点的值。
•所有左子树和右子树自身必须也是二叉搜索树。
根据这个特征可以得出:二叉搜索树的中序遍历(左根右)是一个单调递增的序列,最小值一定在左子树的最左边叶子节点,最大值在右子树的最右边叶子节点
如果左子树还有一层,这个题目怎么理解?
class Solution:
def isValidBST(self, root):
def inorderTraversal(root):#构造二叉树的中序遍历
if root == None:
return []
res = []
res += inorderTraversal(root.left)#递归添加节点
res.append(root.val)
res += inorderTraversal(root.right)
return res
res = inorderTraversal(root)
if res != sorted(list(set(res))): #判断通过二叉树构造出来的中序遍历是否按照从小到大的顺序排列
return False
return True
先递归完再往下执行,有函数就先执行函数
这里是先添加左子树直到完毕再添加根节点和右子树
self.InOrder(root.left)
print(root.val, end=' ')
self.InOrder(root.right)
变形:将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树
class Node(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def sortedArrayToBST(self, nums):
#递归方法
if not nums:
return None
mid=len(nums)//2#找到中间节点
root=Node(nums[mid])#当前节点为根节点
root.left=self.sortedArrayToBST(nums[:mid])#小于当前根节点的作为左子树
root.right=self.sortedArrayToBST(nums[mid+1:])#大于当前根节点的作为右子树
return root
这里传入的是列表,先构建左子树再构建右子树(上面方法是添加的节点)
可以直接传入列表吗?
3、判断一棵树是否对称
注意对称的含义:
最左边和最右边相等self.isSame(p1.left, p2.right),传入的参数是p1的左和p2的右
递归的方法:类中包含判断函数,判断函数中包含递归函数(通常的写法套路)
class Solution:
def isSymmetrical(self, Root):
# write code here
def isSame(p1,p2):
if not p1 and not p2:#根节点左右没有子树
return True
if not p1 or not p2:
return False
if p1.val != p2.val:
return False
return self.isSame(p1.left, p2.right) and self.isSame(p1.right, p2.left)
if not Root:#不存在根节点
return True
return isSame(Root.left,Root.right)
4、判断一颗二叉树是否是平衡二叉树
①左右子树深度之差的绝对值不大于1
②左右子树都是平衡二叉树(通过递归对每个节点进行判断,若全部均未返回False,则返回True)
class Node():
def __init__(self,x):
self.val = x
self.left = None
self.right = None
# 递归求当前节点的深度
def depth(node):
if not node:
return 0
ld = depth(node.left)
rd = depth(node.right)
return max(ld, rd) + 1#这里的加1,是把父节点包括在内
def isBalance(root):
if root is None:
return True
ld = depth(root.left)
rd = depth(root.right)
if abs(ld - rd) > 1:
return False
return isBalance(root.left) and isBalance(root.right)
5、5种遍历:前中后序,深度优先,广度优先(每一种都要熟练掌握)
前序遍历:
递归调用:先打印根节点值,然后递归打印根节点的左子树的节点和右子树的界定啊,直到遍历到叶子节点(root=None,因为之前会有root.left,所以会有为None的情况)
self.PreOrder(root.left)函数一直递归,直到将左子树全部打印出来后才会向下执行
self.InOrder(root.left)当递归到root.left不存在,即root=None后,就会打印root节点的值
广度优先遍历
广度优先遍历函数传入根节点
将当前节点的左节点和右节点分别存入队列中
先弹出再加入,加入顶点,取出顶点,将与顶点相邻且未访问过的顶点加入队列,再重复上述过程(和图的思路过程是一样的),注意这里取的是队列的顶点,二深度优先遍历是取的栈顶元素(即可以看成是队列的尾部元素)
注:图和二叉树都存在深度优先遍历和广度优先遍历
按根的右子树和左子树的顺序存入栈中(按这个顺序的话,结果就是唯一的,之前这里不确定)
广度是pop(0),queue
深度是pop(),stack