16.考研-資料結構-二叉樹的相關演算法01
阿新 • • 發佈:2019-02-08
中序遍歷對二叉樹線索化的遞迴演算法
void InThread(ThreadTree &P,ThreadTree &pre) { if(p!=null) { InThread(p->lchild,pre); if(lchild==null) { p->lchild=pre; p->ltag=1; } if(pre!=null&&pre->rchild==null) { pre->rchild=p; pre->rtag=1; } pre=p; InThread(p->rchild,pre); } } void CreatInTread(ThreadTree T) { ThreadTree pre=null; if(T!=null) { InThread(T,pre); pre->rchild=null; pre->rtag=1; } }
已知一棵二叉樹按順序儲存結構進行儲存,設計一個演算法,求編號i到j的兩個結點的最近的公共祖先結點的值
ElemType Comm_Ancestor(SqTree T,int i,int j)
{
if(T[i]!='#'&&T[j]!='#')
{
while(i!=j)
{
if(i>j)
i=i/2;
else
j=j/2;
}
return T[i];
}
}
假設二叉樹採用二叉連結串列儲存結構,設計一個非遞迴演算法求二叉樹高度
int Btdepth(BiTree T) { if(!T) return 0; int front=-1,rear=-1; int last=0,level=0; BiTree Q[MaxSize]; Q[++rear]=T; BiTree P; while(front<rear) { p=Q[++front]; if(p->lchild) Q[++rear]=p->lchild; if(p->rchild) Q[++rear]=p->rchild; if(front==last) { level++; last=rear; } return level; } }
二叉樹按二叉連結串列形式儲存,寫一個判別給定二叉樹是否是完全二叉樹的演算法
解題思想:
根據完全二叉樹的定義,具有n個結點的完全二叉樹與滿二叉樹中編號1–n的結點一一對應。
採用層次遍歷的演算法,將所有結點加入佇列(包括空結點),當遇到空結點時,檢視其後是否有非空結點,若有,則二叉樹不是完全二叉樹。
bool IsComplete(BiTree &T)
{
InitQueue(Q);
if(!T) 空樹為滿二叉樹
return 1;
EnQueue(Q,T);
while(!IsEmpty(Q))
{
DeQueue(Q,p);
if(p) 結點非空,將其左右樹入佇列
{
EnQueue(Q,p->lchild);
EnQueue(Q,p->rchild);
}
else 結點為空,檢查其後是否有非空結點
{
while(!IsEmpty(Q))
{
DeQueue(Q,p);
if(p) 結點為空,檢查其後是否有非空結點
return 0;
}
}
return 1;
}
}
假設二叉樹採用二叉連結串列儲存結構儲存,試設計一個演算法,計算給定二叉樹的所有雙分支結點個數
int DsonNodes(BiTree &T)
{
if(T==null)
return 0;
else if(T->lchild!=null&&T->rchild!=null)
return DsonNodes(T->lchild)+DsonNodes(T->rchild)+1;
else
return DsonNodes(T->lchild)+DsonNodes(T->rchild);
}
假設二叉樹採用二叉連結串列儲存結構,設計一個演算法,求先序遍歷序列中第k個結點的值(1≤k≤二叉樹中結點個數)
解題思路:
設定一個全域性變數i記錄已訪問過的結點序號,其初值是根結點在先序序列中的序號,即為1,。
當二叉樹為空時返回特殊字元‘#’。
當i=k時,小時豪到滿足條件的結點。返回b->data;
當i!=k時,則遞迴地在左子樹中查詢,若找到了則返回該值,否則繼續遞迴地在右子樹中查詢,並返回其結果
int i=1;
ElemType PreNode(BiTree b,int k)
{
if(b==null)
return '#';
if(i==k)
return b->data;
ch=PreNode(b->lchild,k);
if(ch!='#')
return ch;
ch=PreNode(b->rchild,k);
return ch;
}
在二叉樹中查詢值為x的結點,試編寫演算法,列印值為x的結點的所有祖先,假設值為x的結點不多於1個
演算法思想:採用非遞迴後序遍歷,最後訪問根節點,當訪問之為x的結點時,棧中所有元素均為該結點的祖先,依次出棧列印即可
typedef struct
{
BiTree t;
int tag;
}stack tag=0表示左子樹被訪問,tag=1時表示右子女被訪問
void search(BiTree bt,ElemType x)
{
stack s[];
top=0;
while(bt!=null||top>0)
{
while(bt!=null&&bt->data!=x)
{
s[++top].t=bt;
s[top].tag=0;
bt=bt->lchild;
}
if(bt->data==x)
{
printf("所查結點的所有祖先結點的值為:");
for(int i=1;i<=top;i++)
printf("%d",s[i].t->data);
exit(0);
}
while(top!=0&&s[top].tag==1)
top--;
if(top!=0)
{
s[top].tag=1;
bt=s[top].t->rchild;
}
}
}
若一棵二叉樹的結點結構為(LLIKE,INFO,RLINK),ROOT指向該二叉樹根結點的指標,p和q分別指向該二叉樹中任意兩個結點,試比阿尼額演算法,ANCESTOR(ROOT,p,q,r),該演算法找到p和q的最近公共祖先結點
演算法思想:
採用後續非遞迴遍歷演算法,棧中存放二叉樹結點的指標,當訪問到某結點時,棧中所有元素均為該結點的祖先,後續遍歷必然先遍歷到結點p,棧中元素均為p的忑結點,先將棧複製到另一塊輔助棧中去,繼續遍歷到結點q時,將棧中元素從棧頂開始逐個到輔助棧中去匹配,第一個匹配到的元素即結點p與q的公共最近祖先。
typedef struct
{
BiTree t;
int tag; tag=0左子女被訪問過,tag=1時,右子女被訪問過
}srack;
stack s1[],s2[];
BiTree Ancestor(BiTree ROOT,BiTNode *p,BiTNode *q)
{
top=0;
bt=ROOT;
while(bt!=null&&bt!=p&&bt!=q)
{
while(bt!=null)
{
s[++top].t=bt;
s[top].tag=0;
bt=bt->lchild;
}
while(top!=0&&s[top].tag==1)
{
if(s[top].t==p)
{
for(i=1;i<=top;i++)
{
s1[i]=s[i];
top1=top;
}
if(s[top].t==q)
{
for(i=top;i>0;i--)
for(j=top1;j>0;j--)
if(s1[j].t==s[i].t)
return s[i].t;
}
top--;
}
if(top!=0)
{
s[top].tag=1;
bt=s[top].t->rchild;
}
}
}
}
假定二叉樹採用二叉連結串列儲存結構,設計一個演算法,求非空二叉樹b的寬度(即具有結點數最多的那一層的結點個數)
採用層次遍歷,求出所有結點的層次,並將所有結點與對應的層次放在一個佇列中,然後通過掃描佇列求出各層的結點總數即二叉樹的寬度
typedef struct
{
BiTree data[MaxSize]; 結點
int level[MaxSize]; 儲存data中相同下表的結點層
int front,rear;
}Qu;
int BTWidth(BiTree b)
{
BiTree p;
int i,k,max,n;
Qu.front=Qu.rear=-1;
Qu.rear++;
Qu.data[Qu.rear]=b;
Qu.level[Qu.rear]=1;
while(QU.front<Qu.front)
{
Qu.rear++;
p=Qu.data[Qu.front];
k=Qu.data[Qu.front];
if(p->lchild!=null)
{
Qu.rear++;
Qu.data[Qu.rear]=p->lchild;
Qu.level[Qu.rear]=k+1;
}
if(p->rchild!=null)
{
Qu.rear++;
Qu.data[Qu.rear]=p->rchild;
Qu.level[Qu.rear]=k+1;
}
max=0;
i=0;k=1;
while(i<=Qu.rear)
{
n=0;
while(i<=Qu.rear&&Qu.level[i]==k)
{
i++;n++;
}
k=Qu.level[i];
if(n>max)
max=n;
}
return max;
}
}
設計一個演算法,將二叉樹的葉結點從做導遊的順序連成一個單鏈表,表頭指標為head,二叉樹按二叉連結串列方式儲存,連結時用葉結點的右指標域來存放單鏈表指標
演算法思想:
通常我們所使用的先序,中序和後續遍歷對於葉結點的訪問都從左到右排序,這裡我們採用中序遍歷遞迴演算法。
設前驅結點指標pre,初始為空,第一個葉結點由指標head指向,遍歷到葉結點時,就將它的前驅rchild指向它,最後一個葉結點rchild為空
LinkList head,pre=null;
LinkList InOrder(BiTree bt)
{
if(bt)
{
InOrder(br->lchild);
if(bt->lchild==null&&bt->rchild==null)
{
if(pre==null)
{
head=bt;
pre=bt;
}
else
{
pre->rchild=bt;
pre=bt;
}
InOrder(bt->rchild);
pre->rchild=null;
}
return head;
}
}
試設計判斷兩課二叉樹是否相似的演算法。所謂二叉樹T1與T2相似,指的是T1與T2都是空的二叉樹或都只有一個根結點;或T1的左子樹與T2的左子樹是相似的且T1的右子樹與T2的右子樹是相似的
int similar(BiTree T1,BiTree T2)
{
int lefts,rights;
if(T1==NULL&&t2==NULL)
return 1;
else if(T1==NULL||T2==NULL)
return 0;
else
{
lefts=similar(T1->lchild,T2->lchild)
rights=similar(T1->rchild,T2->rchild);
return lefts&&rights;
}
}