数据结构编程回顾(四) 二叉树的三种非递归遍历以及根节点到任意节点的路径

题目四:求二叉树上结点的路径
设计要求:在采用链式存储结构存储的二叉树上,以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;
}

猜你喜欢

转载自blog.csdn.net/qq_36614557/article/details/81517468
今日推荐