/* c6-5.h 树的二叉链表(孩子-兄弟)存储表示 */ typedef struct CSNode { TElemType data; struct CSNode *firstchild,*nextsibling; }CSNode,*CSTree;
/* bo6-5.c 树的二叉链表(孩子-兄弟)存储(存储结构由c6-5.h定义)的基本操作(17个) */ Status InitTree(CSTree *T) { /* 操作结果: 构造空树T */ *T=NULL; return OK; } void DestroyTree(CSTree *T) { /* 初始条件: 树T存在。操作结果: 销毁树T */ if(*T) { if((*T)->firstchild) /* T有长子 */ DestroyTree(&(*T)->firstchild); /* 销毁T的长子为根结点的子树 */ if((*T)->nextsibling) /* T有下一个兄弟 */ DestroyTree(&(*T)->nextsibling); /* 销毁T的下一个兄弟为根结点的子树 */ free(*T); /* 释放根结点 */ *T=NULL; } } typedef CSTree QElemType; /* 定义队列元素类型 */ #include"c3-2.h" /* 定义LinkQueue类型 */ #include"bo3-2.c" /* LinkQueue类型的基本操作 */ Status CreateTree(CSTree *T) { /* 构造树T */ char c[20]; /* 临时存放孩子结点(设不超过20个)的值 */ CSTree p,p1; LinkQueue q; int i,l; InitQueue(&q); printf("请输入根结点(字符型,空格为空): "); scanf("%c%*c",&c[0]); if(c[0]!=Nil) /* 非空树 */ { *T=(CSTree)malloc(sizeof(CSNode)); /* 建立根结点 */ (*T)->data=c[0]; (*T)->nextsibling=NULL; EnQueue(&q,*T); /* 入队根结点的指针 */ while(!QueueEmpty(q)) /* 队不空 */ { DeQueue(&q,&p); /* 出队一个结点的指针 */ printf("请按长幼顺序输入结点%c的所有孩子: ",p->data); gets(c); l=strlen(c); if(l>0) /* 有孩子 */ { p1=p->firstchild=(CSTree)malloc(sizeof(CSNode)); /* 建立长子结点 */ p1->data=c[0]; for(i=1;i<l;i++) { p1->nextsibling=(CSTree)malloc(sizeof(CSNode)); /* 建立下一个兄弟结点 */ EnQueue(&q,p1); /* 入队上一个结点 */ p1=p1->nextsibling; p1->data=c[i]; } p1->nextsibling=NULL; EnQueue(&q,p1); /* 入队最后一个结点 */ } else p->firstchild=NULL; } } else *T=NULL; return OK; } #define ClearTree DestroyTree /* 二者操作相同 */ Status TreeEmpty(CSTree T) { /* 初始条件: 树T存在。操作结果: 若T为空树,则返回TURE,否则返回FALSE */ if(T) /* T不空 */ return FALSE; else return TRUE; } int TreeDepth(CSTree T) { /* 初始条件: 树T存在。操作结果: 返回T的深度 */ CSTree p; int depth,max=0; if(!T) /* 树空 */ return 0; if(!T->firstchild) /* 树无长子 */ return 1; for(p=T->firstchild;p;p=p->nextsibling) { depth=TreeDepth(p); if(depth>max) max=depth; } return max+1; } TElemType Value(CSTree p) { /* 返回p所指结点的值 */ return p->data; } TElemType Root(CSTree T) { /* 初始条件: 树T存在。操作结果: 返回T的根 */ if(T) return Value(T); else return Nil; } CSTree Point(CSTree T,TElemType s) { /* 返回二叉链表(孩子-兄弟)树T中指向元素值为s的结点的指针。另加 */ LinkQueue q; QElemType a; if(T) /* 非空树 */ { InitQueue(&q); /* 初始化队列 */ EnQueue(&q,T); /* 根结点入队 */ while(!QueueEmpty(q)) /* 队不空 */ { DeQueue(&q,&a); /* 出队,队列元素赋给a */ if(a->data==s) return a; if(a->firstchild) /* 有长子 */ EnQueue(&q,a->firstchild); /* 入队长子 */ if(a->nextsibling) /* 有下一个兄弟 */ EnQueue(&q,a->nextsibling); /* 入队下一个兄弟 */ } } return NULL; } Status Assign(CSTree *T,TElemType cur_e,TElemType value) { /* 初始条件: 树T存在,cur_e是树T中结点的值。操作结果: 改cur_e为value */ CSTree p; if(*T) /* 非空树 */ { p=Point(*T,cur_e); /* p为cur_e的指针 */ if(p) /* 找到cur_e */ { p->data=value; /* 赋新值 */ return OK; } } return Nil; /* 树空或没找到 */ } TElemType Parent(CSTree T,TElemType cur_e) { /* 初始条件: 树T存在,cur_e是T中某个结点 */ /* 操作结果: 若cur_e是T的非根结点,则返回它的双亲,否则函数值为"空" */ CSTree p,t; LinkQueue q; InitQueue(&q); if(T) /* 树非空 */ { if(Value(T)==cur_e) /* 根结点值为cur_e */ return Nil; EnQueue(&q,T); /* 根结点入队 */ while(!QueueEmpty(q)) { DeQueue(&q,&p); if(p->firstchild) /* p有长子 */ { if(p->firstchild->data==cur_e) /* 长子为cur_e */ return Value(p); /* 返回双亲 */ t=p; /* 双亲指针赋给t */ p=p->firstchild; /* p指向长子 */ EnQueue(&q,p); /* 入队长子 */ while(p->nextsibling) /* 有下一个兄弟 */ { p=p->nextsibling; /* p指向下一个兄弟 */ if(Value(p)==cur_e) /* 下一个兄弟为cur_e */ return Value(t); /* 返回双亲 */ EnQueue(&q,p); /* 入队下一个兄弟 */ } } } } return Nil; /* 树空或没找到cur_e */ } TElemType LeftChild(CSTree T,TElemType cur_e) { /* 初始条件: 树T存在,cur_e是T中某个结点 */ /* 操作结果: 若cur_e是T的非叶子结点,则返回它的最左孩子,否则返回"空" */ CSTree f; f=Point(T,cur_e); /* f指向结点cur_e */ if(f&&f->firstchild) /* 找到结点cur_e且结点cur_e有长子 */ return f->firstchild->data; else return Nil; } TElemType RightSibling(CSTree T,TElemType cur_e) { /* 初始条件: 树T存在,cur_e是T中某个结点 */ /* 操作结果: 若cur_e有右兄弟,则返回它的右兄弟,否则返回"空" */ CSTree f; f=Point(T,cur_e); /* f指向结点cur_e */ if(f&&f->nextsibling) /* 找到结点cur_e且结点cur_e有右兄弟 */ return f->nextsibling->data; else return Nil; /* 树空 */ } Status InsertChild(CSTree *T,CSTree p,int i,CSTree c) { /* 初始条件: 树T存在,p指向T中某个结点,1≤i≤p所指结点的度+1,非空树c与T不相交 */ /* 操作结果: 插入c为T中p结点的第i棵子树 */ /* 因为p所指结点的地址不会改变,故p不需是引用类型 */ int j; if(*T) /* T不空 */ { if(i==1) /* 插入c为p的长子 */ { c->nextsibling=p->firstchild; /* p的原长子现是c的下一个兄弟(c本无兄弟) */ p->firstchild=c; } else /* 找插入点 */ { p=p->firstchild; /* 指向p的长子 */ j=2; while(p&&j<i) { p=p->nextsibling; j++; } if(j==i) /* 找到插入位置 */ { c->nextsibling=p->nextsibling; p->nextsibling=c; } else /* p原有孩子数小于i-1 */ return ERROR; } return OK; } else /* T空 */ return ERROR; } Status DeleteChild(CSTree *T,CSTree p,int i) { /* 初始条件: 树T存在,p指向T中某个结点,1≤i≤p所指结点的度 */ /* 操作结果: 删除T中p所指结点的第i棵子树 */ /* 因为p所指结点的地址不会改变,故p不需是引用类型 */ CSTree b; int j; if(*T) /* T不空 */ { if(i==1) /* 删除长子 */ { b=p->firstchild; p->firstchild=b->nextsibling; /* p的原次子现是长子 */ b->nextsibling=NULL; DestroyTree(&b); } else /* 删除非长子 */ { p=p->firstchild; /* p指向长子 */ j=2; while(p&&j<i) { p=p->nextsibling; j++; } if(j==i) /* 找到第i棵子树 */ { b=p->nextsibling; p->nextsibling=b->nextsibling; b->nextsibling=NULL; DestroyTree(&b); } else /* p原有孩子数小于i */ return ERROR; } return OK; } else return ERROR; } void PreOrderTraverse(CSTree T,void(*Visit)(TElemType)) { /* 先根遍历孩子-兄弟二叉链表结构的树T */ if(T) { Visit(Value(T)); /* 先访问根结点 */ PreOrderTraverse(T->firstchild,Visit); /* 再先根遍历长子子树 */ PreOrderTraverse(T->nextsibling,Visit); /* 最后先根遍历下一个兄弟子树 */ } } void PostOrderTraverse(CSTree T,void(*Visit)(TElemType)) { /* 后根遍历孩子-兄弟二叉链表结构的树T */ CSTree p; if(T) { if(T->firstchild) /* 有长子 */ { PostOrderTraverse(T->firstchild,Visit); /* 后根遍历长子子树 */ p=T->firstchild->nextsibling; /* p指向长子的下一个兄弟 */ while(p) { PostOrderTraverse(p,Visit); /* 后根遍历下一个兄弟子树 */ p=p->nextsibling; /* p指向再下一个兄弟 */ } } Visit(Value(T)); /* 最后访问根结点 */ } } void LevelOrderTraverse(CSTree T,void(*Visit)(TElemType)) { /* 层序遍历孩子-兄弟二叉链表结构的树T */ CSTree p; LinkQueue q; InitQueue(&q); if(T) { Visit(Value(T)); /* 先访问根结点 */ EnQueue(&q,T); /* 入队根结点的指针 */ while(!QueueEmpty(q)) /* 队不空 */ { DeQueue(&q,&p); /* 出队一个结点的指针 */ if(p->firstchild) /* 有长子 */ { p=p->firstchild; Visit(Value(p)); /* 访问长子结点 */ EnQueue(&q,p); /* 入队长子结点的指针 */ while(p->nextsibling) /* 有下一个兄弟 */ { p=p->nextsibling; Visit(Value(p)); /* 访问下一个兄弟 */ EnQueue(&q,p); /* 入队兄弟结点的指针 */ } } } } }
/* main6-5.c 检验bo6-5.c的主程序 */ #include"c1.h" typedef char TElemType; TElemType Nil=' '; /* 以空格符为空 */ #include"c6-5.h" #include"bo6-5.c" void vi(TElemType c) { printf("%c ",c); } void main() { int i; CSTree T,p,q; TElemType e,e1; InitTree(&T); printf("构造空树后,树空否? %d(1:是 0:否) 树根为%c 树的深度为%d\n",TreeEmpty(T),Root(T),TreeDepth(T)); CreateTree(&T); printf("构造树T后,树空否? %d(1:是 0:否) 树根为%c 树的深度为%d\n",TreeEmpty(T),Root(T),TreeDepth(T)); printf("先根遍历树T:\n"); PreOrderTraverse(T,vi); printf("\n请输入待修改的结点的值 新值: "); scanf("%c%*c%c%*c",&e,&e1); Assign(&T,e,e1); printf("后根遍历修改后的树T:\n"); PostOrderTraverse(T,vi); printf("\n%c的双亲是%c,长子是%c,下一个兄弟是%c\n",e1,Parent(T,e1),LeftChild(T,e1),RightSibling(T,e1)); printf("建立树p:\n"); InitTree(&p); CreateTree(&p); printf("层序遍历树p:\n"); LevelOrderTraverse(p,vi); printf("\n将树p插到树T中,请输入T中p的双亲结点 子树序号: "); scanf("%c%d%*c",&e,&i); q=Point(T,e); InsertChild(&T,q,i,p); printf("层序遍历树T:\n"); LevelOrderTraverse(T,vi); printf("\n删除树T中结点e的第i棵子树,请输入e i: "); scanf("%c%d",&e,&i); q=Point(T,e); DeleteChild(&T,q,i); printf("层序遍历树T:\n",e,i); LevelOrderTraverse(T,vi); printf("\n"); DestroyTree(&T); }
相关推荐
在C语言中,实现树的存储结构有多种方法,其中一种常见的方式是使用二叉链表,即“孩子-兄弟”存储结构。这种结构允许我们高效地表示和操作树中的节点,特别适用于那些节点具有多个子节点的情况。 “孩子-兄弟”...
【树的二叉链表(孩子-兄弟)存储表示】是一种将树结构转换为二叉链表的方法,目的是为了方便地实现树的各种操作。在该表示中,每个节点包含两个指针:`firstchild` 指向其第一个孩子,`nextsibling` 指向其下一个...
儿子兄弟链表存储的二叉树,其前序、后序、层次遍历实现
要求选用顺序存储结构和二叉链表存储结构实现抽象数据类型二叉树的基本操作。有个亮点是利用字符在dos界面显示二叉树的结构形态。 里面包含了完整的源程序和实验报告文档。 实验报告包含了完整的步骤包括: 一.抽象...
实现了二叉树的多种操作:添加、删除、拷贝、清空、树深度计算、父节点、兄弟节点获取、先中后序递归及非遍历、按层次遍历、中序迭代器(非递归算法)、节点查找、先序和中序序列重建二叉树、数组和二叉链表存储结构...
5. **孩子兄弟链表**:将二叉链表转换为孩子兄弟链表,每个节点不仅有左右子节点指针,还有指向下一个兄弟节点的指针。计算森林(多个无根二叉树)的叶子个数,需要对每棵树进行叶子计数。 6. **中序线索二叉树**:...
- **兄弟节点**:对于非根节点,没有左孩子的兄弟是其双亲的右孩子,没有右孩子的兄弟是其双亲的左孩子。 - **祖先节点**:从根节点开始,沿着从根到目标节点的路径,所有节点都是目标节点的祖先。 - **复制...
本类是儿子兄弟链表类。 利用和二叉链表一样的方法构建这棵树。 分析其前序遍历,后序遍历,层次遍历的方法,和二叉树很相像。
二叉链表的每个节点包含两个指针,分别指向其左孩子和右孩子,以及存储数据的元素。为了实现二叉树的操作,实验设计了以下结构: 1. **InitTree**:初始化二叉链表,分配存储空间并设置头结点。 2. **DestroyTree**...
这个压缩包文件"数据结构——二叉树的实现.zip"显然包含了关于二叉树实现的详细内容,特别是二叉链表和左子右兄弟两种不同的实现方法。 首先,我们来探讨二叉链表的实现。二叉链表是最基础的二叉树存储方式,每个...
从二叉链表转换为孩子兄弟表示法,需要创建一个新的节点结构,包含一个指向第一个孩子的指针和一个指向下一个兄弟的指针,同时调整节点间的连接关系。 二叉树的遍历和操作是编程竞赛和面试中常见的问题,理解并...
- 孩子兄弟表示法:每个节点存储指向第一个孩子节点和下一个兄弟节点的指针。 5. 二叉树: 二叉树是树的一个特例,其中每个节点最多有两个子节点,分别称为左子节点和右子节点。二叉树的性质和存储方法与一般的树...
在实验中,二叉链表通过堆栈和队列的存储结构得以实现,以支持高效的数据操作。 1. 实验内容: - **初始化二叉链表(InitTree)**:此功能用于初始化二叉链表,分配存储空间,并设置头结点。时间复杂度为O(1),因为...
在实际应用中,孩子兄弟链表法常用于树的序列化和反序列化,因为这种表示方式可以方便地通过线性顺序来存储和恢复二叉树。此外,它也适用于某些特定的二叉树算法,如二叉搜索树的平衡调整、树的旋转操作等。 总之,...
【知识点详解】 在计算机科学中,树是一...总结来说,这个实验报告涵盖了树结构中的孩子-兄弟链表构造以及二叉搜索树的插入和打印操作,这些都是数据结构与算法中的基础内容,对理解和操作树型数据结构具有重要意义。
孩子-兄弟存储的树 CTree 二叉树线索化 先序 PreThreading 中序 InThreading 后序 PostThreading 最优二叉树 HuffmanTree 9 图 图类的实现 数组表示 ArrayGraph 邻接表表示 AdjLgraph 十字链表表示 OrLgraph ...
2. **排序**:通过构建特定类型的有值二叉树(如二叉查找树),可以实现数据的快速排序。 3. **数据压缩**:在某些情况下,有值二叉树可用于数据的编码与解码,实现数据压缩的目的。 ### 四、有值二叉树的遍历...
实现过程中,树的存储结构选择孩子-兄弟动态链表的二叉链表形式。初始构建时需要手动输入数据,但后续查询时,系统应能从文件中自动读取并生成树。为实现二叉链表与文件的转换,可以采用先序遍历的方式保存和恢复树...
- 双亲表示法、孩子链表表示法、孩子兄弟表示法都是树的存储方式,而顺序存储通常用于线性结构,不适合树。 8. **二叉线索树**: - 引入二叉线索树是为了在二叉树中方便地找到结点的前驱和后继。 - 二叉线索树的...
### B树、B-树、B+树、B*树详解 #### 一、B树 (Binary Search Tree) **定义**: - B树通常指的是**二叉搜索树**(Binary Search Tree, BST)。这是一种特殊的二叉树,其中每个节点最多有两个子节点(左子节点和右...