該題目參考自<<劍指Offer>>第19題目
求一顆樹的鏡像的過程:我們先前序遍歷這顆樹的每個結點,如果遍歷到的結點有子結點,就交換它的兩個子結點。當交換完所有非葉子結點的左右子節點之後,就得到了樹的鏡像。
a圖中爲一個二叉樹,遍歷此二叉樹,先交換根節點8的左右子樹,如圖中紅色區域。
如圖c,接着遍歷到10結點,交換其左右子樹。如圖中紅色區域。
如圖e,遍歷到結點6,交換其左右子樹。如圖中紅色區域。
遞歸法求二叉樹鏡像
<pre name="code" class="html">void MirrorRecursively(binarytree * head)
{
if(head==NULL)//二叉樹爲空樹
return;
if(head->lchild==NULL&&head->rchild==NULL)//當左右子結點都爲空
return;
binarytree * temp=head->lchild;//語句段1
head->lchild=head->rchild;//
head->rchild=temp;//
if(head->lchild)//語句段2
MirrorRecursively(head->lchild);//
if(head->rchild)//
MirrorRecursively(head->rchild);//
}
上面程序中語句段1與語句段2是可以交換的。既可以先交換當前結點的左右子樹,再調用遞歸函數處理其左右子結點。也可以先調用遞歸函數處理其左右子結點,然後再交換其左右子樹。兩者的區別是處理結點的順序有差異,但是鏡像的結果是一致的。
循環法求二叉樹鏡像,需要使用到STL隊列。void MirrorLoopLy(binarytree *head)
{
if(head==NULL)
return;
queue<binarytree *> que;
que.push(head);
while(!que.empty())
{
binarytree * node=que.front();
que.pop();
binarytree * temp=node->lchild;
node->lchild=node->rchild;
node->rchild=temp;
if(node->lchild)
que.push(node->lchild);
if(node->rchild)
que.push(node->rchild);
}
}
上面程序中,語句段1與語句2的位置可以交換。既可以先交換結點的左右子樹,再把其左右子結點加入隊列。也可以先把其左右子樹加入隊列,再交換其左右子樹。兩者的區別是結點被處理的先後順序有差異,鏡像結果是一樣的。鏈表的結果、打印鏈表、初始化鏈表
struct binarytree
{
int data;
binarytree * lchild;
binarytree * rchild;
};
void Create(binarytree * & t)//指針的引用
{
int c;
cin>>c;
if(c==-1)//遞歸的出口
t=NULL;
else
{
t=new binarytree;
t->data=c;
Create(t->lchild);//遞歸左子節點
Create(t->rchild);//遞歸右子節點
}
}
void Preprint(binarytree *head)//中序遍歷
{
if(head==NULL)
return;
cout<<head->data<<" ";
Preprint(head->lchild);
Preprint(head->rchild);
}
初試化過程中輸入-1,相當於輸入了空樹。所以當輸入1 2 -1 -1 3 -1 -1.此二叉樹的中序遍歷就是1 2 3。
測試程序:
#include<iostream>
using namespace std;
#include<queue>
int main()
{
binarytree *head;
Create(head);
cout<<"鏡像前二叉樹的中序遍歷:"<<endl;
Preprint(head);
cout<<endl;
MirrorRecursively(head);
cout<<"使用遞歸法鏡像後二叉樹的中序遍歷:"<<endl;
Preprint(head);
cout<<endl;
MirrorLoopLy(head);
cout<<"使用循環法鏡像後二叉樹的中序遍歷:"<<endl;
Preprint(head);
cout<<endl;
return 0;
}