数据结构 二叉树

 

目录:

一、层次遍历

1.1 求二叉树的最大高度(层次遍历,每返回到下一层时height+1);

1.2 最小高度(似最大高度,区别在于若该node是叶子节点,则立即返回)

1.3 求二叉树的最大宽度(在每一层的queue中,记录queue中的maxSize,代码略)

二、 通过前序+中序 或者中序+后续还原二叉树

 2.1 利用前序+中序还原二叉树

2.2 利用中序+后续还原二叉树

三、 求和

3.1 求所有叶结点数量

3.2 所有双分支结点书目

3.3 二叉树宽度第k层节点个数

四、一般二叉树的特殊情况

4.1 是否是同样的二叉树;

4.2 A是否是B的子树;

4.3 A和B是否是对称二叉树

4.4 由A就地(不创建新的二叉树)得到A的镜像二叉树

4.5 是否是完全二叉树

4.6 是否是满二叉树:

方法1:分别得到深度h和总结点数n,根据2^h-1=n判断是否是满二叉树

4.7 是否是二叉搜索树BST

4.8 是否是二叉平衡树AVL

五、路径问题

5.0 根节点到某一结点之间的路径:递归调用,路径结果以栈来保存

5.1 在二叉树中找出和为某一值x的某一路径:(前序遍历+递归调用,每一子节点调用x-父节点的值,如果相等则)

5.2 在二叉树中找出和为某一值x的所有路径。路径终点必须是叶节点(前序遍历+递归,每个子结点调用x-父节点val,若相等则输出,不等则退栈)

5.3 求二叉树两结点A和B的最低公共祖先:

递归法思路:先求出root到A的所有路径,保存在stack1中;再求出root到B的所有路径,保存在链表stack2中。求路径的方法参考算法5.0。接下来即是求stack1和stack2 依次pop的最后一个相等的结点。(栈顶为root,栈底分别为p1和p2)时间复杂度O(n),空间O(n)

迭代法思路:暂略。

5.4 求二叉树两节点A和B的路径:思路类似算法5.3, 也是先分别得到从root到A和从root到B的stack1和stack2,再公共结点S,则路径为A -> S ->B。

5.5 求二叉树两结点的最大距离。递归法


一、层次遍历

一般是:利用队列先进先出的特点,依次将结点的左、右孩子入队,然后依次出队访问,以此为循环。算法关键点有2个:1)定义两个计数器:一个记录本层结点数,一个记录下当前层下一层的结点数,这样遍历完一层后输出,然后转向下一层,并更新结点数。2)只需一个计数器,记录下当前行结点数,使用两层while循环结构,每访问完一个结点,计数器减1,直到该层中所有结点访问;然后访问下一行,并通过size()得到该行的结点数,以此进行循环。

应用:

1.1 求二叉树的最大高度(层次遍历,每返回到下一层时height+1);

1.2 最小高度(似最大高度,区别在于若该node是叶子节点,则立即返回)

1.3 求二叉树的最大宽度(在每一层的queue中,记录queue中的maxSize,代码略)

1. 1求二叉树高度(递归+非递归)

求二叉树的最大深度,也即其高度。

递归版本比较容易理解。利用层次遍历非递归求二叉树高度主要的思想是:一层一层地出队列 — 在我们每次访问完毕一层时,这时队列中存储的刚好是下一层的所有元素。所以在下一次循环开始时,首先记录该层的元素个数,一次性访问完这一层的所有元素。

class Solution {
public:
    int maxDepth(TreeNode* root) {
      //return maxDepthWithLevelTraversal(root);
      return maxDepthRecursion(root);
    }

    /* 递归版本 */
    int maxDepthRecursion(TreeNode* root){
       int HL, HR, MaxH;
       if (root){
           HL = maxDepth(root->left);
           HR = maxDepth(root->right);
           MaxH = (HL > HR) ? HL : HR;
           return MaxH + 1;
       }
       else 
           return 0;
    }

