/*
問題描述:
將樹變成二叉樹
引例:《數據結構(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;
}
樹變成二叉樹
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.