第4章第1節練習題11 查詢最近公共祖先節點
問題描述
假設指標p和指標q分別指向二叉樹中任意兩個節點的指標,試編寫演算法找到p和q的最近公共祖先節點r
演算法思想
因為計算的是公共祖先節點,因此可以考慮使用非遞迴後序遍歷的思想。在非遞迴後序遍歷的演算法實現中,棧裡面存放了即將入棧的元素的所有祖先節點。
為了方便表示說明,這裡使用下圖所描述的二叉樹來說明。
假設指標p指向節點E,指標q指向節點G。
- 按照正常的非遞迴後序遍歷演算法進行遍歷,即藉助棧
S
完成;- 當遍歷到節點E時,將此時棧
S
中的元素複製到臨時棧S1
中。此時棧S1
中的所有元素便為節點E的全部祖先節點;- 當編列到節點G時,將此時棧
S
中的元素複製到臨時棧S2
中。此時棧S2
中的所有元素便為節點G的全部祖先節點;- 最後在分別按照從棧頂到棧底的順序尋找棧
S1
和棧S2
中的公共因子便可,第一個匹配到的便是節點E和節點G的最近公共祖先節點。
演算法描述
void PostOrder(BiTNode* T)
{
BiTNode *p=T;
BiTNode *r=NULL;
SqStack S;
InitStack(&S);
SqStack S1;
InitStack(&S1);
SqStack S2;
InitStack(&S2);
int flag=1;
while(IsEmptyStack(&S)!=0||p!=NULL){
if(p){
Push(&S,p);
p=p->lchild;
}else{
p=GetTop(&S);
if(p->data=='E'){
for(int i=0;i<=S.top;i++){
S1.data[i]=S.data[i];
S1.top=S.top;
}
}
if (p->data=='G'){
for(int i=0;i<=S.top;i++){
S2.data[i]=S.data[i];
S2.top=S.top;
}
}
if(p->rchild!=NULL&&p->rchild!=r){
p=p->rchild;
Push(&S,p);
p=p->lchild;
}else{
p=Pop(&S);
if(IsEmptyStack(&S1)!=0&&IsEmptyStack(&S2)!=0){
for(int i=S1.top;i>-1&&flag;i--){
for(int j=S2.top;j>-1;j--){
if(S1.data[i]==S2.data[j]){
printf("%c",S1.data[i]->data);
flag=0;
}
}
}
}
r=p;
p=NULL;
}
}
}
}
具體程式碼見附件。
附件
//AB#DF##G##C#E##
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 100
//---------------------------------------------------------------------
typedef char ElemType;
typedef struct BiTNode{
ElemType data;
struct BiTNode *lchild, *rchild;
}BiTNode,*BiTree;
typedef struct{
BiTNode* data[MaxSize];
int top;
}SqStack;
void InitStack(SqStack*);
void Push(SqStack*,BiTNode*);
BiTNode* Pop(SqStack*);
BiTNode* GetTop(SqStack*);
int IsEmptyStack(SqStack*);
BiTree CreateBiTree(BiTNode*);
void PostOrder(BiTNode*);
//---------------------------------------------------------------------
int main(int argc,char* argv[])
{
BiTNode *T;
T=(BiTNode*)malloc(sizeof(BiTNode));
T=CreateBiTree(T);
PostOrder(T);
printf("\n");
return 0;
}
//---------------------------------------------------------------------
BiTree CreateBiTree(BiTNode* T)
{
ElemType x;
scanf("%c",&x);
if(x=='#'){
return T=NULL;
}else{
T=(BiTNode*)malloc(sizeof(BiTNode));
T->data=x;
T->lchild=CreateBiTree(T->lchild);
T->rchild=CreateBiTree(T->rchild);
}
return T;
}
void PostOrder(BiTNode* T)
{
BiTNode *p=T;
BiTNode *r=NULL;
SqStack S;
InitStack(&S);
SqStack S1;
InitStack(&S1);
SqStack S2;
InitStack(&S2);
int flag=1;
while(IsEmptyStack(&S)!=0||p!=NULL){
if(p){
Push(&S,p);
p=p->lchild;
}else{
p=GetTop(&S);
if(p->data=='E'){
for(int i=0;i<=S.top;i++){
S1.data[i]=S.data[i];
S1.top=S.top;
}
}
if(p->data=='G'){
for(int i=0;i<=S.top;i++){
S2.data[i]=S.data[i];
S2.top=S.top;
}
}
if(p->rchild!=NULL&&p->rchild!=r){
p=p->rchild;
Push(&S,p);
p=p->lchild;
}else{
p=Pop(&S);
if(IsEmptyStack(&S1)!=0&&IsEmptyStack(&S2)!=0){
for(int i=S1.top;i>-1&&flag;i--){
for(int j=S2.top;j>-1;j--){
if(S1.data[i]==S2.data[j]){
printf("%c",S1.data[i]->data);
flag=0;
}
}
}
}
r=p;
p=NULL;
}
}
}
}
//---------------------------------------------------------------------
void InitStack(SqStack* S){
S->top=-1;
}
void Push(SqStack* S,BiTNode* T){
if(S->top==MaxSize-1){
return;
}
S->data[++S->top]=T;
}
BiTNode* Pop(SqStack* S){
if(S->top==-1){
return NULL;
}
return S->data[S->top--];
}
BiTNode* GetTop(SqStack* S){
if(S->top==-1){
return NULL;
}
return S->data[S->top];
}
int IsEmptyStack(SqStack* S){
if(S->top==-1){
return 0;
}else{
return -1;
}
}
相關推薦
第4章第1節練習題11 查詢最近公共祖先節點
問題描述 假設指標p和指標q分別指向二叉樹中任意兩個節點的指標,試編寫演算法找到p和q的最近公共祖先節點r 演算法思想 因為計算的是公共祖先節點,因此可以考慮使用非遞迴後序遍歷的思想。在非遞迴後序遍歷的演算法實現中,棧裡面存放了即將入棧的元素
第4章第1節練習題8 列印指定節點的祖先節點
問題描述 在二叉樹中查詢值為x的節點,試編寫演算法列印值為x的節點的所有祖先節點,假設值為x的節點不多於一個 演算法思想 因為僅僅只是列印祖先節點,可以考慮使用非遞迴後序遍歷的方式來實現。 在非遞迴後序遍歷的方式中,保留在棧中的所有
第4章第1節練習題4 二叉樹高度和寬度統計
為了方便說明二叉樹的遞迴傳值過程,這裡首先給出一個基本的二叉樹結構。 圖中值為NULL的節點實際是不存在的,故與父親節點之間的連線用灰色的虛線表示。只是為了便於說明,才假設了一個NULL的空節點。 以下圖中,黃色的線表明了傳值的方向;綠色的數值表明了子節
第4章第1節練習題2 二叉樹的基本操作(非遞迴實現)
二叉樹的非遞迴遍歷 上一節二叉樹的遞迴遍歷中簡單介紹了二叉樹的遞迴遍歷的實現方式,本節主要介紹二叉樹的非遞迴遍歷實現,繼續引用上節的例子來說明下。 一.先序遍歷 二叉樹先序遍歷的訪問順序為:根結點->左孩子->右孩子。簡單的說,對於任意
第4章第1節練習題1 二叉樹的基本操作(遞迴實現)
二叉樹的遞迴遍歷 所謂二叉樹的遍歷,本質上就是沿某條搜尋路徑訪問樹中的每個結點,使得每個節點均被訪問一次,而且僅被訪問一次。 由二叉樹的基本定義可以知道,遍歷一顆二叉樹首先必須決定對根結點(N),左子樹(L),右子樹(R)的訪問順序,按照先遍歷左孩子再遍歷右
第4章第1節練習題6 二叉樹葉子節點連結成單鏈表
問題描述 設計一個演算法,將二叉樹的葉子節點按從左到右的順序連成一個單鏈表,表頭指標為head。連結時用葉子節點的右指標來存放單鏈表指標。 演算法思想 題目要求將葉子節點按自左向
《數學之美》總結(第4章~第5章)
第四章 談談中文分詞 採用“查字典”方式的分詞技術最早是由北京航天航空大學的樑南元教授提出的,我研究生期間看的第一篇論文也是這個,有點兒歷史…… 後來,中國內地,第一個自覺使用統計學模型對自然語言進行分詞的是清華大學電子工程系的郭
第1章第1節練習題10 查找中位數
str idt findmi proc borde 1.3 hidden argc -a 問題描寫敘述 一個長度為L(L ≥1) 的升序序列S。處在第 ? L/2 ? 個位置的數稱為S的中位數。比如,若序列S1=(11,13,15,17,19)S
Netty原始碼分析第4章(pipeline)---->第1節: pipeline的建立
Netty原始碼分析第四章: pipeline 概述: pipeline, 顧名思義, 就是管道的意思, 在netty中, 事件在pipeline中傳輸, 使用者可以中斷事件, 新增自己的事件處理邏輯, 可
第3章第1節練習題2 回形矩陣
問題描述 回型矩陣即使用二維陣列完成來繞圈圈似的賦值,舉例說明如下所示的形式即為回型陣列。 演算法思想 就單純的在二維陣列中按照某種順序輸出連續的數字而言,實際上是玩弄陣
第1章第1節練習題3 刪除指定元素
問題描述 長度為n的順序表L,編寫一個時間複雜度為O(n),空間複雜度為O(1)的演算法,該演算法刪除線性表中所有值為e的資料元素 演算法思想1 用k記錄順序表L中不等於e的元素個數
第2章第2節練習題1 逆置佇列
問題描述 Q是一個佇列,S是一個空棧,實現將佇列中的元素逆置的演算法 演算法思想 因為Q是一個佇列,如果僅僅按照佇列先進先出的特性時無法完成自身元素逆置操作的,而題目中又給出了一個可
第2章第1節練習題2 判斷是否中心對稱
問題描述 試寫一演算法來判斷單鏈表的前n個字元是否中心對稱。 例如xyx,xyyx都是中心對稱 演算法思想 在第1章第2節練習題19 判斷迴圈雙鏈表對稱中已經初次涉及到了判
第2章第1節練習題1 判斷棧的操作次序是否合法
問題描述 假設I和O分別表示入棧和出棧操作。棧的初狀和終態均為空,入棧和出棧的操作序列可表示僅由I和O組成的序列,可以操作的序列稱為合法序列,否則稱為非法序列。 試寫一個演算法完成對下列輸
第1章第1節練習題5 無序表刪除指定區間值
問題描述 從順序表中刪除其值在給定值s與t之間(包含s和t,要求s<t)的所有元素,如果s或t不合理或者順序表為空則顯示出錯資訊並退出執行。 演算法思想 注意理解題意,本題與練
第1章第1節練習題7 順序表的歸併
問題描述 將兩個有序的順序表合併成一個新的有序順序表,由函式返回結果順序表 演算法思想 本題實際就是歸併排序的一種特殊情況,因為兩個順序表皆有序,這樣我們只需要不斷的取下兩個順序表中
第2章第2節練習題3 使用隊列模擬渡口管理
練習 addclass printf script view process append string Language 問題描寫敘述 汽車輪渡口,過江渡船每次能載10輛車過江。過江車分為客車和貨車類。上渡船有例如以下規定:
《從0到1》讀書筆記第4章“競爭意識”第1記:霧失樓臺,月迷津渡
spl 讓我 tails ext ont down 激情 都是 lines 一直以來我們接受的教育都是教導我們要做個出類拔萃的好學生,小學如此,中學這般,大學也是如是。而評論是否是個好學生的標準在我國有“三好學生”做衡量。而隨著社會就業競爭形勢的日益
第4章系統穩定性4.1在線日誌分析
時間排序 txt ash 可執行 字符串 awk -c 歸檔 行數 cat -n access.log -n打印行號 more access.log 空格-下一頁、回車-下一行、F-下一屏,百分比的下一個、B-上一屏 less access.log /查
c++作業實驗10第4章課後習題11遞歸(用遞歸方法求f())
ace 循環 中間變量 urn 裏的 調用 為什麽 區塊 不知道 // 實驗10第4章課後習題11遞歸.cpp: 定義控制臺應用程序的入口點。 #include "stdafx.h" using namespace std; #include<iostream>