问答题 7.  对于一棵给定的排序二叉树,求两个结点的共同父结点,例如在下图中,结点1和结点5的共同父结点为3。
   
【正确答案】方法一:路径对比法
   对于一棵二叉树的两个结点,如果知道了从根结点到这两个结点的路径,就可以很容易地找出它们最近的公共父结点。因此,可以首先分别找出从根结点到这两个结点的路径(例如上图中从根结点到结点1的路径为6->3->2->1,从根结点到结点5的路径为6->3->5);然后遍历这两条路径,只要是相等的结点都是它们的父结点,找到最后一个相等的结点即为离它们最近的共同父结点,在这个例子中,结点3就是它们共同的父结点。示例代码如下:
   class BiTNode:
   def __init__(self):
   self.data=None
   self.lchild=None
   self.rchild=None
   
   class stack:
   #模拟栈
   def __init__(self):
   self.items=[]
   #判断栈是否为空
   def isEmpty(self):
   return len(self.items)==0
   #返回栈的大小
   def size(self):
   return len(self.items)
   #返回栈顶元素
   def peek(self):
   if not self.isEmpty():
   return self.items[len(self.items)-1]
   else:
   return None
   #弹栈
   def pop(self):
   if len(self.items)>0:
   return self.items.pop()
   else:
   print "栈已经为空"
   return None
   #压栈
   def push(self,item):
   self.items.append(item)
   """
   方法功能: 获取二叉树从根结点root到node结点的路径
   输入参数: root:根结点; node:二叉树中的某个结点; s:用来存储路径的栈返回值: node在root的予树上, 或node==root时返回true, 否则返回false
   """
   def getPathFromRoot(root,node,s):
   if root==None:
   return False
   if root==node:
   s.push(root)
   return True
   """
   如果node结点在root结点的左予树或右子树上,
   那么root就是node的祖先结点, 把它加到栈里
   """
   if getPathFromRoot(root.lchild, node,s) or getPathFromRoot(root.rchild, node,s):
   s.push(root)
   return True
   return False
   """
   方法功能: 查找二叉树中两个结点最近的共同父结点
   输入参数: root:根结点;node1与node2为二叉树中两个结点
   返回值: node1与node2最近的共同父结点
   """
   def FindParentNode(root,node1,node2):
   stack1=stack() #保存从root到node1的路径
   stack2=stack()# 保存从root到node2的路径
   #获取从root到node1的路径
   getPathFromRoot(root, node1,stack1)
   #获取从root到node2的路径
   getPathFromRoot(root, node2, stack2)
   commonParent=None
   #获取最靠近node1和node2的父结点
   while stackl.peek()==stack2.peek():
   commonParent=stack1.peek()
   stack1.pop()
   stack2.pop()
   return commonParent
   
   if __name__=="__main__":
   arr=[1,2,3,4,5,6,7,8,9,10]
   root=arraytotree(arr,0,len(arr)-1)
   node1=root.lchild.lchild.lchild
   node2=root.lchild.rchild
   res=None
   res=FindParentNode(root,node1,node2)
   if res!=None:
   print str(node1.data)+"与"+str(node2.data)+"的最近公共父结点为:"+str(res.data),
   else:
   print "没有公共父结点"
   程序的运行结果为:
   1与5的最近公共父结点为:3
   算法性能分析:
   当获取二叉树从根结点root到node结点的路径时,最坏的情况就是把树中所有结点都遍历了一遍,这个操作的时间复杂度为O(N),再分别找出从根结点到两个结点的路径后,找它们最近的公共父结点的时间复杂度也为O(N),因此,这种方法的时间复杂度为O(N)。此外,这种方法用栈保存了从根结点到特定结点的路径,在最坏的情况下,这个路径包含了树中所有的结点,因此,空间复杂度也为O(N)。
   很显然,这种方法还不够理想。下面介绍另外一种能降低空间复杂度的方法。
   方法二:结点编号法
   根据性质,可以把二叉树看成是一棵完全二叉树(不管实际的二叉树是否为完全二叉树,二叉树中的结点都可以按照完全二叉树中对结点编号的方式进行编号),下图为对二叉树中的结点按照完全二叉树中结点的编号方式进行编号后的结果,结点右边的数字为其对应的编号。
   
【答案解析】[考点] 如何找出排序二叉树上任意两个结点的最近共同父结点