C++树(兄弟孩子结构实现)

树转换为二叉树,森林转换为二叉树,都是基于树的兄弟孩子结构实现的。

树有三种遍历:先根遍历,后根遍历,层次遍历。前两种分别对应于二叉树的前序遍历和中序遍历。层次遍历和二叉树的层次遍历也很相似。

下面是代码:

文件"tree.h"

#include<iostream>
#include<stack>
using namespace std;

//循环队列模版
template<class T>
class My_queue;

template<class T>
class Node
{
private:
	T data;
	Node<T> *next;
public:
	Node()
	{
		next=0;
	}
	Node(T d)
	{
		data=d;
		next=0;
	}
	friend My_queue<T>;
};

template<class T>
class My_queue
{
private:
	Node<T> *tail;
public:
	My_queue()
	{
		tail=new Node<T>();
		tail->next=tail;
	}

	bool empty()
	{
		return (tail->next==tail);
	}

	void push(T d)
	{
		Node<T> *p=new Node<T>(d);
		p->next=tail->next;
		tail->next=p;
		tail=p;
	}

	T front()
	{
		if(empty())
		{
			cout<<"queue is empty!"<<endl;
			exit(0);
		}
		Node<T> *p=tail->next;
		T data=p->next->data;
		return data;
	}

	void pop()
	{
		Node<T> *p=tail->next;
		Node<T> *q=p->next;
		p->next=q->next;
		if(q==tail)
			tail=p;
		delete q;
	}
};

class CStree;

class CSnode
{
private:
	char data;
	CSnode *firstchild;
	CSnode *nextsibling;
	friend CStree;
};

class CStree
{
public:
	void Create_Tree(CSnode *&T)	//创建树
	{
		//按照从上到下,从左往右的顺序输入“双亲——孩子”的有序对,建立树的孩子兄弟存储结构
		//输入时,以('#','#')为结束标志,根结点双亲为空,也是以'#'来表示
		T=NULL;
		My_queue<CSnode *> q;
		char parent,child;
		cout<<"输入双亲,孩子有序对,以'#','#'作为输入结束标志"<<endl;
		for(cin>>parent>>child;child!='#';cin>>parent>>child)
		{
			CSnode *p=new CSnode;
			p->data=child;
			p->firstchild=p->nextsibling=NULL; //暂时现将它们置空
			q.push(p);
			if(parent=='#')
				T=p;
			else
			{
				CSnode *r;
				CSnode *s=q.front();
				while(s->data!=parent)	
				{
					q.pop();
					s=q.front();
				}
				if(!s->firstchild)	//链接第一个孩子结点
				{
					s->firstchild=p;
					r=p;
				}
				else
				{
					r->nextsibling=p;
					r=p;
				}
			}
		}//end_for
	}//end_void

	void Get_Children(CSnode *T)	//找结点孩子
	{
		//在T的还在兄弟表示法中,求输入结点的孩子
		cout<<"输入你要找的结点的值:";
		char x;
		cin>>x;
		My_queue<CSnode *> q;
		if(!T)
		{
			cout<<"这是一棵空树!"<<endl;
			return ;
		}
		q.push(T);
		CSnode *r=NULL;
		if(T->data==x)
			r=T;
		else
		{
			do
			{
				CSnode *p=q.front();
				q.pop();
				if(p->firstchild && p->firstchild->data==x)
				{
					r=p->firstchild;
					break;
				}
				if(p->firstchild && p->firstchild->data!=x)
					q.push(p->firstchild);
				if(p->nextsibling && p->nextsibling->data==x)
				{
					r=p->nextsibling;
					break;
				}
				if(p->nextsibling && p->nextsibling->data!=x)
					q.push(p->nextsibling);
			}while(!q.empty());
		}
		if(r==NULL)
		{
			cout<<"树T中没有结点"<<x<<endl;
			return;
		}
		else
			Print_children(r);
	}

