树变成二叉树

/*
问题描述:
将树变成二叉树
引例:《数据结构(C语言版)》清华大学出版社
P135下图

input.data 数据如下:

10
R
A
R
B
R
C
R
D
A
E
A
F
C
G
F
H
F
K
F
 
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_TREE_SIZE 20
typedef char TElemType; 

typedef struct CTNode{
	int child;
	struct CTNode * next;
}ChildPtr;

typedef struct{
	int parent;//保存父亲结点下标 
	TElemType data;
	ChildPtr * firstchild;
}CTBox;

typedef struct{
	CTBox nodes[MAX_TREE_SIZE];
	int n,r;
}CTree;

CTree * Init()
{
	CTree *ct;
	ChildPtr *p,*q;
	int i,j;
	char temp;
	
	ct = (CTree *)malloc(sizeof(CTree));
	memset(ct,0,sizeof(CTree));
	printf("请输入树的结点个数:");
	scanf("%d",&ct->n);
	getchar();
	
	//输入每个结点的信息 
	//输入顺序:按层,每层从左往右 
	for(i=0;i<ct->n;i++){
		printf("请输入第%d个结点的信息:\n",i+1);
		printf("请输入该结点的字母信息:\n");
		scanf("%c",&ct->nodes[i].data);
		getchar();
		if(i){//不是根结点
			printf("请输入该结点的父亲结点的字母信息:");
			scanf("%c",&temp);
			getchar();
			for(j=0;j<i && ct->nodes[j].data - temp;j++);
			if(j == i){
				printf("查询父亲结点失败!\n");
				exit(0);
			}
			ct->nodes[i].parent = j;//设置从当前结点到父亲结点的指向 
			
			//遍历当前结点的父亲结点的孩子链,给其添加当前结点的信息 (装箱算法)
			p = (ChildPtr *)malloc(sizeof(ChildPtr));
			p->child = i;
			p->next = NULL;
			for(q = ct->nodes[j].firstchild ;q && q->next; q = q->next);
			if(q){//该结点不是第一个孩子 
				q->next = p;
			}
			else//该结点是第一个孩子
				ct->nodes[j].firstchild = p;
		}
		else{//是根结点,自动确定父亲结点为-1 
			ct->nodes[i].parent = -1;
			ct->r = i;
		}
	}
	
	return ct;
}

void PrintCTree(CTree *ct)
{
	int i;
	ChildPtr *p;
	
	for(i=0;i<ct->n;i++){
		printf("下标:%d 父亲下标:%d 数据:%c 孩子下标:",i,ct->nodes[i].parent,ct->nodes[i].data);
		for(p = ct->nodes[i].firstchild;p;p = p->next)
			printf("%d ",p->child);
		putchar('\n');
	}

}

void TransForm(CTree *ct)
{
	int i;
	ChildPtr *left,*other,*p;
	
	//把每个结点的孩子(如果有的话)分成最左边的孩子 和 其他的孩子两部分
	//让其他的孩子的parent指向最左边的孩子 
	//即断掉除最左边孩子外其他孩子和父亲结点的关系
	//删除父亲结点中除最左边孩子的信息外其他孩子的信息
	//这些信息接在最左边孩子的原有的孩子信息的后面 
	
	for(i=0;i<ct->n;i++){
		left = ct->nodes[i].firstchild;
		if(left){//左孩子存在 
			if(ct->nodes[i].firstchild && ct->nodes[i].firstchild->next 
			&& !ct->nodes[i].firstchild->next->next && i != ct->r){
			//孩子只有两个,无需转化 
			//根结点的孩子必须转化 
				continue;
			}
			
			for(other = left->next;other;other = other->next){
				ct->nodes[other->child].parent = left->child;//改指向 
			}
			other = left->next;
			left->next = NULL;
			for(p = ct->nodes[left->child].firstchild;p && p->next;p = p->next);
			if(p){
				p->next = other;
			}
			else
				ct->nodes[left->child].firstchild = other;			
		}
	}
}

void Preorder(CTree *ct,int subscript)
{
	ChildPtr *p;
	
	printf("%c ",ct->nodes[subscript].data);
	p = ct->nodes[subscript].firstchild;
	if(p){//如果有第一个孩子 
		Preorder(ct,p->child);
		if(p->next)
			Preorder(ct,p->next->child);
	}
}

int main(void)
{
	CTree *ct;
	
	freopen("input.data","r",stdin); 
	//Init 文件input.data中测试用例 以书上所给图示为例 
	ct = Init();
	printf("树信息如下:\n");
	PrintCTree(ct);
	printf("\n\n将树二叉树化:\n\n");
	TransForm(ct);
	PrintCTree(ct);
	printf("\n\n二叉树中序遍历:\n\n");
	Preorder(ct,ct->r); 
	
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章