1. 程式人生 > >利用二叉樹的非遞迴後序遍歷求解最近公共祖先問題

利用二叉樹的非遞迴後序遍歷求解最近公共祖先問題

通過上一篇的部落格我們知道,可以利用棧來實現二叉樹的後序遍歷。其實這裡有一個性質,就是當使用非遞迴後序遍歷時,棧中的元素就是當前節點到根節點的路徑。利用這個規律,我們就可以求解最近公共最先問題了。

演算法

  1. 找出兩個節點各自到根節點的路徑。這裡利用非遞迴後序遍歷二叉樹,既可以找到兩個節點到根節點的路徑。
  2. 根據路徑找出最近的公共祖先。首先根節點肯定是他們的祖先,可以從跟節點開始查詢,直到最後一個相同的樹節點,就是他們的公共祖先了。

實現

///求兩個節點的最大公共祖先
void BiTree::ancestor(char A,char B){
    vector<BiNode *>
pathA,pathB; ///非遞迴後序遍歷 ///p表示當前樹節點指標, ///r表示最近訪問的樹節點指標 BiNode *p,*r; r = NULL; p = root; stack<BiNode*> my_stack; int pathCnt=0; while(p!=NULL || !my_stack.empty()){ if(p){ ///一直走到樹的最左邊 my_stack.push(p); p=p->lchild; } else
{ p=my_stack.top(); ///如果右子樹沒有遍歷,遍歷右子樹 if(p->rchild!=NULL && p->rchild!=r){ p=p->rchild; my_stack.push(p); ///注意這裡需要向左轉,因為如果不向左轉, ///將會遍歷右子樹節點兩邊 p=p->lchild; } ///否則遍歷根節點
else{ p=my_stack.top(); my_stack.pop(); ///記錄A的路徑 if(p->data==A){ cout<<"找到"<<A<<"的路徑:"<<endl; pathA.push_back(p); while(!my_stack.empty()){ p=my_stack.top(); my_stack.pop(); pathA.push_back(p); } ///恢復my_stack for(int i=pathA.size()-1;i>=0;i--){ cout<<pathA[i]->data<<' '; my_stack.push(pathA[i]); p=pathA[i]; } p=my_stack.top(); my_stack.pop(); cout<<endl; ///找到了一個節點的路徑 ++pathCnt; } ///記錄B的路徑 if(p->data==B){ cout<<"找到"<<B<<"的路徑:"<<endl; pathB.push_back(p); while(!my_stack.empty()){ p=my_stack.top(); my_stack.pop(); pathB.push_back(p); } ///恢復my_stack for(int i=pathB.size()-1;i>=0;i--){ cout<<pathB[i]->data<<' '; my_stack.push(pathB[i]); p=pathB[i]; } p=my_stack.top(); my_stack.pop(); cout<<endl; ///找到了另一個節點的路徑 ++pathCnt; } ///如果找到了兩個節點的路徑就不遍歷了 if(pathCnt==2) break; ///更新最近遍歷的節點 r=p; ///將遍歷後的節點設為NULL,進行下一個節點的遍歷 p=NULL; } } } BiNode *common_node; int i,j; i=pathA.size()-1; j=pathB.size()-1; while(i>=0 && j>=0 && pathA[i]==pathB[j]){ ///更新公共結點 common_node = pathA[i]; --i,--j; } cout<<"結點"<<A<<"和節點"<<B<<"的最近公共祖先是"<<common_node->data<<"。"<<endl; }

測試

#include <iostream>
#include "BiTree.h"
using namespace std;

int main()
{
    BiTree a;
    string s;
    s="ABD##E#F##C##";
    a.createBiTree(s);
    a.ancestor('D','D');
    cout<<"--------------------"<<endl;
    a.ancestor('D','F');
    cout<<"--------------------"<<endl;
    a.ancestor('D','C');
    cout<<"--------------------"<<endl;
    return 0;
}

這裡寫圖片描述

相關推薦

利用求解最近公共祖先問題

通過上一篇的部落格我們知道,可以利用棧來實現二叉樹的後序遍歷。其實這裡有一個性質,就是當使用非遞迴後序遍歷時,棧中的元素就是當前節點到根節點的路徑。利用這個規律,我們就可以求解最近公共最先問題了。 演算法 找出兩個節點各自到根節點的路徑。這裡利

【LeetCode-面試演算法經典-Java實現】【145-Binary Tree Postorder Traversal()】

原題   Given a binary tree, return the postorder traversal of its nodes’ values.   For exampl

演算法

與正常的非遞迴中序遍歷演算法不同於兩點: 一  比正常的中序遍歷演算法多了對資料元素的標記。        在壓資料元素入棧(標記記為0,用來表示訪問了其左子樹)時標記,       還有訪問完左子樹利用gettop()獲取雙親通過p=p->rchild進一步訪問右子

【leetcode】145Binary Tree Postorder Traversal(

二叉樹後序遍歷非遞迴方法很多書和部落格已經講的很清楚啦,這裡就是記錄一下方便自己日後看 基本思路是: 利用棧來實現 先找到最左節點,過程中的節點都入棧 如果該節點沒有右孩子或前一步訪問了右孩子(根據後序遍歷二叉樹的特點可以知道,如果當前節點有右孩子,則訪問當前節點前一定是

棧實現

#include "stdio.h" #include "stdlib.h" typedef struct TreeNode *Tree; typedef char ElementType; typedef struct stack *Stack; typedef Tree

java之中

思路:使用輔助棧改寫遞迴程式,中序遍歷沒有前序遍歷好寫,其中之一就在於入棧出棧的順序和限制規則。我們採用「左根右」的訪問順序可知主要由如下四步構成。 步驟: 1.首先需要一直對左子樹迭代並將非空節點入棧 2.節點指標為

的前中版本)

各位讀者週末愉快呀,今天我想來說說一道很常見的面試題目 —— 關於二叉樹前中後序遍歷的實現。本文將以遞迴和非遞迴方式實現這 3 種遍歷方式,程式碼都比較短,可以放心食用。 先簡單說明一下這 3 種遍歷方式有什麼不同 —— 對於每種遍歷,樹中每個結點都需要經過 3 次(對於葉結點,其左右子樹視為空子樹),但前

每日一題之 列印所有路徑

描述 給一個二叉樹,列印其所有路徑 思路: 利用後序非遞迴遍歷,因為後序非遞迴遍歷的特性,對於每次訪問的節點,棧裡面存的元素都是當前節點的祖先,所以只要判斷當前節點是不是葉子節點,如果是葉子節點,那麼將棧中元素取出,和當前葉子節點組成一條路徑。 #include <

的前中+

/** * 二叉樹節點類 * @author wj * */ class TreeNode{ int value; TreeNode left_Node; TreeNode right_Node; public TreeNode(int value) { this.value

的前中(&)

中序遞迴: class Solution { public: vector<int> res; vector<int> inorderTraversal(Tre

建立與

建立過程:通過棧來模擬遞迴建立。先將根壓入棧中,然後不斷的加左子樹,遇到空則加右子樹;在開始不斷的加左子樹...一直                     重複下去直到讀取到回車。(建立時

的前中(&)

中序遞迴: class Solution { public: vector<int> res; vector<int> inorderTraversal(TreeNode * root) { inorder(root);

、中

import java.util.Stack; class Solution {     private static void doPre(ListNode root) { &n

c語言實現連結串列)

演算法思想 因為後序遍歷是先訪問左子樹,再訪問右子樹,最後訪問根節點。當用棧實現遍歷時,必須分清返回根節點時,是從左子樹返回的還是從右子樹返回的。所以使用輔助指標r指向最近已訪問的結點。當然也可以在節點中增加一個標誌域,記錄是否已被訪問。 #include<iost

模板 先中演算法,層次,葉子結點數,深度

#include <iostream> #include<stdio.h> #include<malloc.h> #include<queue> #define MAX 50 using namespace std; type

資料結構----求的深度(

二叉樹為空:深度為0; 二叉樹為0:深度為1; 一般的二叉樹:深度=max{左子樹的深度,右子樹的深度} + 1。 int Depth (BiTree T) { if (!T)//如果二叉樹根節點為空,則深度為0 depthval=0; else {

的前中

本文介紹二叉樹的前序,中序和後序遍歷,採用遞迴和非遞迴兩種方式實現。除此之外,還介紹了對二叉樹按層遍歷的方法。對樹的前中後序遍歷是深度優先搜尋的策略,因此用棧實現。對樹的按層遍歷是廣度優先搜尋,因此採用佇列實現。 樹的前序,中序和後序遍歷,都是針對父節點而言的。 二叉樹的定

連結串列建立一棵並進行前中

原始碼:#include<iostream>using namespace std;typedef char Datatype;struct TNode{    Datatype data;    TNode* rchild;    TNode* lchild;}

資料結構-----演算法(利用堆疊實現)

一、非遞迴後序遍歷演算法思想 後序遍歷的非遞迴演算法中節點的進棧次數是兩個,即每個節點都要進棧兩次,第二次退棧的時候才訪問節點。 第一次進棧時,在遍歷左子樹的過程中將"根"節點進棧,待左子樹訪問完後,回溯的節點退棧,即退出這個"根"節點,但不能立即訪問,只能藉助於這個"根"

版的演算法

你會學到什麼? 樹的遞迴遍歷演算法很容易理解,程式碼也很精簡,但是如果想要從本質上理解二叉樹常用的三種遍歷方法,還得要思考樹的非遞迴遍歷演算法。 讀完後的收穫: 將學到二叉樹的後序遍歷的非遞迴版本 明白棧這種資料結構該怎麼使用 討論的問題是什麼?