1. 程式人生 > >[樹] 6.74 以廣義表的形式輸出樹(孩子兄弟連結串列CSTree)

[樹] 6.74 以廣義表的形式輸出樹(孩子兄弟連結串列CSTree)

題目來源:嚴蔚敏《資料結構》C語言版本習題冊 6.74

【題目】6.74 試寫一遞迴演算法,以6.73題給定的樹的廣義表表示法的字元序列形式輸出以孩子-兄弟連結串列表示的樹

【答案】

/*-----------------------------------------
 |6.74 以廣義表的形式輸出                 |
 -----------------------------------------*/
void PrintAsGList(CSTree T) {
	CSNode *child;
	visit(T->data);
	if (T->firstchild)
{ //有孩子 printf("("); for (child=T->firstchild; child->nextsibling; child=child->nextsibling) { PrintAsGList(child); printf(","); } PrintAsGList(child); printf(")"); } }

【完整答案】

/*-------------------
 |樹-孩子兄弟表達法 |
 -------------------*/
#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); } typedef struct CSNode{ TElemType data;
struct CSNode *firstchild, *nextsibling; }CSNode, *CSTree; /*------------------- |6.59 輸出T的所有邊 | -------------------*/ void TreePrintEdge(CSTree T) { CSNode *p; for (p=T->firstchild; p; p=p->nextsibling) { printf("(%c,%c)\n", T->data, p->data); //輸出T的孩子 TreePrintEdge(p); //輸出p的孩子 } } /*------------------------- |6.60 統計葉子結點的個數 | -------------------------*/ int TreeLeafCnt(CSTree T) { // 樹的葉子結點-->沒有孩子 int ret=0; CSNode *p; if (!T) return 0; else if (!T->firstchild) return 1; else { for (p=T->firstchild; p; p=p->nextsibling) ret += TreeLeafCnt(p); return ret; } } /*------------------------- |6.61 求樹的度 | -------------------------*/ int TreeDegree(CSTree T) { // 最大的孩子數 int max=-1; int cnt=0; CSNode *child; if (!T) return -1; //空樹 else if (!T->firstchild) return 0; //只有一個根結點,度為0 else { for (cnt=0,child=T->firstchild; child; child=child->nextsibling) cnt++; //求自己的度 max = cnt; //當前的最大值 for (child=T->firstchild; child; child=child->nextsibling) { cnt = TreeDegree(child); if (cnt>max) max=cnt; } return max; } } /*------------------------- |6.62 求樹的深度 | -------------------------*/ int TreeDepth(CSTree T) { int h1,h2; if (!T) return 0; else { h1 = TreeDepth(T->firstchild)+1; //T孩子的深度+1 h2 = TreeDepth(T->nextsibling); //T兄弟的深度 return h1>h2 ? h1 : h2; } } /*--------------------------------- |6.66 雙親表示法-->孩子兄弟表示式| ---------------------------------*/ #define MAX_TREE_SIZE 50 typedef struct PTNode{ TElemType data; int parent; //雙親的位置域 }PTNode; typedef struct{ PTNode nodes[MAX_TREE_SIZE]; int r,n; }PTree; CSTree CreateCSTreeByPTree(PTree T) { CSNode *tmp[MAX_TREE_SIZE]; //建立一個輔助的陣列,仿照PTree結點的位置存放 CSNode *p, *q; int i,parent; if (T.n<=0) return NULL; for (i=0; i<T.n; i++) { //雙親表按層序儲存 //建立新結點 p = (CSNode *)malloc(sizeof(CSNode)); if(!p) exit(OVERFLOW); //賦值 p->data = T.nodes[i].data;p->firstchild=p->nextsibling=NULL; //連線 parent=T.nodes[i].parent; //父親 if (parent!=-1) { //不是根結點 if (tmp[parent]->firstchild==NULL) tmp[parent]->firstchild=p; //第一個孩子 else { //不是第一個孩子 for (q=tmp[parent]->firstchild; q->nextsibling; q=q->nextsibling) ; //找到最後一個孩子 q->nextsibling = p; //連線 } } tmp[i]=p; } return tmp[0]; } /*--------------------------------- |6.67 二元組(F,C)建立CSTree | ---------------------------------*/ #define maxSize 50 Status CreateCSTreeByDuplet(CSTree *pT) { char input[5]; CSNode *queue[maxSize];int front,rear; CSNode *p, *q; front=rear=0; //對佇列初始化 for (scanf("%s", input); input[1]!='^'; scanf("%s", input)) { //建立結點 p = (CSNode *)malloc(sizeof(CSNode)); if (!p) exit(OVERFLOW); p->data=input[1];p->firstchild=p->nextsibling=NULL; //入佇列 queue[rear]=p;rear=(rear+1)%maxSize; //找爸爸 if (input[0]=='^') { //根結點-->不需要找爸爸 *pT = p; //傳出去 } else { for (q=queue[front]; q->data!=input[0]; front=(front+1)%maxSize,q=queue[front]) ; //找爸爸 //找哥哥 if (!q->firstchild) q->firstchild=p; //它是最大的 else { //它不是最大的 for(q=q->firstchild; q->nextsibling; q=q->nextsibling) ; //找最近的哥哥 q->nextsibling = p; //和哥哥牽手 } } } return OK; } /*----------------------------------------- |6.68 層次序列+每個結點的度-->構造CSTree | -----------------------------------------*/ CSTree CreateCSTreeByLevelDegree(char *levelstr, int *num) { int cnt,i,parent; CSNode *p; CSNode *tmp[maxSize]; //先建立結點 for (i=0; i < strlen(levelstr); ++i) { p = (CSNode *)malloc(sizeof(CSNode)); if (!p) exit(OVERFLOW); p->data = levelstr[i];p->firstchild=p->nextsibling=NULL; tmp[i]=p; } //連線 parent=0; //孩子的爸爸 cnt=0; //計數器:表示已經找了幾個孩子 i=1; //遍歷結點,為他們找爸爸 while (i<strlen(levelstr)) { if (num[parent]==0 || cnt==num[parent]) { //這個父親沒有孩子 || parent的孩子已經找完了 cnt=0; //計數器歸0 parent++; //位移一位 continue; } //這個父親有孩子(i是parent的孩子) cnt++; if (cnt==1) { //i是parent的第一個孩子 tmp[parent]->firstchild = tmp[i]; } else { //不是第一個孩子 tmp[i-1]->nextsibling = tmp[i]; //它是前面的兄弟 } i++; } return tmp[0]; } /*----------------------------------------- |6.71 以樹狀的形式輸出 | -----------------------------------------*/ void PrintAsTree(CSTree T,int i) { /*思路: 1. 觀察題目輸出的序列ABEFCGD 2. 此為樹的先根遍歷-->對應為二叉樹儲存的先序遍歷 3. 前面的空格是該結點所在的層數 */ int cnt; if (T) { //輸出空格 for (cnt=1; cnt<i; cnt++) printf(" "); //輸出字元 visit(T->data); printf("\n"); PrintAsTree(T->firstchild, i+1); PrintAsTree(T->nextsibling, i); } } /*----------------------------------------- |6.73 用廣義表的形式構造 | -----------------------------------------*/ Status CreateCSTreeByGList(CSTree *pT) { char c; while (1) { c = getchar(); if (c>='A' && c<='Z') { //根結點 *pT = (CSNode *)malloc(sizeof(CSNode)); if (!*pT) exit(OVERFLOW); (*pT)->data = c; (*pT)->firstchild=(*pT)->nextsibling=NULL; } else if (c=='(') { //是我的第一個孩子 CreateCSTreeByGList(&(*pT)->firstchild); } else if (c==',') { //是我的兄弟 CreateCSTreeByGList(&(*pT)->nextsibling); break; //這裡要返回 } else break; } return OK; } /*----------------------------------------- |6.74 以廣義表的形式輸出 | -----------------------------------------*/ void PrintAsGList(CSTree T) { CSNode *child; visit(T->data); if (T->firstchild) { //有孩子 printf("("); for (child=T->firstchild; child->nextsibling; child=child->nextsibling) { PrintAsGList(child); printf(","); } PrintAsGList(child); printf(")"); } } int main() { /*6.74測試資料 A(B(E,F),C(G),D) */ CSTree CST; CreateCSTreeByGList(&CST); //6.73 PrintAsGList(CST); //6.74 return 0; }