课程设计 树的应用与实现
任务概述:
(1)采用孩子双亲表示法,创建一棵一般的树,初始化树后添加孩子及其双亲结点,要求从键盘输入树中结点,并且结点数不少于五个;
(2)将树转成对应的二叉树,将结点的第一个孩子作为其左孩子,其余孩子作为其左孩子的右孩子;
(3)实现转换后二叉树的前序、中序、后序的递归遍历算法的实现;
(4)利用栈实现转换后二叉树的前序、中序、后序的非递归遍历算法的实现。
存储结构:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #define OVERFLOW -2 4 #define OK 0 5 #define ERROR 0 6 #define STACK_INIT_SIZE 100//存储空间初始分配量 7 #define STACKINCREMENT 10//存储空间分配增量 8 #define MAX_TREE_SIZE 21//树的结点数目最大值 9 //>>>>>>>>>>>>>>>>>>>>>>>>>>>自定义数据类型<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 10 typedef int Status;//函数返回值状态码类型 11 typedef char ElemType;//树中结点元素类型 12 //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>结构体定义<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 13 //孩子结构 14 typedef struct CTNode 15 { 16 int child;//孩子结点的下标 17 struct CTNode *next;//指向下一个结点的指针 18 }*ChildPtr; 19 //表头结构 20 typedef struct 21 { 22 ElemType data;//存放在树中的结点的数据 23 int parent;//存放双亲的下标 24 ChildPtr firstchild;//指向第一个孩子的指针 25 }CTBox; 26 //树结构 27 typedef struct 28 { 29 CTBox tree[MAX_TREE_SIZE];//结点数组 30 int n;//结点数目 31 }CTree; 32 //二叉树结点,左孩子,右孩子 33 typedef struct BTNode 34 { 35 ElemType data; 36 struct BTNode *lchild,*rchild; 37 }BTNode,*BTree; 38 typedef BTree SElemType; 39 //栈的结构体 40 typedef struct{ 41 SElemType *base;//在栈构造和销毁之后,base的值为NULL 42 SElemType *top;//栈顶指针 43 int stacksize;//当前已分配的存储空间 44 }Stack; 45 //--------------------------------1.采用孩子双亲表示法创建一棵一般的树------------------------------- 46 void InitCtree(CTree &T) 47 {//初始化树 48 int i; 49 printf("请输入树的结点个数:"); 50 scanf("\n%d",&T.n); 51 printf("依次输入各个结点:\n"); 52 for(i=0; i<T.n; i++) 53 { 54 fflush(stdin);//清理标准输入流,把多余的未被保存的数据丢掉 55 T.tree[i].data = getchar(); 56 T.tree[i].parent = 0; 57 T.tree[i].firstchild = NULL; 58 } 59 } 60 void AddChild(CTree &T) 61 {//添加孩子 62 int i,j,k; 63 printf("-----------------------添加孩子及其双亲结点------------------------------------------\n"); 64 for(k=0; k<T.n; k++) 65 { 66 fflush(stdin); //清理标准输入流,把多余的未被保存的数据丢掉 67 printf("请输入孩子结点及其双亲结点的序号:(用空格隔开)\n"); 68 scanf("%d %d",&i,&j); 69 fflush(stdin); 70 CTNode *p = (CTNode *)malloc(sizeof(CTNode)); 71 p->child = i; 72 p->next = NULL; 73 T.tree[i].parent = j;//找到双亲 74 if(!T.tree[j].firstchild) 75 T.tree[j].firstchild = p; 76 else 77 { 78 CTNode *temp = T.tree[j].firstchild; 79 while(temp->next ) 80 temp = temp->next ; 81 temp->next = p; 82 } 83 } 84 } 85 //---------------------------------------2.将树转换成对应的二叉树------------------------------------------ 86 Status ExchangeTree(BTree &BT,CTree &T) 87 { 88 BTNode *p,*q,*t,*pre;//pre指向p的双亲结点 89 CTNode *temp; 90 int m=T.n ; 91 if(!(p=(BTNode*)malloc(sizeof(BTNode)))) 92 exit (OVERFLOW); 93 int i=0; 94 p->data =T.tree [i].data; 95 p->lchild =NULL; 96 p->rchild =NULL; 97 BT=p; 98 for(i=0;i<m;i++) 99 { 100 if(p->data !=T.tree [i].data) 101 { 102 if(!p->lchild &&!p->rchild ) 103 p=pre;//p没有孩子时,p指向双亲结点 104 if(p->lchild ) 105 { 106 if(T.tree [i].data==p->lchild->data ) 107 pre=p; 108 p=p->lchild ; 109 } 110 if(p->rchild ) 111 if(T.tree [i].data==p->rchild ->data) 112 pre=p; 113 p=p->rchild ; 114 }//寻找要转化的根结点 ,让p指向此时要转换的根节点 115 if(T.tree [i].firstchild) 116 { 117 int k=T.tree [i].firstchild->child; 118 q=(BTNode*)malloc(sizeof(BTNode));//为第一个孩子即左孩子分配空间 119 q->data =T.tree [k].data; 120 q->lchild =NULL; 121 q->rchild =NULL; 122 p->lchild =q;//p指向其左孩子 123 temp=T.tree [i].firstchild; 124 while(temp->next )//判断是否有兄弟结点 125 { 126 t=(BTNode*)malloc(sizeof(BTNode)); 127 int s=temp->next ->child; 128 t->data =T.tree [s].data; 129 t->lchild =NULL; 130 t->rchild =NULL; 131 q->rchild =t;//右孩子为其兄弟结点 132 q=q->rchild ; 133 temp=temp->next ; //后移判断是否还有兄弟结点 134 } 135 } 136 } 137 } 138 //-------------------------------------3.遍历二叉树的递归算法----------------------------------------------- 139 /*先序遍历的递归算法*/ 140 void PreOrderTraverse(BTree BT) 141 { 142 if(BT){ 143 printf("%c ",BT->data ); 144 PreOrderTraverse(BT->lchild ); 145 PreOrderTraverse(BT->rchild ); 146 } 147 } 148 /*中序遍历的递归算法*/ 149 void InOrderTraverse(BTree BT) 150 { 151 if(BT){ 152 InOrderTraverse(BT->lchild ); 153 printf("%c ",BT->data ); 154 InOrderTraverse(BT->rchild ); 155 } 156 } 157 /*后序遍历的递归算法*/ 158 void PostOrderTraverse(BTree BT) 159 { 160 if(BT){ 161 PostOrderTraverse(BT->lchild ); 162 PostOrderTraverse(BT->rchild ); 163 printf("%c ",BT->data ); 164 } 165 } 166 //----------------------------------------4.遍历的非递归算法-------------------------------------------------- 167 //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>栈的相关算法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 168 Status InitStack(Stack &S){ 169 //构造一个空栈 170 S.base =(SElemType*)malloc(STACK_INIT_SIZE*sizeof(SElemType)); 171 if(!S.base ) exit(OVERFLOW); 172 S.top =S.base ; 173 S.stacksize = STACK_INIT_SIZE; 174 return OK; 175 } 176 Status Push(Stack &S,SElemType e) 177 { 178 //入栈 179 if(S.top -S.base >=S.stacksize ){ 180 //栈满 181 S.base =(SElemType*)realloc(S.base ,(S.stacksize+STACKINCREMENT)*sizeof(SElemType)); 182 if(!S.base ) exit (OVERFLOW); 183 S.top =S.base +S.stacksize ; 184 S.stacksize += STACKINCREMENT; 185 } 186 *S.top++=e; 187 return OK; 188 } 189 Status Pop(Stack &S,SElemType &e){ 190 //出栈 191 if(S.top ==S.base ) return ERROR; 192 e=*--S.top ; 193 return OK; 194 } 195 Status GetTop(Stack S,SElemType &e) 196 {//若栈不空,则用e返回S的栈顶元素,并返回OK,否则返回ERROR 197 if(S.top ==S.base ) return ERROR; 198 e=*(S.top -1); 199 return OK; 200 } 201 Status StackEmpty(Stack S){ 202 return (S.base ==S.top )?true:false; 203 } 204 //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>栈的相关算法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 205 //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>遍历的非递归算法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 206 /*先序遍历的非递归算法*/ 207 void PreOrder(BTree BT) 208 { 209 Stack S; 210 BTree p=BT; 211 InitStack(S); 212 while(p||!StackEmpty(S)) 213 { 214 if(p) 215 { 216 Push(S,p); 217 printf("%c ",p->data ); 218 p=p->lchild ; 219 } 220 else 221 { 222 Pop(S,p ); 223 p=p->rchild ; 224 } 225 } 226 } 227 /*中序遍历的非递归算法*/ 228 void InOrder(BTree BT) 229 { 230 Stack S; 231 BTree p=BT; 232 InitStack(S); 233 while(p||!StackEmpty(S)) 234 { 235 if(p) 236 { 237 Push(S,p ); 238 p=p->lchild ; 239 } 240 else 241 { 242 Pop(S,p ); 243 printf("%c ",p->data ); 244 p=p->rchild ; 245 } 246 } 247 } 248 /*后序遍历的非递归算法*/ 249 /*步骤: 250 对于树中任意一个访问的节点p可以分情况讨论 251 1. p如果是叶子节点,直接输出 252 2. p如果有孩子,且孩子没有被访问过,则按照右孩子,左孩子的顺序依次入栈 253 3. p如果有孩子,而且孩子都已经访问过,则访问p节点*/ 254 void PostOrder(BTree BT) 255 { 256 Stack S; 257 SElemType e; 258 BTree p=BT; 259 BTree mark; 260 mark=p; 261 InitStack(S); 262 Push(S,p); 263 while(!StackEmpty(S)) 264 { 265 GetTop(S,p);//p等于栈顶指针 266 if( (p->lchild == NULL && p->rchild == NULL) || (p->rchild == NULL && mark == p->lchild ) || (mark == p->rchild ) ) 267 //入栈时按照右孩子,左孩子顺序入栈,则右孩子被标记,左孩子没有或被标记 268 { 269 printf("%c ",p->data ); 270 mark=p; 271 Pop(S,p); 272 } 273 else 274 { 275 if(p->rchild ) 276 Push(S,p->rchild ); 277 if(p->lchild ) 278 Push(S,p->lchild ); 279 } 280 } 281 } 282 //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>遍历的非递归算法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 283 //----------------------------------------------主函数-------------------------------------------------------------- 284 main() 285 { 286 BTree BT; 287 CTree T; 288 SElemType e; 289 printf("--------------------------孩子双亲表示法表示一棵一般的树---------------------------\n"); 290 InitCtree(T); 291 AddChild(T); 292 printf("---------------------------------树的创建已完成-------------------------------------\n"); 293 ExchangeTree(BT,T); 294 printf("-------------------------------二叉树的转换已完成-----------------------------------\n"); 295 printf("------------------------------二叉树的递归遍历算法----------------------------------\n"); 296 printf("前序遍历:"); 297 PreOrderTraverse(BT); 298 printf("\n"); 299 printf("中序遍历:"); 300 InOrderTraverse(BT); 301 printf("\n"); 302 printf("后序遍历:"); 303 PostOrderTraverse(BT); 304 printf("\n"); 305 printf("------------------------------二叉树的非递归遍历算法---------------------------------\n"); 306 printf("前序遍历:"); 307 PreOrder(BT); 308 printf("\n"); 309 printf("中序遍历:"); 310 InOrder(BT); 311 printf("\n"); 312 printf("后序遍历:"); 313 PostOrder(BT); 314 printf("\n"); 315 return 0; 316 }
运行结果: