数据结构--树--双亲孩子表示法

双亲孩子表示法

双亲孩子表示法就是在每一个结点中添加一个firstchild指针域用来存放孩子链表指针,而且每个节点会有一个存放双亲结点在顺序存储结构中的索引,这样可以更好的查找到每个结点的双亲。但是问题是这得提前给出该树的结点数量,并生成内存空间。
在这里插入图片描述

下面用C++类来实现一个简单的类,这个树的创建中,每个结点后面最少会跟着一个孩子结点,且最后一个孩子结点是空的。
主要难点是在基于当前树的某一个结点下插入另一棵树的实现,具体看代码
要实现的是创建A、B、C和D、E、F树,并在C结点插入D、E、F树:
在这里插入图片描述

代码:

#include <iostream>
#include <stdlib.h>
using namespace std;

#define MAX_SIZE 100
//双亲孩子表示法
class CTnode
{
   public:
	   int child;
	   CTnode *next;
};

class CTbox
{
	public:
int parent;
		char data;
		CTnode *firstchild;
};

class CTtree
{
	public:
		CTtree();
		CTtree(int m);
		CTtree(const CTtree &t);
		int Treedepth();
		int Value(char cur_e);//返回节点cur_e的双亲
	//	void Assige(char cur_e,char value);//给节点cur_e赋值valua
	//	CTbox * Parent(char cur_e);//返回非根节点cur_ed的双亲
		char Leftchild(char cur_e);//返回左孩子
        void Findsibling(char cur_e);//找兄弟
		CTtree Insertchild(char cur_e,CTtree &c);//把树c插入cur_e节点中,成为cur_e的子树
        void Deletechild(char cur_e,int i);//删除cur_e节点的第i个子树
		friend ostream& operator<<(ostream& output,CTtree& p);
	private:
		
	CTbox *nodes;
	int r,n;//根的位置和节点数
}
;
//实际上在g++编译器中,对于返回对象是类的函数,并不会领创建一个空间把对象复制进去
//为了节省消耗,编译器做了优化,不会调用自定义的复制构造函数也可以完成深复制,一次
//会发现,即便删除掉下面cout注释,也不会打印出任何字符
CTtree::CTtree(const CTtree &t)
{
	CTnode *pnew,*qqnew;
	nodes=new CTbox[t.n];//创建当前对象相同节点数量的CTbox数组
//cout<<"复制"<<endl;
	for(int i=0;i<t.n;i++)
	{
		 nodes[i].parent=t.nodes[i].parent;
		 nodes[i].data=t.nodes[i].data;
		 nodes[i].firstchild=new CTnode;  //每一个节点后面都会跟至少一个CTnode结点
		 nodes[i].firstchild->child=-1;
		 nodes[i].firstchild->next=NULL;
		 pnew=nodes[i].firstchild;
		 qqnew=t.nodes[i].firstchild;
                 //对于当前对象  节点下有孩子的,进行转存复制
		 while(qqnew->next!=NULL&&qqnew->child!=-1)
		 {
                         pnew->child=qqnew->child;
                        // cout<<"复制:"<<nodes[i].data<<pnew->child<<endl;
			 pnew->next=new CTnode;//最后都会存在一个child=1  next=NULL的CTnode结点
			 pnew->next->child=-1;
			 pnew->next->next=NULL;
			 pnew=pnew->next;
			 qqnew=qqnew->next;
		 }
	}
}

