对于n叉树输入以及存储结构改变

 

       对于二叉树来说,输入时非常easy的,但对于n叉树,尤其时n\geq 2情况时,就显得略先困难。特别的,对于树的不同存储方式之间的转化就显得不是那么的容易,本文就n阶树孩子兄弟法(链式存储)存储转换为孩子法(邻接表)提供一个可靠的方法。

1.结构体的定义: 

邻接表由两部分组成:表头结点表和边表。

     邻接表中每个单链表的第一个结点存放有关顶点的信息,把这一结点看成链表的表头,其余结点存放有关边的信息

(1)表头结点表:包括数据域和链域,数据域存储顶点(data)的名称,链域(first)用于指向链表中第一个结点(与顶点邻接的第一个顶点)

(2)边表:包括邻接点域(指示与顶点邻接的点在图中的位置,即数组下标)、数据域(存储和边相关的信息,如权值)、链域(指示与顶点邻接的下一条边的结点)。

   在此处建立时,我们可以按层次建立:首先定义边表中节点:

struct ctnode {
    int child;
    struct ctnode* next;
};

 随后建立单层头表和边表:

typedef struct cno2 {
    int js;
    char data;
    struct ctnode* first;
}cbox; 

最后,定义多层即可建立:

typedef struct ccno
{
    cbox node[maxsize];
    int n, t;
}haitree; 

定义部分代码:

typedef struct cno {
	char data;
	struct cno* firstchild, * mbro;
}cnode,*ctree;
struct ctnode {
	int child;
	struct ctnode* next;
};
typedef struct cno2 {
	int js;
	char data;
	struct ctnode* first;
}cbox;
typedef struct ccno
{
	cbox node[maxsize];
	int n, t;
}haitree;

 2.树的变形(变为二叉树)

孩子兄弟表示法,采用的是链式存储结构

其存储的实现思想是:从树的根节点开始,依次用链表存储各个节点的孩子节点和兄弟节点

因此,该链表中的节点应包含以下 3 部分内容:

  1. 节点的值
  2. 指向孩子节点的指针
  3. 指向兄弟节点的指针

依据以上方法,可以将n叉树转化为二叉树。

存储结构:

typedef struct cno {
    char data;
    struct cno* firstchild, * mbro;
}cnode,*ctree;

以下为孩子兄弟法代码实现:

ctree creat()
{
	ctree p;
	char x;
	cin >> x;
	if (x == '#')
		return NULL;
	else
	{
		p = (cnode*)malloc(sizeof(cnode));
		p->data = x;
		p->firstchild = creat();
		p->mbro = creat();
	}
	return p;
}

3.n叉树先根和后根遍历

(1)、先根遍历:若树不为空,则先访问根,然后依次先根遍历各棵子树。

(2)、后根遍历:若树不为空,则先依次后根遍历各棵子树,然后再访问根结点。

 

void middletrave(ctree t)
{
	if (t == NULL)
		return;
	else
	{
        cout << t->data << " ";
		middletrave(t->firstchild);
		middletrave(t->mbro);
	}
}
void middletrave(ctree t)
{
	if (t == NULL)
		return;
	else
	{
		middletrave(t->firstchild);
		cout << t->data << " ";
		middletrave(t->mbro);
	}
}

4.孩子兄弟法转化为孩子法(邻接表)

(1). 表头节点对应值的填入:

          对于邻接表表头节点,就为树中出现的所有字符,因此,可以在遍历书的时候,依次建立         表头节点。

    (为了偷懒,就直接加入到上面的先序遍历中)

haitree ht;
void firsttrave(ctree t)
{
	if (t == NULL)
		return;
	else
	{
		ht.node[ht.n].data = t->data;
		ht.node[ht.n].js++;
		ht.node[ht.n].first = (ctnode*)malloc(sizeof(ctnode));
		ht.node[ht.n].first->child = -1;
		ht.node[ht.n].first->next = NULL;
		ht.n++;

		cout << t->data << " ";
		firsttrave(t->firstchild);
		firsttrave(t->mbro);
	}
}

其中ht定义为全局变量。

 (2).生成对应的邻接表数据:

      采用递归的方式扫描一个节点处理一个。

      在将节点值对应到具体的头节点时:

   (a).若左孩子不为NULL的(在原本的树结构中存在子节点)可以采用x1和x2记录该节点和该节点的左节点(第一个孩子),将两个和邻接表头节点对应,得到对应的节点号xh1和xh2,生成    节点后接入头节点。

     (b).若有孩子不为NULL(该点和右子点为兄弟关系),因此该点的父节点和右子点为同一个个,只需找到右子点对应的节点号,生成节点后接入。