    /* 层次遍历的非递归版本 */
    int maxDepthWithLevelTraversal(TreeNode* root){
        /* 判断树是否为空 */
        if(!root){
            return 0;
        }

        int height = 0;    // 初始化树的高度为0

        queue<TreeNode*>Q;  // 初始化一个队列,并将根节点入队
        Q.push(root);

        /* 当队列不为空时 */
        /* 实际上当每次循环开始时,队列中存储的刚好是将要访问下一层的所有元素*/
        while(!Q.empty()){
            height++;
            int curLevelSize = Q.size();  // 记录当前层元素个数
            int cnt = 0;
            /* 弹出当前层所有元素 */
            while(cnt < curLevelSize){
                TreeNode* temp = Q.front();
                Q.pop();
                cnt++;
                /* 将下一层的元素入队列 */
                if(temp->left){
                    Q.push(temp->left);
                }
                if(temp->right){
                    Q.push(temp->right);
                }
            }
        }
        return height;
    }
};
--------------------- 
作者:liuchengxu_ 
来源:CSDN 
原文:https://blog.csdn.net/simple_the_best/article/details/52712892 
版权声明:本文为博主原创文章,转载请附上博文链接!

1.2 求二叉树最小高度(非递归)

这题是求二叉树的最小高度,与最大高度类似,不同之处在于层次遍历时,如果在该层遇到有叶子节点则立即返回,在进行层次遍历时需要进行叶子节点的判断。

class Solution {
public:
    int minDepth(TreeNode* root) {
        if(!root)
            return 0;

        queue<TreeNode*>Q;
        Q.push(root);

        int height = 0;

        while(!Q.empty()){
            height++;

            int curLevelSize = Q.size();
            int cnt = 0;

            while(cnt++ < curLevelSize){
                TreeNode *temp = Q.front();
                Q.pop();
                /* 此处比二叉树高度多了叶子节点的判断 */
                if(!temp->left && !temp->right)
                    return height;

                if(temp->left)
                    Q.push(temp->left);
                if(temp->right)
                    Q.push(temp->right);
            }
        }
        return height;
    }
};
--------------------- 
作者:liuchengxu_ 
来源:CSDN 
原文:https://blog.csdn.net/simple_the_best/article/details/52712892 
版权声明:本文为博主原创文章,转载请附上博文链接!

二、 通过前序+中序 或者中序+后续还原二叉树

根据三种遍历结点的顺序,我们可以得到只有前序遍历+中序遍历、中序遍历+后续遍历才能实现二叉树的构造,而前序遍历+后续遍历是不能构建二叉树的,因为,没法通过根结点的位置将左右子树分开。这两种方式构造二叉树的思路相同,都是先根据根结点确定左右子树,然后依次找到以每个结点的左右子树,递归实现构造二叉树,值得注意的,下标问题。Construct binary tree from preorder and inorder travesal Construct binary tree from inorder and postorder travesal 

 2.1 利用前序+中序还原二叉树

2.2 利用中序+后续还原二叉树

 2.1 利用前序+中序还原二叉树

class Solution {
11 public:
12     TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) 
13     {
14         int len=preorder.size();
15         return build(preorder,0,len-1,inorder,0,len-1);    
16     }
17 
18     TreeNode *build(vector<int> &preorder,int preBeg,int preEnd,vector<int> &inorder,int inBeg,int inEnd)
19     {
             // 递归终止条件
20         if(preBeg>preEnd||inBeg>inEnd)  
                return NULL;  

21         TreeNode *root=new TreeNode(preorder[preBeg]);
22 
23         for(int i=0;i<inorder.size();++i)
24         {
25             if(inorder[i]==preorder[preBeg])
26             {
                    // 递归建立左子树
27                 root->left=build(preorder,preBeg+1,preBeg+i-inBeg,inorder,inBeg,i-1);
28                 // 递归建立右子树
                   root->right=build(preorder,preBeg+i+1-inBeg,preEnd,inorder,i+1,inEnd);
29             }
30         }
31         return root;
32     }
33 };

2.2 利用中序+后续还原二叉树