CTtree::CTtree(int m)
{
	nodes=new CTbox[m];
    n=m;
	r=0;
}
//根的双亲是-1     
CTtree::CTtree()
{
	//char A='A';
	char A='\0';
	int p,num;
	CTnode * pnew=NULL;
        cout<<"输入节点数:";
        cin>>num;
    nodes=new CTbox[num];//这个数组的元素是对象,不是指针
	for(int i=0;i<num;i++)
	{
		cout<<"输入节点的值(A--Z):";
        cin>>A;
		nodes[i].data=A;
        nodes[i].firstchild=new CTnode;
        nodes[i].firstchild->child=-1;
		nodes[i].firstchild->next=NULL;
		cout<<"输入节点的双亲位置下标:";
		cin>>p;
       
        nodes[i].parent=p;
        //如果双亲值不是-1,且双亲值必比当前插入结点数小,说明该结点其双亲已经存在,那么就
        //为它的双亲创建孩子节点(链表)
        if(p<i&&p!=-1)
          {
			  pnew=nodes[p].firstchild;
			  while(pnew->next!=NULL&&pnew->child!=-1)
			  {
				  pnew=pnew->next;
			  }
			  pnew->next=new CTnode;
                          //pnew=pnew->next;
			  pnew->child=i;
                          pnew->next->child=-1;
			  pnew->next->next=NULL;
		  }
	     
	}

   r=0;
   n=num;
}

//重载输出操作符
//按输入节点顺序打印,并在对应节点下输出其孩子节点data  样式如‘->B’
ostream& operator<<(ostream& output,CTtree& p)
{
	CTbox *q;
    CTnode *pnew;
     bool childs=false;
	for(int i=0;i<p.n;i++)
	{
		q=&(p.nodes[i]);
		cout<<q->data<<' '<<q->parent<<endl;
		pnew=q->firstchild;
		while(pnew->next!=NULL&&pnew->child!=-1)
		{
                        childs=true;
			cout<<q->data<<"->"<<p.nodes[pnew->child].data<<' ';
			pnew=pnew->next;
		}
                if(childs)     //如果该节点有孩子,则换行,方便下一个节点打印,纯属是为了格式更好看
               {
                cout<<endl;
                childs=false;
                }
	}
	return output;
}

//计算当前树的深度
int CTtree::Treedepth()
{
	int m=0,c=0;
    int i=0;
	for(;i<n;)
	{
       while(i<n&&c==nodes[i].parent)
	   {
         i++; 
	   }
         if(i<n)
           {
	   c=nodes[i].parent;
	   if(nodes[nodes[i].parent].parent!=nodes[nodes[i-1].parent].parent)
	   m++;
          }
         else
         {
            if(c!=nodes[i-1].parent)
             {
                if(nodes[nodes[i].parent].parent!=nodes[nodes[i-1].parent].parent)
                m++;
             }
         }
	}
	return m;
}

int CTtree::Value(char cur_e)
{
	int i=0;
    while(nodes[i].data!=cur_e&&i<n)
		i++;
	if(i>=n)
		return -2;
	else
		return nodes[i].parent;
}

char CTtree::Leftchild(char cur_e)
{
	int i=0,m=0;
	while(nodes[i].data!=cur_e&&i<n)
		i++;
	if(i>=n)
		return '\0';
	m=i;                           //记录下该节点索引,第几个节点
	while(nodes[m].parent!=i&&m<n) //它的孩子的索引肯定比它自己索引要大,因此继续往下找以它为双亲的第一个结点就是它的左孩子
    m++;
	if(i>=n)
		return '\0';
	else
		return nodes[m].data;
}
//
void CTtree::Findsibling(char cur_e)
{
	int i=0,m=0;
	CTnode * pnew;
		while(nodes[i].data!=cur_e&&i<n)
					i++;
		if(i>=n)
			return;
else if(i==0)
{
  cout<<"根无兄弟节点"<<endl;
return;
}
     pnew=nodes[nodes[i].parent].firstchild;//得到该节点双亲结点
     //对这双亲的孩子进行打印,但是不打印自身
     while(pnew!=NULL)
	 {
                 if(nodes[pnew->child].data!=nodes[i].data)
		 cout<<nodes[pnew->child].data<<' ';
		 pnew=pnew->next;
	 }
	 cout<<endl;
}

//需要添加一个复制构造函数
//调试的时候遇到运行过程中会把一些变量值改变,是因为在CTtree pnew(m)的构造函数中的参数变量传递的时候搞错了
//导致创建new的空间指针出现指向错误,以致与改变了一些参数值

