二叉树的各种遍历

#include "pch.h"

#define MaxSize 200
#include <iostream>
typedef char TElemType;
using namespace std;
typedef struct BiTnode {//链表
	TElemType data;
	struct BiTnode * lchild, *rchild;
	bool isFirst;
}BiTnode, *BiTree;
typedef struct StackNode {
	struct StackNode *next;
	BiTree point;
}StackNode, *LinkStack;
//初始化
bool init(BiTree & B) {
	B = new BiTnode;
	B->rchild = NULL;
	B->lchild = NULL;//空树
	if (B)
		return true;
	else
		return false;
}
//创建二叉树,用先序法输入,一'#'来分开
void createTree(BiTree & B) {
	TElemType e;
	cin >> e;
	if (e == '#') B = NULL;
	else {
		B = new BiTnode;
		B->data = e;
		createTree(B->lchild);
		createTree(B->rchild);
	}
}

//入栈

bool Push(LinkStack  &L, BiTree p) {
	StackNode * Temp = new StackNode;
	Temp->point = p;
	Temp->next = NULL;
	Temp->next = L;
	L = Temp;
	return true;
}
//退栈
bool Pop(LinkStack &S, BiTree &t) {
	if (!S) return false;
	LinkStack temp = S;
	t = temp->point;
	S = S->next;
	delete temp;
	return true;
}
//判断栈空
bool isEmpty(LinkStack L) {
	if (L == NULL) return true;
	else return false;
}
BiTree getTop(LinkStack L) {
	if (!L) return NULL;
	else
		return L->point;
}

//先序遍历

void PreOrderTraverse(BiTree B) {
	if (B) {
		cout << B->data << " ";
		PreOrderTraverse(B->lchild);
		PreOrderTraverse(B->rchild);
	}

}
//中序遍历
void InOrderTraverse(BiTree B) {
	if (B) {
		InOrderTraverse(B->lchild);
		cout << B->data << " ";
		InOrderTraverse(B->rchild);
	}

}
//后序遍历
void PostOrderTraverse(BiTree B) {
	if (B) {
		PostOrderTraverse(B->lchild);
		PostOrderTraverse(B->rchild);
		cout << B->data << " ";
	}
}

//6.层次遍历,利用队的思想

void LeveLOrder(BiTree b) {
	BiTree p;
	BiTree qu[MaxSize];
	int front, rear;
	front = rear = -1;
	rear++;
	qu[rear] = b;
	while (front != rear) {
		front = (front + 1) % MaxSize;
		p = qu[front];
		printf("%c ", p->data);
		if (p->lchild != NULL) {
			rear = (rear + 1) % MaxSize;
			qu[rear] = p->lchild;
		}
		if (p->rchild != NULL) {
			rear = (rear + 1) % MaxSize;
			qu[rear] = p->rchild;
		}
	}
}

//非递归方式,基于栈的实现

//基于非递归的先序遍历,需要栈先入右子树,再入左子树,直到左子树没了,就一直弹出上个父结点,输入这个父节点的右子结点的右、左子树

void PreOrder2(BiTree B) {
	LinkStack L = NULL;//一个bug存在的方法,需要先定义为NULL,否则会多一个没用的结点
	if (B) {
		// 树不为空时开始遍历
		Push(L, B);
		BiTree t;
		while (!isEmpty(L)) {// 栈不为空时循环
			if (Pop(L, t))
				printf("%c ", t->data);
			if (t->rchild) {//右分支存在则入栈
				Push(L, t->rchild);
			}
			if (t->lchild) {
				Push(L, t->lchild);
			}
		}
	}
}

//基于非递归的中序遍历,需要栈先入父节点,左子树,直到左子树没了,就一直弹出上个父结点,输入这个父节点的右子结点的左,右子树

void InOrder2(BiTree B) {
	LinkStack L = NULL;
	BiTree t = NULL, p = B;
	while (p || !isEmpty(L)) {
	//只有栈空和树空才结束《重点思想》,
	//当A父节点出栈后,需要靠树未空继续循环入栈
		if (p) {
			Push(L, p);
			p = p->lchild;
		}
		else {
			Pop(L, t);
			cout << t->data << " ";
			p = t->rchild;
		}
	}
}

//基于非递归的后序遍历

//后序遍历的非递归实现是三种非递归遍历方式中最难的一种。

//因为在后序遍历中,要保证左孩子和右孩子都已被访问并且左孩子在右孩子前访问才能访问根结点,这就为流程的控制带来了难题
/*第一种思路:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问, 因此其右孩子还为被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就 保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是 否是第一次出现在栈顶。*/
void AftOrder1(BiTree B) {
	LinkStack L = NULL;
	BiTree q = B, t;
	while (q || !isEmpty(L)) {
		//1.对最左孩子遍历
		while (q) {
			q->isFirst = true;
			Push(L, q);
			q = q->lchild;
		}
		//2.判断第几次出现在栈中,只有在第二次出现在栈顶时,才能访问它输出
		if (!isEmpty(L)) {
			Pop(L, t);
			if (t->isFirst == true) {
				t->isFirst = false;
				Push(L, t);
				q = t->rchild;
			}
			else {
				cout << t->data << " ";
				q = NULL;
			}
		}
	}
}