利用中序和后序遍历构造二叉树,要注意到后序遍历的最后一个元素是二叉树的根节点,而中序遍历中,根节点前面为左子树节点后面为右子树的节点。例如二叉树:{1,2,3,4,5,6,#}的后序遍历为4->5->2->6->3->1;中序遍历为:4->2->5->1->6->3。

故,递归的整体思路是,找到根节点,然后遍历左右子树。这里有一个很重要的条件是:树中没有重复元素。

10 class Solution {
11 public:
12     TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) 
13     {
14         int len=inorder.size();
15         return build(inorder,0,len-1,postorder,0,len-1);    
16     }
17     TreeNode *build(vector<int> &inorder,int inBeg,int inEnd,vector<int> &postorder,int postBeg,int postEnd)
18     {
19         if(inBeg>inEnd||postBeg>postEnd)   
                 return NULL;
20         TreeNode *root=new TreeNode(postorder[postEnd]);
21 
22         for(int i=0;i<inorder.size();++i)
23         {
24             if(inorder[i]==postorder[postEnd])
25             {
26                 root->left=build(inorder,inBeg,i-1,postorder,postBeg,postBeg+i-1-inBeg);
27                 root->right=build(inorder,i+1,inEnd,postorder,postBeg+i-inBeg,postEnd-1);
28             }
29         }
30         return root;    
31     }
32 };

三、 求和

该类问题都可以通过2种方法加以解决:

    法1:递归+前序遍历

    法2:层序遍历,以层序遍历求二叉树的深度为模板,通过一个全局的累加遍历acc和每一层中的结点是否满足情况,对acc进行累加。

3.1 求所有叶结点数量

3.2 所有双分支结点书目

3.3 二叉树宽度第k层节点个数

3.1 求所有叶结点数量(递归+前序)

 

 

3.2 所有双分支结点书目(递归+前序)

 

 

3.3 二叉树宽度第k层节点个数

(法1:递归;法2:迭代+层次遍历(迭代法求二叉树深度类似))

法1(递归):
(1)如果二叉树为空或者k<1返回0
(2)如果二叉树不为空并且k==1,返回1
(3)如果二叉树不为空且k>1,返回左子树中k-1层的节点个数与右子树k-1层节点个数之和
参考代码如下:

int GetNodeNumKthLevel(BinaryTreeNode * pRoot, int k)  
{  
    if(pRoot == NULL || k < 1)  
        return 0;  
    if(k == 1)  
        return 1;  
    int numLeft = GetNodeNumKthLevel(pRoot->m_pLeft, k-1); // 左子树中k-1层的节点个数  
    int numRight = GetNodeNumKthLevel(pRoot->m_pRight, k-1); // 右子树中k-1层的节点个数  
    return (numLeft + numRight);  
}  
--------------------- 
作者:艾阳丶 
来源:CSDN 
原文:https://blog.csdn.net/csdn_aiyang/article/details/73187533 
版权声明:本文为博主原创文章,转载请附上博文链接!

四、一般二叉树的特殊情况

4.1 是否是同样的二叉树;

4.2 A是否是B的子树;

4.3 A和B是否是对称二叉树

4.4 由A就地(不创建新的二叉树)得到A的镜像二叉树

4.5 是否是完全二叉树

4.6 是否是满二叉树:

方法1:分别得到深度h和总结点数n,根据2^h-1=n判断是否是满二叉树

4.7 是否是二叉搜索树BST

4.8 是否是二叉平衡树AVL

 

4.1是否是同样的二叉树

法1:递归法+前序遍历次序

按照前序遍历次序对每个结点依次比较和调用,递归基和递归体见作业本。

bool isSame(TreeNode* root1,TreeNode* root2){

        if(root1==NULL && root2==NULL) return true;
        if((root1==NULL && root2!=NULL) || (root1!=NULL && root2==NULL)) return false;

        if(root1->val!=root2->val) return false;
        return isSame(root1->left,root2->left) && isSame(root1->right,root2->right);
}
--------------------- 
作者:zqxN 
来源:CSDN 
原文:https://blog.csdn.net/zqxnum1/article/details/48352465 
版权声明:本文为博主原创文章,转载请附上博文链接!

