[樹] 6.75|6.76 由廣義表構造樹(孩子連結串列CTree)並以廣義表的形式輸出
阿新 • • 發佈:2018-12-13
題目來源:嚴蔚敏《資料結構》C語言版本習題冊 6.75、6.76
【題目】6.75 試寫以遞迴演算法,由6.73題定義的廣義表表示法的字元序列,構造樹的孩子連結串列。
【題目】6.76 試寫以遞迴演算法,以6.73題給定的樹的廣義表表示法的字元序列形式輸出以孩子連結串列表示的樹。
【測試資料】A(B(E,F),C(G),D)
【答案】
/*-------------------------
|6.75 用廣義表構造樹 |
-------------------------*/
// @Quesion:有一些格式檢測不了"A(" "A()" "A)("
Status CreateCTreeByGList (CTree *pT, int parent) {
// 建立新結點newNode --> 放在下標為pT->n
// 該結點的爸爸為parent
char c;
CNode *p, *q;
int newNode;
//建立newNode結點
newNode = pT->n; //新結點的下標
for (c=getchar(); c!='\n'; c=getchar() ) {
if (c>='A' && c<='Z') { // 結點資訊
pT->nodes[newNode].data = c; //給結點賦值
pT->nodes[ newNode].firstchild = NULL; //給結點賦值
pT->n++; //結點數+1
//newNode有爸爸,即parent
if (parent!=-1) {
//建立孩子結點
p = (CNode *)malloc(sizeof(CNode));if (!p) exit(OVERFLOW);
p->index = newNode;
p->next = NULL;
//兒子父親相認
if (pT->nodes[parent].firstchild==NULL) {
pT->nodes[ parent].firstchild = p;
} else {
for (q=pT->nodes[parent].firstchild; q->next; q=q->next) ;
q->next = p;
}
}
} else if (c=='(') { //是newNode的孩子
CreateCTreeByGList(pT, newNode); //開始建立newNode的孩子
} else if (c==',') { //是newNode的兄弟,即parent的下一個孩子
CreateCTreeByGList(pT, parent); //parent的下一個孩子
return OK; //newNode結點構造完成(自己建立了、孩子建立了、兄弟建立了)
} else if (c==')') { //parent構造完畢
return OK;
} else {
return ERROR; //格式錯誤
}
}
return OK;
}
/*-------------------------
|6.76 以廣義表的形式輸出 |
-------------------------*/
Status PrintAsGList(CTree T,int parent) {
CNode *p;
if (T.n<=0) return ERROR;
visit(T.nodes[parent].data);
if (T.nodes[parent].firstchild) {
printf("(");
for (p=T.nodes[parent].firstchild; p; p=p->next) {
PrintAsGList(T, p->index);
if (p->next) printf(",");
}
printf(")");
}
return OK;
}
【完整程式碼】
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#ifndef BASE
#define BASE
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int bool;
#endif
#define TElemType char
void visit(TElemType e) {
printf("%c", e);
}
#define MAX_TREE_SIZE 100
#define maxSize 50
typedef struct CNode{
int index; //這個孩子的結點號(注意:在嚴書中變數名為child)
struct CNode *next; //下一個孩子結點
}CNode, *ChildPtr; //孩子結點結構(在嚴書中名為CTNode)
typedef struct{
TElemType data;
CNode* firstchild;
}PNode; //雙親結點結構(在嚴書中,結構名為CTBox)
typedef struct{
PNode nodes[MAX_TREE_SIZE];
int n,r; //結點數 和 根結點的位置
}CTree; //樹結構
// 先根遍歷
void SubPreOrder(CTree T, int index) {
CNode *child;
visit(T.nodes[index].data);
for (child=T.nodes[index].firstchild; child; child=child->next)
SubPreOrder(T, child->index);
}
void PreOrder(CTree T) {
SubPreOrder(T, T.r);
}
/*-------------------------
|6.63 求樹的深度 |
-------------------------*/
int SubTreeDepth(CTree T, int index) { //序號為index的子樹深度
int max=-1; //孩子的最大深度
int sd; //孩子的深度
CNode *p;
if (!T.nodes[index].firstchild) return 1; //沒有孩子,深度為1
for (p=T.nodes[index].firstchild; p; p=p->next) { //遍歷該結點的所有孩子
sd = SubTreeDepth(T, p->index); //求孩子的深度
if (max<sd) max=sd;
}
return max+1; //孩子的最大深度+1
}
int TreeDepth(CTree T) {
return SubTreeDepth(T, T.r);
}
/*-------------------------
|6.72 將樹列印成樹狀 |
-------------------------*/
void PrintAsTree(CTree T, int index, int i) {
/*思路
1. 觀察題目輸出的序列ABEFCGD
2. 此為樹的先根遍歷–>對應為二叉樹儲存的先序遍歷
3. 前面的空格是該結點所在的層數
*/
CNode *p;
int cnt;
//輸出空格
for (cnt=1; cnt<i; cnt++) printf(" ");
//輸出元素
visit(T.nodes[index].data);printf("\n");
//遍歷它的孩子
for(p=T.nodes[index].firstchild; p; p=p->next)
PrintAsTree(T, p->index, i+1);
}
// 樹的層序次序+每個結點的度 --> 建立CTree
Status CreateCTreeByLevelDegree(CTree *pT,char *levelstr, int *degree) {
CNode *c,*sibling;
int parent;
int i,cnt;
//建立結點
for (i=0; i<strlen(levelstr); ++i) {
//賦值
pT->nodes[i].data = levelstr[i];
pT->nodes[i].firstchild = NULL;
}
pT->n=strlen(levelstr); //個數
pT->r=0; //根結點
//為孩子找爸爸
parent=0; //當前的爸爸
i=1; //遍歷孩子
cnt=0; //已經為parent找到了cnt個孩子
while (i<strlen(levelstr)) {
if (degree[parent]==0 || cnt==degree[parent]) { //parent沒有孩子 || parent的孩子已經全部找到
cnt=0;
parent++;
continue;
}
cnt++; //為parent找到了一個孩子
//建立孩子結點
c = (CNode *)malloc(sizeof(CNode)); if (!c) exit(OVERFLOW);
c->index = i; //孩子的編號
c->next = NULL;
if (cnt==1) { //第一個孩子
pT->nodes[parent].firstchild = c;
} else { //不是第一個孩子
for(sibling=pT->nodes[parent].firstchild; sibling->next; sibling=sibling->next) ;
sibling->next = c;
}
i++;
}
return TRUE;
}
/*-------------------------
|6.75 用廣義表構造樹 |
-------------------------*/
// @Quesion:有一些格式檢測不了"A(" "A()" "A)("
Status CreateCTreeByGList(CTree *pT, int parent) {
// 建立新結點newNode --> 放在下標為pT->n
// 該結點的爸爸為parent
char c;
CNode *p, *q;
int newNode;
//建立newNode結點
newNode = pT->n; //新結點的下標
for (c=getchar(); c!='\n'; c=getchar() ) {
if (c>='A' && c<='Z') { // 結點資訊
pT->nodes[newNode].data = c; //給結點賦值
pT->nodes[newNode].firstchild = NULL; //給結點賦值
pT->n++; //結點數+1
//newNode有爸爸,即parent
if (parent!=-1) {
//建立孩子結點
p = (CNode *)malloc(sizeof(CNode));if (!p) exit(OVERFLOW);
p->index = newNode;
p->next = NULL;
//兒子父親相認
if (pT->nodes[parent].firstchild==NULL) {
pT->nodes[parent].firstchild = p;
} else {
for (q=pT->nodes[parent].firstchild; q->next; q=q->next) ;
q->next = p;
}
}
} else if (c=='(') { //是newNode的孩子
CreateCTreeByGList(pT, newNode); //開始建立newNode的孩子
} else if (c==',') { //是newNode的兄弟,即parent的下一個孩子
CreateCTreeByGList(pT, parent); //parent的下一個孩子
return OK; //newNode結點構造完成(自己建立了、孩子建立了、兄弟建立了)
} else if (c==')') { //parent構造完畢
return OK;
} else {
return ERROR; //格式錯誤
}
}
return OK;
}
/*-------------------------
|6.76 以廣義表的形式輸出 |
-------------------------*/
Status PrintAsGList(CTree T,int parent) {
CNode *p;
if (T.n<=0) return ERROR;
visit(T.nodes[parent].data);
if (T.nodes[parent].firstchild) {
printf("(");
for (p=T.nodes[parent].firstchild; p; p=p->next) {
PrintAsGList(T, p->index);
if (p->next) printf(",");
}
printf(")");
}
return OK;
}
int main() {
/*6.75測試資料
A(B(E,F),C(G),D)
A
A(B)
A(B,C)
A(B,C(D,E))
*/
CTree T;
T.n=0;T.r=0;
CreateCTreeByGList(&T, -1); //6.75
PrintAsGList(T, T.r); //6.76
return 0;
}