void bian(ctree t)
{
	if (t->firstchild == NULL && t->mbro == NULL)
		return;
	char x1,x2,x3;
	int xh1,xh2,xh3;
	if (t->firstchild != NULL)
	{
	
		x1 = t->data;
		x2 = t->firstchild->data;
		for (int i = 0; i < ht.n; i++)
		{
			if (ht.node[i].data == x1)
			{
				xh1 = i;
			}
			if (ht.node[i].data == x2)
			{
				xh2 = i;
			}
		}
		ctnode *p,*q;
		p = (ctnode*)malloc(sizeof(ctnode));
		p->child = xh2;
		p->next = NULL;
		q = ht.node[xh1].first;
		if (q->next== NULL)
		{
			q->next = p;
		
		}
		else
		{
	     while (q ->next!= NULL)
		  {
			q = q->next;
		  }
		q->next = p;
		}
	

	}
	if (t->mbro != NULL)
	{
		x1 = t->data;
		x3= t->mbro->data;
		for (int i = 0; i < ht.n; i++)
		{
			if (ht.node[i].data == x1)
			{
				xh1 = i;
			}
			if (ht.node[i].data == x3)
			{
				xh3 = i;
			}
			
		}
		ctnode* p, * q;
		p = (ctnode*)malloc(sizeof(ctnode));
		p->child = xh3;
		p->next = NULL;
		q = ht.node[xh1].first;
		if (q->next == NULL)
		{
			q->next = p;
		
		}
		else
		{
	while (q->next != NULL)
		{
			q = q->next;
		}
		q->next = p;

		}
	
	}
	if(t->firstchild!=NULL)
	  bian(t->firstchild);
	if(t->mbro!=NULL)
	  bian(t->mbro);
}

5.输出邻接表结构

void ctrave(cbox p)
{
	ctnode *q;
	q = p.first;
	q = q->next;
	while (q != NULL)
	{
		cout << q->child << " ";
		q = q->next;
	}
}

      通过以上的方法,我们可以将孩子兄弟法(链表)轻松的转化为孩子法(邻接表),并将其结构输出。

以下是源代码:

#include<bits/stdc++.h>
using namespace std;
#define maxsize 100
typedef struct cno {
	char data;
	struct cno* firstchild, * mbro;
}cnode,*ctree;
struct ctnode {
	int child;
	struct ctnode* next;
};
typedef struct cno2 {
	int js;
	char data;
	struct ctnode* first;
}cbox;
typedef struct ccno
{
	cbox node[maxsize];
	int n, t;
}haitree;
haitree ht;
ctree creat()
{
	ctree p;
	char x;
	cin >> x;
	if (x == '#')
		return NULL;
	else
	{
		p = (cnode*)malloc(sizeof(cnode));
		p->data = x;
		p->firstchild = creat();
		p->mbro = creat();
	}
	return p;
}
void firsttrave(ctree t)
{
	if (t == NULL)
		return;
	else
	{
		ht.node[ht.n].data = t->data;
		ht.node[ht.n].js++;
		ht.node[ht.n].first = (ctnode*)malloc(sizeof(ctnode));
		ht.node[ht.n].first->child = -1;
		ht.node[ht.n].first->next = NULL;
		ht.n++;

		cout << t->data << " ";
		firsttrave(t->firstchild);
		firsttrave(t->mbro);
	}
}
void middletrave(ctree t)
{
	if (t == NULL)
		return;
	else
	{
		middletrave(t->firstchild);
		cout << t->data << " ";
		middletrave(t->mbro);
	}
}
void bian(ctree t)
{
	if (t->firstchild == NULL && t->mbro == NULL)
		return;
	char x1,x2,x3;
	int xh1,xh2,xh3;
	if (t->firstchild != NULL)
	{
	
		x1 = t->data;
		x2 = t->firstchild->data;
		for (int i = 0; i < ht.n; i++)
		{
			if (ht.node[i].data == x1)
			{
				xh1 = i;
			}
			if (ht.node[i].data == x2)
			{
				xh2 = i;
			}
		}
		ctnode *p,*q;
		p = (ctnode*)malloc(sizeof(ctnode));
		p->child = xh2;
		p->next = NULL;
		q = ht.node[xh1].first;
		if (q->next== NULL)
		{
			q->next = p;
		
		}
		else
		{
	     while (q ->next!= NULL)
		  {
			q = q->next;
		  }
		q->next = p;
		}
	

	}
	if (t->mbro != NULL)
	{
		x1 = t->data;
		x3= t->mbro->data;
		for (int i = 0; i < ht.n; i++)
		{
			if (ht.node[i].data == x1)
			{
				xh1 = i;
			}
			if (ht.node[i].data == x3)
			{
				xh3 = i;
			}
			
		}
		ctnode* p, * q;
		p = (ctnode*)malloc(sizeof(ctnode));
		p->child = xh3;
		p->next = NULL;
		q = ht.node[xh1].first;
		if (q->next == NULL)
		{
			q->next = p;
		
		}
		else
		{
	while (q->next != NULL)
		{
			q = q->next;
		}
		q->next = p;

		}
	
	}
	if(t->firstchild!=NULL)
	  bian(t->firstchild);
	if(t->mbro!=NULL)
	  bian(t->mbro);
}
void ctrave(cbox p)
{
	ctnode *q;
	q = p.first;
	q = q->next;
	while (q != NULL)
	{
		cout << q->child << " ";
		q = q->next;
	}
}
int main()
{
	ctree t;
	ht.node->js = 0;
	ht.n = 0;
	cout << "此方法用于树(n叉树,n>=2)。输入时用树和二叉树关系转化为二叉树" << endl;
	t = creat();
	cout << "先根遍历:";
	firsttrave(t);
	cout << endl;
	cout << "后根遍历:" << endl;
	middletrave(t);
	cout << endl;
	bian(t);
	cout << "孩子兄弟表示法(邻接表)"<<endl;
	for (int i = 0; i < ht.n; i++)
	{
		cout <<i<<" "<< ht.node[i].data << " ";
		ctrave(ht.node[i]);
		cout << endl;
	}
}

  • 22
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值