法2:迭代法+层次遍历

使用两队列,按照层次遍历的方式,两二叉树的左右孩子的入队顺序相同。

注意:此处与之前的层次遍历的区别在于,此处node的左右孩子即使是null也进入队列。队列每次pop的元素要进行data的比较和是否是null的比较。

	private static boolean getTreeNodeIsSame(TreeNode r1, TreeNode r2) {
		if(r1 == null && r2 == null){
			return true;
		}
        // r1,r2一个为null,一个非null
        else if(r1 == null || r2 == null){
			return false;
		}
        // 2个比较队列
		Queue<TreeNode> q1 = new LinkedList<TreeNode>();
		Queue<TreeNode> q2 = new LinkedList<TreeNode>();
		q1.add(r1);
		q2.add(r2);
		while(!q1.isEmpty() && !q2.isEmpty()){
			TreeNode current1 = q1.remove();
			TreeNode current2 = q2.remove();
            // 2结点都为null
			if(current1 ==null && current2==null){   
				continue;
			}
            // 2个都非null且值相等,则2个结点的左右孩子都进栈(不判断左右孩子是否存在)
            else if(current1 !=null && current2 != null && current1.data == current2.data){           
				q1.add(current1.leftChild);   
				q1.add(current1.rightRight);
				q2.add(current2.leftChild);
				q2.add(current2.rightRight);
			}else{
				return false;
			}
		}
		return true;
	}

--------------------- 
作者:猛龙过蒋 
来源:CSDN 
原文:https://blog.csdn.net/jcm666666/article/details/52555159 
版权声明:本文为博主原创文章,转载请附上博文链接!

4.2 A是否是B的子树

递归+前序遍历,判断root1 的每个结点是否和root2是否相等,即isSame()的变种

/**
     * 判断 以root2为根的树是否是 root1 为根的树 的 子树
     * @param root1
     * @param root2
     * @return
     */
    public boolean isSubTree(BinaryNode<T> root1, BinaryNode<T> root2){
        boolean result = false;
        
        //只有root1 和 root2 都不为空时,才去判断.其他情况root2都不是root1的子树
        if(root1 != null && root2 != null){
            if(root1.data == root2.data)
                result = isSame(root1, root2);
            if(!result)
                result = isSubTree(root1.left, root2);//递归遍历左子树
            if(!result)
                result = isSubTree(root1.right, root2);//递归遍历右子树
        }
        return result;
    }

 

4.3 是否是对称二叉树

若以结点p为根的二叉树对称,即p.right和p.left是相等的,即对root的left和right调用isSame(TNode p.left, TNode right)。

bool isSymmetric(TreeNode* root) {

        if(!root) return true;
        return isSame(root->left,root->right);

}

--------------------- 
作者:zqxN 
来源:CSDN 
原文:https://blog.csdn.net/zqxnum1/article/details/48352465 
版权声明:本文为博主原创文章,转载请附上博文链接!

4.4 构建镜像二叉树

递归解法:
(1)如果二叉树为空,返回空
(2)如果二叉树不为空,求左子树和右子树的镜像,然后交换左子树和右子树
参考代码如下:

4.5 是否是完全二叉树:

按照层次遍历的算法,将p和p的左右孩子加入队列(包括null)。对于完全二叉树,出队时null结点后的所有结点应当都为null。若存在null结点后非null,则该数是非完全二叉树。

public static boolean isComplete(TNode root){
    Queue q = new Queue();
    Tnode p;
    // 空树是完全二叉树
    if(q == null){
        return true;
    }
    q.enQueue(root);
    // 队列q非空时执行循环
    while(! q.isEmpty()){
        p = q.deQueue();
        // p结点非空,则左右孩子入队
        if(p != null){
            q.enQueue(p.left);
            q.enQueue(p.right);
        }
        // p==null,检查q里是否还有非空结点
        else{
           while(!q.isEmpty()){
               p = q.deQueue();
               if(p !=null)  // 结点非空,为非完全二叉树
                 return false;
            }

        }
    }
}

 

