226. 翻转二叉树
翻转一棵二叉树。
示例:
输入:
4 / \ 2 7 / \ / \ 1 3 6 9
输出:
4 / \ 7 2 / \ / \ 9 6 3 1
代码:
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
"""
采用递归的方法
"""
#一:确定递归的参数和返回值
def digui(root: TreeNode):
if root == None:
#二:确定递归停止的条件
return root
#开始交换左右节点
temp = root.left
root.left = root.right
root.right = temp
#三:确定单层递归的逻辑
digui(root.left)
digui(root.right)
digui(root)
return root
101. 对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树
[1,2,2,3,4,4,3]
是对称的。1 / \ 2 2 / \ / \ 3 4 4 3
但是下面这个
[1,2,2,null,3,null,3]
则不是镜像对称的:1 / \ 2 2 \ \ 3 3
代码:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
"""
思路一:直接翻转根节点左右子树--后面比较的时候比较麻烦,2个地址比较不对--放弃
"""
# left_tree = root.left
# right_tree = root.right
# """
# 翻转二叉树,用递归
# """
# def invertTree(root: TreeNode):
# if root == None:
# return root
# temp = root.left
# root.left = root.right
# root.right = temp
# invertTree(root.left)
# invertTree(root.right)
# invertTree(right_tree)
# print("left_tree",left_tree)
# print("right_tree",right_tree)
# if left_tree == right_tree:
# return True
# else:
# return False
"""
思路二:直接比较根节点的左右子树,本题遍历只能是“后序遍历”,因为我们要通过
递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。正是因为要遍历两
棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树
的遍历顺序是右左中。
"""
#1.确定递归函数的参数和返回值
def compare(left_root: TreeNode,right_root: TreeNode):
#2.确定终止条件----要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚
"""
左节点为空,右节点不为空,不对称,return false
左不为空,右为空,不对称 return false
左右都为空,对称,返回true
"""
if left_root == None and right_root != None:
return False
if left_root != None and right_root == None:
return False
if left_root == None and right_root == None:
return True
if left_root.val != right_root.val:
return False
#下面不能else-------------后面继续研究
#不能直接就返回True了
# else:
# return True
"""
此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:
左右都不为空,比较节点数值,不相同就return false
此时左右节点不为空,且数值也不相同的情况我们也处理了。
"""
#3.确定单层递归的逻辑
"""
比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
比较内测是否对称,传入左节点的右孩子,右节点的左孩子。
如果左右都对称就返回true ,有一侧不对称就返回false 。
"""
outside = compare(left_root.left,right_root.right)
inside = compare(left_root.right,right_root.left)
isSame = outside and inside
return isSame
if root == None:
return True
return compare(root.left,root.right)
104. 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树[3,9,20,null,null,15,7]
,3 / \ 9 20 / \ 15 7
返回它的最大深度 3 。
代码:
class Solution:
def maxDepth(self, root: TreeNode) -> int:
"""
和层次遍历很相关
"""
if root == None:
return 0
queue = [root]
out_list = []
while len(queue) > 0:
inner_list = []
lens = len(queue)
for _ in range(lens):
#遍历当前节点值
cur_node = queue.pop(0)
inner_list.append(cur_node.val)
#左右子节点都入队
if cur_node.left != None:
queue.append(cur_node.left)
if cur_node.right != None:
queue.append(cur_node.right)
out_list.append(inner_list)
return len(out_list)
559. N 叉树的最大深度
给定一个 N 叉树,找到其最大深度。
最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。
N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。
示例 1:
输入:root = [1,null,3,2,4,null,5,6] 输出:3
代码:
class Solution:
def maxDepth(self, root: 'Node') -> int:
"""
和层次遍历很相关----对于多叉树,就是将一个节点的
所有孩子节点都入队
"""
if root == None:
return 0
queue = [root]
out_list = []
while len(queue) > 0:
inner_list = []
lens = len(queue)
for _ in range(lens):
#遍历当前节点值
cur_node = queue.pop(0)
inner_list.append(cur_node.val)
#所有孩子节点都入队
for chil in cur_node.children:
queue.append(chil)
out_list.append(inner_list)
return len(out_list)
111. 二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
示例 1:
输入:root = [3,9,20,null,null,15,7] 输出:2
代码:
class Solution:
def minDepth(self, root: TreeNode) -> int:
"""
找到根节点的最小高度
"""
#1.确定递归函数的参数和返回值
def getDepth(root: TreeNode):
#2.确定终止条件---终止条件也是遇到空节点返回0,表示当前节点的高度为0。
if root == None:
return 0
#3.确定单层递归的逻辑
leftDepth = getDepth(root.left)
rightDepth = getDepth(root.right)
"""
注意:这种写法错误,假如根节点左子树为空,那么最小深度就成1啦,这是错误的
如果左子树为空,右子树不为空,说明最小深度是 1 + 右子树的深度。
反之,右子树为空,左子树不为空,最小深度是 1 + 左子树的深度。
最后如果左右子树都不为空,返回左右子树深度最小值 + 1 。
"""
#这里要考虑所有情况,不然就会空指针
if root.left == None and root.right != None:
return (1 + rightDepth)
if root.left != None and root.right == None:
return (1 + leftDepth)
if root.left == None and root.right == None:
return 1
if root.left != None and root.right != None:
return min(leftDepth,rightDepth)+1
return getDepth(root)
222. 完全二叉树的节点个数
给你一棵 完全二叉树 的根节点
root
,求出该树的节点个数。完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第
h
层,则该层包含1~ 2h
个节点。
示例 1:
输入:root = [1,2,3,4,5,6] 输出:6
代码:
class Solution:
def countNodes(self, root: TreeNode) -> int:
"""
还是采用递归,节点的个数===左节点的个数+右节点的个数+1
"""
#1.传入根节点
def get_nodes(root: TreeNode):
#2.终止条件
if root == None:
return 0
#3.代码逻辑
left_nodes = get_nodes(root.left)
right_nodes = get_nodes(root.right)
if root.left != None and root.right == None:
return 2
if root.left == None and root.right == None:
return 1
if root.left != None and root.right != None:
return 1+left_nodes+right_nodes
return get_nodes(root)
110. 平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
示例 1:
输入:root = [3,9,20,null,null,15,7] 输出:true
代码:
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
"""
同样采用递归来做,判断左右节点的深度差
求二叉树深度可以从上到下去查 所以需要前序遍历(中左右),
而二叉树高度只能从下到上去查,所以只能后序遍历(左右中)
"""
"""
此时大家应该明白了既然要求比较高度,必然是要后序遍历。
递归三步曲分析:
1. 明确递归函数的参数和返回值
参数的话为传入的节点指针,就没有其他参数需要传递了,返回值要返回传入节点为根节点树的深度。
那么如何标记左右子树是否差值大于1呢。
如果当前传入节点为根节点的二叉树已经不是二叉平衡树了,还返回高度的话就没有意义了。
所以如果已经不是二叉平衡树了,可以返回-1 来标记已经不符合平衡树的规则了。
2. 明确终止条件
递归的过程中依然是遇到空节点了为终止,返回0,表示当前节点为根节点的树高度为0
3. 明确单层递归的逻辑
如何判断当前传入节点为根节点的二叉树是否是平衡二叉树呢,当然是左子树高度和右子树高度相差。
分别求出左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则则返回-1,表示已经不是二叉树了。
"""
def Get_Deeps(root: TreeNode):
if root == None:
return 0
left_deep = Get_Deeps(root.left)#左
if left_deep == -1:
return -1
right_deep = Get_Deeps(root.right)#右
if right_deep == -1:
return -1
if left_deep != None and right_deep != -1:
sub_deep = abs(left_deep - right_deep)
if sub_deep > 1:
return -1
else:
#这里别忘了加1
return 1+max(left_deep,right_deep)
if Get_Deeps(root) == -1:
return False
else:
return True
257. 二叉树的所有路径
给定一个二叉树,返回所有从根节点到叶子节点的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
输入: 1 / \ 2 3 \ 5 输出: ["1->2->5", "1->3"] 解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
代码:
class Solution:
def binaryTreePaths(self, root: TreeNode) -> List[str]:
"""
还是使用递归
因为要寻找从根节点到叶子节点的路径,所有应该使用前序遍历,即先根节点的顺序
"""
"""
1.定义函数返回值和参数
参数:当前节点、应该记录走过的路径集合
返回值:不需要
"""
def get_paths(root: TreeNode,now_paths:list,all_paths:list):
"""
2.终止条件
即结束逻辑后要做的处理,这里只要判断当前节点是叶节点
就return,不用到空节点
"""
if root.left == None and root.right == None:
#当前节点是叶子节点
now_paths.append(str(root.val))
all_paths.append(now_paths.copy())
return
"""
3.逻辑语句:前序遍历
"""
#直接加入到路径中
now_paths.append(str(root.val))
#上面没有处理当前为None的逻辑,在这里处理
if root.left != None:
"""
回溯和递归是一一对应的,有一个递归,就要有一个回溯
"""
get_paths(root.left,now_paths,all_paths)
#退回上一步
now_paths.pop(-1)
if root.right != None:
get_paths(root.right,now_paths,all_paths)
now_paths.pop(-1)
now_paths = list()
all_paths = list()
get_paths(root,now_paths,all_paths)
"""
将路径封装成要求的形式
"""
res = list(map(lambda x:"->".join(x),all_paths))
return res
100. 相同的树
给你两棵二叉树的根节点
p
和q
,编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入:p = [1,2,3], q = [1,2,3] 输出:true
代码:
class Solution:
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
"""
同样使用递归
"""
def if_same(p: TreeNode, q: TreeNode):
#停止条件
if p == None and q != None:
return False
if p != None and q == None:
return False
if p == None and q == None:
#这里直接返回True了,没有调用,因为都是空节点了
#就不会再有子节点,也就不用再去判断了
return True
#遍历当前节点,且都不为空
#若不相等,直接返回False
if p.val != q.val:
return False
#若相等,还要看其子节点是否相等,后面就去递归
left_ifsame = if_same(p.left, q.left)
right_ifsame = if_same(p.right, q.right)
if left_ifsame and right_ifsame:
return True
else:
return False
return if_same(p, q)
404. 左叶子之和
计算给定二叉树的所有左叶子之和。
示例:
3 / \ 9 20 / \ 15 7 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24
代码:
class Solution:
def sumOfLeftLeaves(self, root: TreeNode) -> int:
"""
递归法:找到节点的左节点不为空,且该左节点的左右子节点都为空,
递归方法:知道左节点的左叶子之和、知道右节点的左叶子之和
最后才能知道以当前树的的所有左叶子之和。即根节点的所有左叶子之和
故:用后序遍历比较好
"""
def left_leaf_sum(root: TreeNode):
#2.0判断截止条件:
#找到节点的左节点不为空,且该左节点的左右子节点都为空,便停止
if root == None:
return 0
#3.0代码逻辑
"""
---------->对当前节点root而言,要处理的逻辑
"""
"""
这表示以当前节点的左子节点为根节点这棵树上所有左叶子之和
"""
left_leaf_leftS = left_leaf_sum(root.left)
"""
这表示以当前节点的右子节点为根节点这棵树上所有左叶子之和
"""
left_leaf_rightS = left_leaf_sum(root.right)
"""
在计算当前root节点的左右子节点是否含有左叶子节点
"""
now_nums = 0
if root.left != None and root.left.left == None and root.left.right == None:
now_nums = root.left.val
"""
当前root节点含有的总左叶子之和
"""
return left_leaf_leftS + left_leaf_rightS + now_nums
return left_leaf_sum(root)
513. 找树左下角的值
给定一个二叉树的 根节点
root
,请找出该二叉树的 最底层 最左边 节点的值。假设二叉树中至少有一个节点。
示例 1:
输入: root = [2,1,3] 输出: 1示例 2:
输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7
代码:
class Solution:
def findBottomLeftValue(self, root: TreeNode) -> int:
"""
方法一:用分层遍历的代码
"""
# if root == None:
# return []
# #把根节点放入队列中
# queue = [root]
# out_list = []
# while len(queue) > 0:
# #len = 1
# length = len(queue)
# in_list = []
# for _ in range(length):
# #取出根节点
# cur_node = queue.pop(0)
# in_list.append(cur_node.val)
# #若左子节点不为空
# if cur_node.left != None:
# queue.append(cur_node.left)
# if cur_node.right != None:
# queue.append(cur_node.right)
# out_list.append(in_list)
# return out_list[-1][0]
"""
方法二:用遍历的方法
找到树最深的那一层,且最左侧的那个节点,(用前序遍历)
还要用到回溯
"""
maxLen = 1
maxleftValue = root.val
def traversal(root: TreeNode,leftLen: int):
"""
nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量
"""
nonlocal maxLen, maxleftValue
#找到该节点了,看是否是叶节点
if root.left == None and root.right == None:
#中
if leftLen > maxLen:
maxLen = leftLen
maxleftValue = root.val
#左
if root.left != None:
leftLen += 1
traversal(root.left,leftLen)
#当该节点的子节点遍历结束-----回溯
leftLen -= 1
#右
if root.right != None:
leftLen += 1
traversal(root.right,leftLen)
#当该节点的子节点遍历结束-----回溯
leftLen -= 1
traversal(root,1)
return maxleftValue
112. 路径总和
给你二叉树的根节点
root
和一个表示目标和的整数targetSum
,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和targetSum
。叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22 输出:true
代码:
class Solution:
def hasPathSum(self, root: TreeNode, targetSum: int) -> bool:
"""
采用递归
"""
def path_sums(root: TreeNode, targetSum: int):
#代码终止条件
if root.left == None and root.right == None and targetSum == 0:
return True
if root.left == None and root.right == None and targetSum != 0:
return False
#左
if root.left != None:
targetSum -= root.left.val
#假如左子树已经符合条件,直接返回True
if path_sums(root.left,targetSum):
return True
#回溯
targetSum += root.left.val
#右
if root.right != None:
targetSum -= root.right.val
if path_sums(root.right,targetSum):
return True
#回溯
targetSum += root.right.val
#中
#上面都没return ,说明没找到
return False
if root == None:
return False
return path_sums(root, targetSum-root.val)
617. 合并二叉树
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
示例 1:
输入: Tree 1 Tree 2 1 2 / \ / \ 3 2 1 3 / \ \ 5 4 7 输出: 合并后的树: 3 / \ 4 5 / \ \ 5 4 7注意: 合并必须从两个树的根节点开始。
代码:
class Solution:
def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
#1.0参数、返回值
def mergeTrees(root1: TreeNode, root2: TreeNode) -> TreeNode:
#2.0终止条件
if root1 == None:
return root2
if root2 == None:
return root1
#3.0业务逻辑
#这是当前节点的新合并后的左子树
root_left = mergeTrees(root1.left,root2.left)
#这是当前节点的新合并后的右子树
root_right = mergeTrees(root1.right,root2.right)
root_val = (root1.val+root2.val)
root1.val = root_val
#当前节点的新左子节点是合并后的root_left
root1.left = root_left
#当前节点的新右子节点是合并后的root_left
root1.right = root_right
return root1
return mergeTrees(root1,root2)
700. 二叉搜索树中的搜索
给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。
例如,
给定二叉搜索树: 4 / \ 2 7 / \ 1 3 和值: 2你应该返回如下子树:
2 / \ 1 3
代码:
class Solution:
def searchBST(self, root: TreeNode, val: int) -> TreeNode:
# 方法一:使用二叉树的方法
def traversal(root: TreeNode):
if root == None:
return
if root.val == val:
return root
left_node = traversal(root.left)
right_node = traversal(root.right)
if left_node != None:
return left_node
if right_node != None:
return right_node
return traversal(root)
#方法二:使用二叉搜索树的方法
def traversal(root: TreeNode):
if root == None:
return
if root.val == val:
return root
if root.val > val:
#去左子树去找
return traversal(root.left)
if root.val <= val:
#去右子树去找
return traversal(root.right)
return traversal(root)
98. 验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
- 节点的左子树只包含小于当前节点的数。
- 节点的右子树只包含大于当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入: 2 / \ 1 3 输出: true
代码:
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
"""
要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列
"""
res = []
def traversal(root: TreeNode):
if root == None:
return
traversal(root.left)
res.append(root.val)
traversal(root.right)
traversal(root)
#判断一个列表是否是有序的
for i in range(len(res)-1):
if res[i] >= res[i+1]:
return False
return True
530. 二叉搜索树的最小绝对差
给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值。
示例:
输入: 1 \ 3 / 2 输出: 1 解释: 最小绝对差为 1,其中 2 和 1 的差的绝对值为 1(或者 2 和 3)。
代码:
class Solution:
def getMinimumDifference(self, root: TreeNode) -> int:
res = []
def traversal(root: TreeNode):
if root == None:
return
traversal(root.left)
res.append(root.val)
traversal(root.right)
traversal(root)
#统计一个有序列表的最小差值
all_subs = []
for i in range(len(res)-1):
all_subs.append(res[i+1]-res[i])
return min(all_subs)
501. 二叉搜索树中的众数
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
假定 BST 有如下定义:
- 结点左子树中所含结点的值小于等于当前结点的值
- 结点右子树中所含结点的值大于等于当前结点的值
- 左子树和右子树都是二叉搜索树
例如:
给定 BST[1,null,2,2]
,1 \ 2 / 2
返回[2]
.
代码:
class Solution:
def findMode(self, root: TreeNode) -> List[int]:
res = []
def traversal(root: TreeNode):
if root == None:
return
traversal(root.left)
res.append(root.val)
traversal(root.right)
traversal(root)
temp_set = {}
for val in res:
if val in temp_set:
temp_set[val] += 1
else:
temp_set[val] = 1
results = []
for key, value in temp_set.items():
if value == max(temp_set.values()):
results.append(key)
return results
236. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例 1:
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 输出:3 解释:节点5
和节点1
的最近公共祖先是节点3 。
代码:
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
"""
采用后续遍历
如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,
右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。
"""
#1.0 确定返回值及其参数
def recursion(root: 'TreeNode', p: 'TreeNode', q: 'TreeNode'):
#2.0 确定停止条件,或者找到p,q中的一个就去返回
if root == None or root == p or root == q:
return root
left_node = recursion(root.left,p,q)
right_node = recursion(root.right,p,q)
#3.0代码的逻辑
"""
---->如果left_node与right_node都不为空,说明该root就是要找的公共祖先
---->如果left_node不为空,而right_node为空,说明公共祖先位于root的左子节点上
---->如果left_node为空,而right_node不为空,说明公共祖先位于root的右子节点上
"""
if left_node != None and right_node != None:
return root
if left_node != None and right_node == None:
return left_node
if left_node == None and right_node != None:
return right_node
return recursion(root,p,q)
235. 二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 输出: 6 解释: 节点2
和节点8
的最近公共祖先是6。
代码:
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
"""
采用后续遍历
如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,
右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。
"""
#1.0 确定返回值及其参数
def recursion(root: 'TreeNode', p: 'TreeNode', q: 'TreeNode'):
#2.0 确定停止条件,或者找到p,q中的一个就去返回
if root == None or root == p or root == q:
return root
left_node = recursion(root.left,p,q)
right_node = recursion(root.right,p,q)
#3.0代码的逻辑
"""
---->如果left_node与right_node都不为空,说明该root就是要找的公共祖先
---->如果left_node不为空,而right_node为空,说明公共祖先位于root的左子节点上
---->如果left_node为空,而right_node不为空,说明公共祖先位于root的右子节点上
"""
if left_node != None and right_node != None:
return root
if left_node != None and right_node == None:
return left_node
if left_node == None and right_node != None:
return right_node
return recursion(root,p,q)