資料結構程式設計回顧(四) 二叉樹的三種非遞迴遍歷以及根節點到任意節點的路徑
題目四:求二叉樹上結點的路徑
設計要求:在採用鏈式儲存結構儲存的二叉樹上,以bt 指
向根結點,p 指向任一給定的結點,程式設計實現求出從根結點
到給定結點之間的路徑。
選單內容:
1. 建立二叉樹儲存結構
2. 求二叉樹的前序遍歷
3. 求二叉樹的中序遍歷
4. 求二叉樹的後續遍歷
5. 求指定結點的路徑
6. 退出系統
請選擇:1 – 6:
提示:
【採用非遞迴遍歷的方法】
1. 二叉樹的建立
2. 求指定結點的路徑
3. 二叉樹的前、中、後序非遞迴遍歷演算法
4. 查詢函式
使用結構體:樹和棧 棧用來實現非遞迴以及路徑
typedef struct Tree { char data; int run=0;//在後序遍歷的非遞迴中使用 表示這個節點是否被訪問過 struct Tree *l,*r; } Tree,*BiTree; //用棧來儲存指標 typedef struct Stack { Tree **top; Tree **base; int stacksize;// } Stack;
首先,輸入按照先序遍歷樹的字串,其中若結點為空,則用'#'表示:
遞迴方法建立:
void CreateTree2(BiTree &T) {
char c;
cin>>c;
if(c=='#')
T=NULL;
else {
InitTree(T,c);
CreateTree2(T->l);
CreateTree2(T->r);
}
}
非遞迴方法(程式碼可能有問題 當時註釋掉了 略過略過):
int CreateTree1(BiTree &bt) { Stack ss; InitStack(ss); cout << "按照先序輸入樹,用'#'表示空:" << endl; char input[100]; BiTree p=bt; int i=0; gets(input); int n=strlen(input); for(i=0; i<n; i++) { if(input[i]!='#') { InitTree(p,input[i]); push(ss,p); p=p->l; } else { InitTree(p,input[i]); if(isempty(ss)||i==n-1) { p=bt; return 0; } else bt=pop(ss,p); if(p->l&&(p->r==NULL)) { p=p->r; } else { while(p->l&&p->r) { if(isempty(ss)) return 0; else bt=pop(ss,p); } p=p->r; } } } }
先序和中序遍歷的非遞迴方式:
先序:
1.先輸出該結點的值,然後把該節點壓入棧中,然後沿著該節點的左子樹繼續,直到該結點為空;
2.此時如果棧不為空,則彈出棧頂元素,並訪問其右子樹,執行1,否則結束。
中序:
和先序類似,唯一不同的是輸出該結點的時機是在出棧時,而不是在最開始。
void First(BiTree T) { Stack sf; InitStack(sf); Tree *p=T; while(p||!isempty(sf)) { while(p) { cout<<p->data<<' '; push(sf,p); p=p->l; } if(!isempty(sf)) { p=pop(sf,p); p=p->r; } } cout<<endl; } void Mid(BiTree T) { Stack sm; InitStack(sm); Tree *p=T; while (p||!isempty(sm)) { while(p) { push(sm,p); p = p->l; } if (!isempty(sm)) { p=pop(sm,p); cout <<p->data<<' '; p = p->r; } } cout<<endl; }
後序:
後序輸出結點的值是要判斷其左右結點(如果存在)是否都被訪問過才可以。
首先類似中序的方法先沿著左子樹走並壓入棧中,當結點為空時,如果棧不空,則彈出棧頂元素,如果這個元素的右子樹存在並且沒有被訪問過的話,那麼把當前結點壓入棧中,並訪問其右子樹,執行最開始的沿著左子樹的過程,如果右子樹不存在或者右子樹已經被訪問,那麼輸出該結點的值,並值該節點的訪問為1.如果棧空,結束。
void Last(BiTree T) {
Stack sl;
InitStack(sl);
Tree *p=T;
while (p||!isempty(sl)) {
while(p&&p->run==0) {
push(sl,p);
p = p->l;
}
if (!isempty(sl)) {
p=pop(sl,p);
// cout<<2;
if(p->r&&p->r->run==0) {
push(sl,p);
p = p->r;
// cout<<3;
}
else {
cout <<p->data<<' ';//
p->run=1;
if(isempty(sl)) {
cout<<endl;
break;
}
}
}
}
}
根節點到任意結點的路徑:
有點類似於分治法的思想,如果這個點存在這個樹中(值唯一),那麼必定滿足以下條件的唯一一個:
1.該結點在根節點被找到
2.該節點在根節點的左子樹被找到
3.該節點在根節點的右子樹被找到
如果都不滿足,則不在這個樹內。
利用這個思想,判斷樹是否滿足三個條件中的一個,如果滿足,則把根壓入棧中,最後依次彈出,即為路徑。
bool Find(BiTree T,char c){
if(T==NULL)
return 0;
if(T->data==c||Find(T->l,c)||Find(T->r,c)){
push(sq,T);
count++;
return 1;
}
return 0;
}
void jiedian(BiTree T){
InitStack(sq);
char d1;
cout<<"請輸入指定的結點:";
cin>>d1;
Find(T,d1);
if(isempty(sq)){
cout<<"cannot find.";
}
while(!isempty(sq)){
BiTree p=pop(sq,p);
cout<<p->data;
if(count!=1)
cout<<"->";
count--;
}
cout<<endl;
}
完整程式碼:
#include <iostream>
#include <windows.h>
#include<stdio.h>
#include <string.h>
#define SIZE 100
#define incre 10
using namespace std;
typedef struct Tree {
char data;
int run=0;
struct Tree *l,*r;
} Tree,*BiTree;
//用棧來儲存指標
typedef struct Stack {
Tree **top;
Tree **base;
int stacksize;//
} Stack;
int isempty(Stack s) {
if(s.top==s.base)
return 1;
else
return 0;
}
void InitStack(Stack &s) {
s.base=(Tree **)malloc(SIZE*sizeof(Tree));
s.top=s.base;
s.stacksize=SIZE;
}
void push(Stack &s,Tree *p) {
*s.top++=p;
}
Tree *pop(Stack &s,Tree *p) {
if(s.top==s.base)
exit(-1);
p=*--s.top;
return p;
}
void InitTree(BiTree &T,char c) {
T=(BiTree)malloc(sizeof(Tree));
T->data=c;
T->l=NULL;
T->r=NULL;
}
void First(BiTree T) {
Stack sf;
InitStack(sf);
Tree *p=T;
while(p||!isempty(sf)) {
while(p) {
cout<<p->data<<' ';
push(sf,p);
p=p->l;
}
if(!isempty(sf)) {
p=pop(sf,p);
p=p->r;
}
}
cout<<endl;
}
void Mid(BiTree T) {
Stack sm;
InitStack(sm);
Tree *p=T;
while (p||!isempty(sm)) {
while(p) {
push(sm,p);
p = p->l;
}
if (!isempty(sm)) {
p=pop(sm,p);
cout <<p->data<<' ';
p = p->r;
}
}
cout<<endl;
}
void Last(BiTree T) {
Stack sl;
InitStack(sl);
Tree *p=T;
while (p||!isempty(sl)) {
while(p&&p->run==0) {
push(sl,p);
p = p->l;
}
if (!isempty(sl)) {
p=pop(sl,p);
// cout<<2;
if(p->r&&p->r->run==0) {
push(sl,p);
p = p->r;
// cout<<3;
}
else {
cout <<p->data<<' ';//
p->run=1;
if(isempty(sl)) {
cout<<endl;
break;
}
}
}
}
}
int CreateTree1(BiTree &bt) {
Stack ss;
InitStack(ss);
cout << "按照先序輸入樹,用'#'表示空:" << endl;
char input[100];
BiTree p=bt;
int i=0;
gets(input);
int n=strlen(input);
for(i=0; i<n; i++) {
if(input[i]!='#') {
InitTree(p,input[i]);
push(ss,p);
p=p->l;
} else {
InitTree(p,input[i]);
if(isempty(ss)||i==n-1) {
p=bt;
return 0;
}
else
bt=pop(ss,p);
if(p->l&&(p->r==NULL)) {
p=p->r;
}
else {
while(p->l&&p->r) {
if(isempty(ss))
return 0;
else
bt=pop(ss,p);
}
p=p->r;
}
}
}
}
void CreateTree2(BiTree &T) {
char c;
cin>>c;
if(c=='#')
T=NULL;
else {
InitTree(T,c);
CreateTree2(T->l);
CreateTree2(T->r);
}
}
Stack sq;
int count;
bool Find(BiTree T,char c){
if(T==NULL)
return 0;
if(T->data==c||Find(T->l,c)||Find(T->r,c)){
push(sq,T);
count++;
return 1;
}
return 0;
}
void jiedian(BiTree T){
InitStack(sq);
char d1;
cout<<"請輸入指定的結點:";
cin>>d1;
Find(T,d1);
if(isempty(sq)){
cout<<"cannot find.";
}
while(!isempty(sq)){
BiTree p=pop(sq,p);
cout<<p->data;
if(count!=1)
cout<<"->";
count--;
}
cout<<endl;
}
int main() {
BiTree bt=NULL;
BiTree p=bt;
cout << "按照先序輸入樹,用'#'表示空:" << endl;
CreateTree2(bt);
cout<<"先序遍歷:";
First(bt);
cout<<"中序遍歷:";
Mid(bt);
cout<<"後序遍歷:";
Last(bt);
jiedian(bt);
return 0;
}