4.7 是否是二叉搜索树

紧紧的围绕搜索二叉树的中序遍历是非降序列来解题。

方法1:定义一个指针指向当前结点的前一个结点,利用二叉树中序遍历的思路,将两者的值进行比较,只要前者大于后者就不是搜索二叉树    ;空间复杂度O(1)

方法2:可以将利用中序遍历将二叉树结点值都存入一个数组中,然后遍历数组看是否为非降序型;空间复杂度O(n)

方法1实现:


public class Main {
	static int lastNodeValue = Integer.MIN_VALUE;
	public static boolean isSearchBTree(TreeNode root) {
        // 递归终止情况
		if(root == null)
            return true;
        // 判断左子树
		if(!isSearchBTree(root.left))
            return false ;
        // 判断是该结点是否小于终于遍历上一个访问的结点(因为中序遍历必须是降序)
		if(root.val<=lastNodeValue)
            return false;
		lastNodeValue = root.val;  // 更新lastNodeValue
        // 判断右子树
		if(!isSearchBTree(root.right))
            return false ;
		return true;
	}
--------------------- 
作者:YeBobr 
来源:CSDN 
原文:https://blog.csdn.net/YeBobr/article/details/79992003 
版权声明:本文为博主原创文章,转载请附上博文链接!

方法2实现:

	// 根据中序遍历结果判断是否是搜索二叉树
	public static boolean isSearchBTree(TreeNode root) {
		ArrayList<Integer> list = new ArrayList<>();
		convertBTreeToList(root, list);
		if(list.size() <=1)return true;
		for(int i = 1; i < list.size();i++){
			if(list.get(i)<list.get(i-1))
				return false;
		}
		return true;
	}
    //中序遍历结果用list保存
	public static void convertBTreeToList(TreeNode root, ArrayList<Integer> list) {
		if(root == null)return;
		if(root.left != null)convertBTreeToList(root.left, list);
		list.add(root.val);
		if(root.right != null)convertBTreeToList(root.right, list);
	}
--------------------- 
作者:YeBobr 
来源:CSDN 
原文:https://blog.csdn.net/YeBobr/article/details/79992003 
版权声明:本文为博主原创文章,转载请附上博文链接!

 

4.8 否是平衡二叉树

法1:后续遍历,相对法2比较节省时间。每个从下到上返回的不仅有true 或者false,还有Integer 最大高度对象

bool IsBalanced(BinaryTreeNode* pRoot)
{
   Integer pDepth = new Integer(0);
   return IsBalanced(pRoot, pDepth);
}

// c中此处对整数的指针,可以用Java的Integer对象代替。
bool IsBalanced(BinaryTreeNode* pRoot, Integer pDepth)
{
     if(pRoot == NULL)
     {
           pDepth = 0;
           return true;
     }

     Integer left, right;
     if(IsBalanced(pRoot->m_pLeft, left) && IsBalanced(pRoot->m_pRight, right))
     {
           int diff = left - right;
           if(diff <= 1 && diff >= -1)
           {
                 pDepth = 1 + (left > right ? left : right);
                 return true;
           }
     }

     return false;
}

法2:先编写一个计算二叉树深度的函数GetDepth,利用递归实现;然后再递归判断每个节点的左右子树的深度是否相差1

缺点:由于是从上到下遍历,故造成了大量的重复计算 

static int GetDepth(BinNode root)
{
if (root == null)
return 0;
int leftLength = GetDepth(root.Left);
int rightLength = GetDepth(root.Right);
return (leftLength > rightLength ? leftLength : rightLength) + 1;
}
 

注意这里的+1,对应于root不为空(算作当前1个深度)

static bool IsBalanceTree(BinNode root)
{
if (root == null)
return true;
int leftLength = GetDepth(root.Left);
int rightLength = GetDepth(root.Right);
int distance = leftLength > rightLength ? leftLength - rightLength : rightLength - leftLength;

if (distance > 1)
return false;
else 
        return IsBalanceTree(root.Left) && IsBalanceTree(root.Right);
}

 

五、路径问题

5.0 根节点到某一结点之间的路径:递归调用,路径结果以栈来保存

5.1 在二叉树中找出和为某一值x的某一路径:(前序遍历+递归调用,每一子节点调用x-父节点的值,如果相等则)

5.2 在二叉树中找出和为某一值x的所有路径。路径终点必须是叶节点(前序遍历+递归,每个子结点调用x-父节点val,若相等则输出,不等则退栈)

5.3 求二叉树两结点A和B的最低公共祖先

递归法思路:先求出root到A的所有路径,保存在stack1中;再求出root到B的所有路径,保存在链表stack2中。求路径的方法参考算法5.0。接下来即是求stack1和stack2 依次pop的最后一个相等的结点。(栈顶为root,栈底分别为p1和p2)时间复杂度O(n),空间O(n)

迭代法思路:暂略。

5.4 求二叉树两节点A和B的路径:思路类似算法5.3, 也是先分别得到从root到A和从root到B的stack1和stack2,再公共结点S,则路径为A -> S ->B。

5.5 求二叉树两结点的最大距离。递归法

5.0 根节点到某一结点之间的路径

递归调用,路径结果以栈来保存

// 栈底node, 栈顶root
static bool GetPositionByNode(BinNode root, BinNode node, ref Stack stack)
{
    // 递归终止条件1 结点为空
if (root == null)
    return false;

// 递归终止条件2: 结点相等
if (root == node){
    stack.Push(root);
    return true;
}
bool ret1 = GetPositionByNode(root.Left, node, ref stack);
bool ret2 = GetPositionByNode(root.Right, node, ref stack);
if (ret1 || ret2){
        stack.Push(root);
        return true;
}
// 否则return false
return false;
}

5.1 在二叉树中找出和为某一值x的某一路径

递归调用,只找到一层即可

bool hasPathSum(TreeNode *root, int sum) {
    // 空树 
    if (root == NULL)
        return false;
    // 判断是否是叶子节点
    else if (root->left == NULL && root->right == NULL && root->val == sum)
        return true;
    //  递归调用左右子树
    else {
        return hasPathSum(root->left, sum-root->val) || hasPathSum(root->right, sum - root->val);
    }
}

5.2   在二叉树中找出和为某一值x的所有路径,路径终点必须是叶节点

ref:http://www.cnblogs.com/edisonchou/p/4787736.html

递归实现

