樹變成二叉樹

/*
問題描述:
將樹變成二叉樹
引例:《數據結構(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;
}

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