	void Print_children(CSnode *p)
	{
		CSnode *q=p->firstchild;
		if(!q)
		{
			cout<<"结点"<<p->data<<"没有孩子"<<endl;
			return ;
		}
		cout<<"结点"<<p->data<<"的所有孩子是:";
		while(q)
		{
			cout<<q->data<<"  ";
			q=q->nextsibling;
		}
		cout<<endl;
	}

	void OutPath(CSnode *T,stack<char> &s) //求路径
	{
		//输出树T中从根节点到所有叶子结点的路径,用栈暂存路径
		while(T)
		{
			s.push(T->data);	//将当前层访问的结点记入路径
			if(!T->firstchild)
				Print_stack(s);	//输出从栈底到栈顶的元素
			else
				OutPath(T->firstchild,s); //继续遍历左子树
			s.pop();	//将当前层访问的结点从路径中删除
			T=T->nextsibling; //继续访问右子树
		}
	}

	void Print_stack(stack<char> s)
	{
		char temp[100];
		int i=0;
		while(!s.empty())
		{
			temp[i]=s.top();
			s.pop();
			i++;
		}
		cout<<"从根节点到叶子结点的一条路径:";
		for(int j=i-1;j>0;j--)
			cout<<temp[j]<<"->";
		cout<<temp[0]<<endl;
	}

	void PreRoot_Traverse(CSnode *T) //先根遍历
	{
		if(T)
		{
			cout<<T->data<<"  ";
			PreRoot_Traverse(T->firstchild);
			PreRoot_Traverse(T->nextsibling);
		}
	}

	void PostRoot_Traverse(CSnode *T)  //后根遍历
	{
		if(T)
		{
			PostRoot_Traverse(T->firstchild);
			cout<<T->data<<"  ";
			PostRoot_Traverse(T->nextsibling);
		}
	}

	void LevelOrder_Traverse(CSnode *T) //层次遍历
	{
		My_queue<CSnode *> q;
		CSnode *t;
		q.push(T);
		do
		{
			t=q.front();
			do
			{
				cout<<t->data<<"  ";
				if(t->firstchild)
					q.push(t->firstchild);
				t=t->nextsibling;
			}while(t);
			q.pop();
		}while(!q.empty());
	}

};

测试文件"main.cpp"

#include"tree.h"

int main()
{
	CStree tree;
	CSnode *T;
	tree.Create_Tree(T);

	tree.Get_Children(T);

	stack<char> s;
	tree.OutPath(T,s);

	cout<<"树的先根遍历为:";
	tree.PreRoot_Traverse(T);
	cout<<endl;

	cout<<"树的后根遍历为:";
	tree.PostRoot_Traverse(T);
	cout<<endl;

	cout<<"层次遍历树为:";
	tree.LevelOrder_Traverse(T);
	cout<<endl;
	
	return 0;
}

输入 # A A B A C A D C E C F C G C H E I E J G K # # 后生成的树和转换为二叉树后就是下面这种效果:



输出结果为:

输入双亲,孩子有序对,以'#','#'作为输入结束标志
# A
A B
A C
A D
C E
C F
C G
C H
E I
E J
G K
# #
输入你要找的结点的值:C
结点C的所有孩子是:E  F  G  H
从根节点到叶子结点的一条路径:A->B
从根节点到叶子结点的一条路径:A->C->E->I
从根节点到叶子结点的一条路径:A->C->E->J
从根节点到叶子结点的一条路径:A->C->F
从根节点到叶子结点的一条路径:A->C->G->K
从根节点到叶子结点的一条路径:A->C->H
从根节点到叶子结点的一条路径:A->D
树的先根遍历为:A  B  C  E  I  J  F  G  K  H  D
树的后根遍历为:B  I  J  E  F  K  G  H  C  D  A
层次遍历树为:A  B  C  D  E  F  G  H  I  J  K
Press any key to continue

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值