CTtree CTtree::Insertchild(char cur_e,CTtree &c)
{
     int m=n+c.n;   //计算树c和当前树的节点数量
	 int i=0,j=0,k=-1;

	 CTtree pnew(m); //创建新的空树
	 CTnode *pnode,*qqnode;
	 //对当前对象进行了转存
	 for(;i<n;i++)
	 {
		 pnew.nodes[i].parent=nodes[i].parent;
		 pnew.nodes[i].data=nodes[i].data;
		 if(nodes[i].data==cur_e)//在对应节点进行插入,就需要把该结点的序号保存下来 存到k中
			 k=i;
		 pnew.nodes[i].firstchild=new CTnode;
		 pnew.nodes[i].firstchild->child=-1;
		 pnew.nodes[i].firstchild->next=NULL;
                 
		 qqnode=pnew.nodes[i].firstchild;
		 pnode=nodes[i].firstchild;
		 while(pnode->next!=NULL&&pnode->child!=-1)
		 {
             qqnode->child=pnode->child;

			 qqnode->next=new CTnode;
			 qqnode->next->child=-1;
			 qqnode->next->next=NULL;
			 qqnode=qqnode->next;
             pnode=pnode->next;
		 }
	 }
	 //if(k==-1)
	//	 exit(1);



	 //下一步是对c树进行插入转存

     qqnode=pnew.nodes[k].firstchild;//得到要第k结点的孩子链表指针
	 while(qqnode->next!=NULL&&qqnode->child!=-1)
	 qqnode=qqnode->next;
         qqnode->child=i;       //k结点的下一个孩子肯定是c树的根结点,也就是第i个元素(i=当前树的n)
	 qqnode->next=new CTnode;
	 qqnode->next->child=-1;
	 qqnode->next->next=NULL;

		 for(;i<m&&j<c.n;j++,i++)
		 {
			 if(j==0)
			 {
                           pnew.nodes[i].parent=k;//c树的根节点双亲肯定是k结点
			 }
			 else
				 pnew.nodes[i].parent=n+c.nodes[j].parent;//c树的非根节点的双亲也就是在原来的基础上加上n(当前树的结点数量)
       
	 pnew.nodes[i].data=c.nodes[j].data;
	 pnew.nodes[i].firstchild=new CTnode;
	  pnew.nodes[i].firstchild->child=-1;
	 pnew.nodes[i].firstchild->next=NULL;
        
	  qqnode=pnew.nodes[i].firstchild;
	  pnode=c.nodes[j].firstchild;
      while(pnode->next!=NULL&&pnode->child!=-1)
	     {

	     qqnode->child=pnode->child+n;
             
             qqnode->next=new CTnode;
		 qqnode->next->child=-1;
		 qqnode->next->next=NULL;
		 qqnode=qqnode->next;
		 pnode=pnode->next;
	      }

		}

return pnew; 
}
/

int main()
{
	CTtree tree1,tree3;
	CTtree tree2(6);
	cout<<tree1<<endl;
	cout<<"深度值:"<<tree1.Treedepth()<<endl;
	cout<<"双亲:"<<tree1.Value('B')<<endl;
	cout<<"左孩子:"<<tree1.Leftchild('B')<<endl;
        cout<<"兄弟:";
	tree1.Findsibling('B');
        cout<<"tree3"<<endl;
	cout<<tree3<<endl;
	cout<<"深度值:"<<tree3.Treedepth()<<endl;
	cout<<"双亲:"<<tree3.Value('E')<<endl;
	cout<<"左孩子:"<<tree3.Leftchild('E')<<endl;
        cout<<"兄弟:";
	tree3.Findsibling('E');

	tree2=tree1.Insertchild('C',tree3);
	cout<<tree2<<endl;
	return 0;
}


在这里插入图片描述

  • 5
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值