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

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

 

  • 3
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
1、已知一个链表存储了若干名学生的信息,每名学生的信息包括:学号、英语成绩、数学成绩、计算机成绩。 现编写一个函数search(),要对输入的无序学号进行排序,然后采用折半查找方法查找输入学生学号,并输出该学生各科成绩。 2、设计一个学生类(CStudent),它具有私有数据成员是:学号、姓名、数学、外语和计算机课程的成绩。要能实现三门课总成绩和平均成绩,并能设置和显示学生信息 (类声明和成员函数定义分离)。设计一个友元函数,按照成绩从高到低的顺序输出姓名、学号和成绩信息。 3、实现雇员管理,类Employee需存储雇员的姓名。这种信息对于所有雇员(包括Employee的派生类的雇员)是很普遍的。现在假设从雇员类Employee派生出了小时工类HourlyWorker、计件工类PieceWorker、老板类Boss和销售员类CommissionWorker。小时工每周工作40小时,超过40小时部分的报酬是平时的1.5倍;计件工是按生产的工作件数计算报酬的,每件的报酬是固定的,假设他只生成一种类型的工件,因而类PieceWorker的private数据成员是生产的工件数量和每件的报酬;老板每周有固定的薪水;销售员每周有小部分固定的基本工资加上其每周销售额的固定百分比。设计和规划该类体系,并分别产生每个基类及派生类对象,并显示该员工的工资。 4、约瑟夫生死者游戏 每30个旅客同乘一条船,因为严重超载,加上风高浪大,危险万分;因此船长告诉乘客,只有将全船一半的旅客投入海,其余人才能幸免遇难。无奈,大家只得同意这种办法,并议定30个人围成一圈,由第一个人数起,依次报数,数到第9人,便把他投入大海,然后再从他的下一个人数起,数到第9人,再将他扔进大海,如此循环地进行,直到剩下15个乘客为止。问哪些位置是将是被扔下大海的位置。 5、二叉树结点路径在采用链式存储结构存储的二叉树上,以bt指向结点,p指向任一给定结点编程实现出从节点给定结点之间的路径。 6、图的操作 (1)写出将一个无向图的邻接矩阵转换成邻接表的算法 (2)设计一个算法,判断无向图G是否连通。若连通则返回1; 返回0。 7、内部排序算法的性能分析 要:(1)对冒泡排序、直接排序、简单选择排序、快速排序、希尔排序、堆排序算法进行比较; (2)待排序表的表长不小于100,表数据随机产生,至少用5组不同数据作比较,比较指标有:关键字参加比较次数和关键字的移动次数(关键字交换记为3次移动); (3)输出各种算法的排序结果和比较结果。 8.2、通讯录管理系统 编程实现通讯录管理系统,要该系统能够完成通讯信息的建立、查询、插入、删除等基本功能。程序运行后至少给出下面7个菜单项的选择并分别实现其功能: 0、 通讯录的建立 1、通讯录信息输出 2、 通讯者结点信息的删除 3、通讯者结点信息的查询 4、 通讯者结点信息的插入 5、通讯录信息更改 6、 退出通讯录管理系统 设计的任务要,通讯录每个学生的基本信息应包括姓名、地址、电话等基本信息,采用链表存储结构。(复习c语言结构体和链表知识)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值