  (1)当用前序遍历的方式访问到某一结点时,我们把该结点添加到路径上,并累加该结点的值。

  (2)如果该结点为叶结点并且路径中结点值的和刚好等于输入的整数,则当前的路径符合要求,我们把它打印出来。如果当前结点不是叶结点,则继续访问它的子结点。

  (3)当前结点访问结束后,递归函数将自动回到它的父结点。这里要注意的是:在函数退出之前要在路径上删除当前结点并减去当前结点的值,以确保返回父结点时路径刚好是从根结点到父结点的路径。

    public static void FindPath(BinaryTreeNode root, int expectedSum)
    {
        if (root == null)
        {
            return;
        }

        int currentSum = 0;
        List<int> path = new List<int>();
        FindPath(root, expectedSum, path, ref currentSum);
    }

    private static void FindPath(BinaryTreeNode root, int expectedSum, List<int> path, ref int currentSum)
    {
        currentSum += root.Data;
        path.Add(root.Data);
        // 如果是叶结点,并且路径上结点的和等于输入的值
        // 打印出这条路径
        bool isLeaf = root.leftChild == null && root.rightChild == null;
        if (isLeaf && currentSum == expectedSum)
        {
            foreach (int data in path)
            {
                Console.Write("{0}\t", data);
            }
            Console.WriteLine();
        }

        // 如果不是叶结点,则遍历它的子结点
        if (root.leftChild != null)
        {
            FindPath(root.leftChild, expectedSum, path, ref currentSum);
        }

        if (root.rightChild != null)
        {
            FindPath(root.rightChild, expectedSum, path, ref currentSum);
        }

        // 在返回到父结点之前,在路径上删除当前结点,
        // 并在currentSum中减去当前结点的值
        path.Remove(root.Data);
        currentSum -= root.Data;
    }

5.3 求二叉树两节点的最近公共祖先

// 求结点root分别到A和B的路径,存在stack中
static bool GetPositionByNode(BinNode root, BinNode node, ref Stack stack)
{
if (root == null)
return false;
if (root == node)
    {
        stack.Push(root);
return true;
    }
if (GetPositionByNode(root.Left, node, ref stack) || GetPositionByNode(root.Right, node, ref stack))
    {
        stack.Push(root);
return true;
    }
return false;
}

// 根据stack寻找最近共同祖先
static BinNode FindParentNode(BinNode root, BinNode node1, BinNode node2)
{
Stack stack1 = new Stack();
    GetPositionByNode(root, node1, ref stack1);
Stack stack2 = new Stack();
    GetPositionByNode(root, node2, ref stack2);
BinNode tempNode = null;
while (stack1.Peek() == stack2.Peek())
    {
        tempNode = (BinNode)stack1.Pop();
        stack2.Pop();
    }
return tempNode;
}

 

5.5 求二叉树中两节点间的最大距离 

分析可知:对于二叉树,若要两个节点U,V相距最远,有两种情况:

情况A: 路径经过左子树的最深节点,通过根节点,再到右子树的最深节点。
情况B: 路径不穿过根节点,而是左子树或右子树的最大距离路径,取其大者

对于情况A来说,只需要知道左右子树的深度,然后加起来即可。

对于情况B来说,需要知道左子树的最远距离,右子树的最远距离。

算法如下:每个结点增加左子树最长距离和右子树最长距离变量, 递归遍历从叶节点到根节点的左右子树最长变量,并且过程中始终把左右子树最长距离的和与全局静态变量maxLen进行比较,并实时更新。


typedef struct Node {
    struct Node *pleft;     //左孩子
    struct Node *pright;    //右孩子
    char chValue;           //该节点的值
 
    int leftMaxValue;       //左子树最长距离
    int rightMaxValue;      //右子树最长距离
}LNode, *BinTree;
 
void findMaxLen(BinTree root, int *maxLen) {
    //遍历到叶子结点,返回
    if(root == NULL)
        return;
 
    //如果左子树为空,那么该节点左边最长距离为0
    if(root->pleft == NULL)
        root->leftMaxValue = 0;
 
    //如果右子树为空,那么该节点右边最长距离为0
    if(root->pright == NULL)
        root->rightMaxValue = 0;
 
    //如果左子树不为空,递归寻找左子树最长距离
    if(root->pleft != NULL)
        findMaxLen(root->pleft, maxLen);
 
    //如果右子树不为空,递归寻找右子树最长距离
    if(root->pright != NULL)
        findMaxLen(root->pright, maxLen);
 
    //计算左子树中距离根节点的最长距离
    if(root->pleft != NULL) {
        if(root->pleft->leftMaxValue > root->pleft->rightMaxValue)
            root->leftMaxValue = root->pleft->leftMaxValue + 1;
        else
            root->leftMaxValue = root->pleft->rightMaxValue + 1;
    }
 
    //计算右子树中距离根节点的最长距离
    if(root->pright != NULL) {
        if(root->pright->leftMaxValue > root->pright->rightMaxValue)
            root->rightMaxValue = root->pright->leftMaxValue + 1;
        else
            root->rightMaxValue = root->pright->rightMaxValue + 1;
    }
 
    //更新最长距离
    if(root->leftMaxValue + root->rightMaxValue > *maxLen)
        *maxLen = root->leftMaxValue + root->rightMaxValue;
}

--------------------- 
作者:CaryaLiu 
来源:CSDN 
原文:https://blog.csdn.net/caryaliu/article/details/8107089 
版权声明:本文为博主原创文章,转载请附上博文链接!

 

 

 

  • 法2:

    算法思路:先编写一个计算二叉树深度的函数GetDepth,利用递归实现;然后再递归判断每个节点的左右子树的深度是否相差1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值