/ *第二种思路:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存 在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了 每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。*/

void AftOrder2(BiTree B) {
	BiTree pre, cur, t;
	pre = cur = t = NULL;
	LinkStack L = NULL;
	if (B)
		Push(L, B);
	while (!isEmpty(L)) {
		cur = getTop(L);
		if ((cur->lchild == NULL && cur->rchild == NULL) ||		//如果P不存在左孩子和右孩子
			(pre != NULL && (pre == cur->lchild || pre == cur->rchild))) {//或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,
			cout << cur->data << " ";
			Pop(L, t);
			pre = cur;
		}
		else {
			if (cur->rchild)
				Push(L, cur->rchild);
			if (cur->lchild)
				Push(L, cur->lchild);

		}
	}
}

//3.locate

BiTree Locate(BiTree B, TElemType e) {//返回值所在的指针
	BiTree p;
	if (!B) return NULL;
	else if (B->data == e) return B;
	else {
		p = Locate(B->lchild, e);
		if (p)
			return p;
		else
			return Locate(B->rchild, e);
	}
}

//4.递归查找第几层

int _level(BiTree B, BiTree goal, int depth) {
	if (B == NULL) return 0;
	if (B == goal) return depth;
	int l = _level(B->lchild, goal, depth + 1);
	int r = _level(B->rchild, goal, depth + 1);
	if (l > 0) return l;
	if (r > 0) return r;
	else return 0;
}
int level(BiTree B, BiTree p) {
	return B ? _level(B, p, 1) : 0;
}

//复制二叉树

void copy(BiTree b, BiTree & b1) {
	if (b == NULL) {
		b1 = NULL;
		return;
	}
	else {
		b1 = new BiTnode;
		b1->data = b->data;
		copy(b->lchild, b1->lchild);
		copy(b->rchild, b1->rchild);
	}
}

//计算深度

int depth(BiTree T) {
	int m, n;
	if (T == NULL) return 0;
	else {
		m = depth(T->lchild);
		n = depth(T->rchild);
		return (m > n ? m : n) + 1;//加上根节点那一层
	}
}

//计算节点数

int codecount(BiTree T) {
	if (T == NULL)return 0;
	else
		return codecount(T->lchild) + codecount(T->rchild) + 1;
}

//删除,假设从上到下,从左到右递增
bool Delete(BiTree & T,TElemType e) {

	BiTree f, p, q, s;
	p = T;
	f = NULL;//p的双亲
	while ( p->data!=e && p) 
	{
		f = p;
		if (e <p->data)
			p = p->lchild;
		else
			p = p->rchild;
	}
	if (p == NULL) return false;//找不到这样的点
	if (p->lchild == NULL) 
	{//左子树为空
		if (f ==  NULL) {//目标点是根结点
			T = p->rchild; delete p;
		}
		else if(f->lchild==p)//左分支
		{
			f->lchild = p->rchild;
			delete p;
		}
		else if (f->rchild == p)//左分支
		{
			f->rchild = p->rchild;
			delete p;
		}
	}
	else
	{	//思路:一直找左分支的最右结点,最后把最后结点的值赋给被删的结点
		q = p;
		s = p->lchild;
		while (s->rchild) {
			q = s; 
			s = s->rchild;
		}
		if (q == p)
			q->lchild = s->lchild;//只有2层
		else
			q->rchild = s->lchild;
		p->data = s->data;
		delete s;
	}
	return true;
}
int main() {//
	BiTree B,TEMP;
	init(B);
	cout << "Please input the data" << endl;
	createTree(B);
	cout << "先序遍历" << ends; PreOrderTraverse(B); cout << endl;
	cout <<"中序递归遍历"<<ends;InOrderTraverse(B); cout << endl;
	cout << "后序遍历" << ends; PostOrderTraverse(B); cout << endl;
	cout << "先序非递归遍历" << ends; PreOrder2(B); cout << endl;
	cout << "中序非递归遍历" << ends; cout << endl;
	 cout << "第一种后序非递归遍历" << ends; AftOrder1(B); cout << endl;
	 cout << "第二种后序非递归遍历" << ends; AftOrder2(B); cout << endl;
	 cout << "\n层次非递归遍历" << ends; LeveLOrder(B); cout << endl;

	cout << "深度" << depth(B) << endl;
	cout << "节点数" << codecount(B) << endl;
	//copy
	copy(B, TEMP);
	cout << "复制后的先序遍历" << endl;
	PreOrderTraverse(TEMP);
	cout << "\n深度" << depth(TEMP) << endl;
	cout << "节点数" << codecount(TEMP) << endl;
	char e;
	cout << "输入一个数字,找出层数" << endl;
	while (cin >> e)
		if (level(B, Locate(B, e)))
			cout << e << "在第" << level(B, Locate(B, e)) << "层" << endl;
		else cout << e << "不存在" << endl;


}

测试案例:
AB#CD##E##F#GH###
在这里插入图片描述

发布了122 篇原创文章 · 获赞 14 · 访问量 6180

猜你喜欢

转载自blog.csdn.net/weixin_44001521/article/details/103748178