广义表创建二叉树
关于用广义表的形式表示二叉树的形式如下
①广义表中的一个字母代表一个结点的数据信息。
②每个根结点作为由子树构成的表的名字放在义表的前面。
③每个结点的左子树与右子树之间用逗号分开。若结点只有右子树面无左子树,则该逗号不能省略。
④在整个广义表的末尾加一个特殊符号(如“@”)作为结束标志。
下面先用自然语言描述算法如下。
依次从广义表中取得-个元素,并对取得的元素做如下相应的处理。
①若当前取得的元素为字母,则按如下规则建立一个新的(链)结点。
a)若该结点为二叉树的根结点,则将该结点的地址送T。
b)若该结点不是二叉树的根结点,则将该结点作为左孩子(若标志flag为1)或者右子若标志flag为2)链接到其双亲结点上(此时双亲结点的地址在栈顶位置)。
②若当前取得的元素为左括号“(”,则表明一个子表开始,将标志flag置为1,同时将面那个结点的地址进栈。
③若当前取得的元素为右括号“)”,则表明一个子表结束,做退栈操作。
④若当前取得的元素为逗号,则表明以左孩子为根的子树处理完毕,接着应该处理孩子为根的子树,将标志flag置为2。
如此处理广义表中的每一个元素,直到取得广义表的结束符号“@”为止。
二叉树的中序遍历(非递归)
算法的核心思想是:
当P所指的结点不为空时.则将该结点所在链结点的地址进栈,然后再将”指向该结点的左孩子结点:当P所指的结点为空时则从堆栈中退出栈项元素(某个结宜的地址)送p.并访问该结点,然后再将p指向该结点的右孩子结点。重复上述过程,直到P为NULL.并且堆栈也为空,遍历结束。
二叉树的后序遍历(非递归)
下面再讨论后序遍历的非递归算法:
在对二又树进行后序遍历的过程中,当指针p指向某一个结点时,不能马上对它进行访问,而要先遍历它的左子树,因而要将此结点的地址进栈;当其左子树遍历完毕之后,再次搜索到该结点时(该结点的地址通过退栈得到),还不能对它进行访问,还需要遍历它的右子树,所以,再一次将此结点的地址进栈。只有当该结点的右子树被遍历后回到该结点,才访问该结点。为了标明某结点是否可以被访问,引人一个标志变量flag,
并有
1、flag=0表示该结点暂不访问
2、flag =1表示该结点可以访问
标志flag的值随同进栈结点的地址起进栈和出栈。因此,算法中设置了两个空间足够的堆栈,其中,STACK1[0… M- 1 ]存放进栈结点的地址,STACK2[0… M- 1]存放相应的标志flag的值,两个堆栈使用同一栈顶指针top,top的初值为一1。
二叉树的按层次遍历
下面测试的算法中使用了一个顺序存储结构队列QUEUE[0. . M- 1],(不妨假设队列的空间足够大).front与rear分别为队头指针和队尾指针。遍历进行之前先把二叉树根结点的存储地址进队.然后依次从队列中退出一个元素(结点的存储地址);每退出一个元素,先访问该元素所指的结点.然后依次把该结点的左孩子结点(若存在的话)与右孩子结点(若存在的话)的地址依次进队。如此重复下去,直到队列为空。此时,访问结点的次序就是按层次遍历该二叉树的次序。
有关中序遍历,后序遍历,层次遍历的非递归算法和二叉树的广义表创建一起测试
1 #include<stdio.h> 2 #include<stdlib.h> 3 #define M 100 4 5 typedef struct BTREE { 6 char data; 7 struct BTREE *lchild, *rchild; 8 }BT, *LBTREE; 9 10 LBTREE Creat() 11 { 12 LBTREE STACK[M], p = NULL, T = NULL; 13 int flag, top = -1; 14 char ch; 15 while (1) 16 { 17 scanf_s("%c", &ch); 18 switch (ch) 19 { 20 case '(': //左括号则下一个读取字符入栈 21 STACK[++top] = p; 22 flag = 1; 23 break; 24 case ')': //右括号则栈顶元素出栈 25 top--; 26 break; 27 case ',': 28 flag = 2; 29 break; 30 case '@': //返回T,表示创建完毕 31 return T; 32 default: //读到字母时 33 p = (LBTREE)malloc(sizeof(BT)); 34 p->data = ch; 35 p->lchild = NULL; 36 p->rchild = NULL; 37 if (T == NULL) 38 T = p; 39 else if (flag == 1) 40 STACK[top]->lchild = p; 41 else if (flag == 2) 42 STACK[top]->rchild = p; 43 } 44 } 45 } 46 47 void INORDER(LBTREE T) //中序遍历非递归 48 { 49 LBTREE STACK[M], p = T; 50 int top = -1; 51 if (T != NULL) 52 { 53 do { 54 while (p != NULL) //这里不可以是 (p=p->lchild)!=NULL 55 { 56 STACK[++top] = p; 57 p = p->lchild; 58 } 59 p = STACK[top--]; //出栈 60 printf("%c", STACK[top + 1]->data); 61 p = p->rchild; 62 } while (!(p == NULL && top == -1)); 63 } 64 } 65 66 void LAYERORDER(LBTREE T) //按层次遍历 67 { 68 LBTREE QUEUE[M], p; 69 int front, rear; 70 if (T != NULL) //队列 71 { 72 QUEUE[0] = T; 73 front = -1; 74 rear = 0; 75 while (front < rear) 76 { 77 p = QUEUE[++front]; 78 printf("% c", p->data); 79 if (p->lchild != NULL) 80 QUEUE[++rear] = p->lchild; 81 if (p->rchild != NULL) 82 QUEUE[++rear] = p->rchild; 83 84 } 85 } 86 } 87 88 void POSTORED(LBTREE T) //后序遍历的非递归算法 89 { 90 LBTREE STACK1[M]; //创建了两个栈,一个用来存放结点的地址 91 int STACK2[M], flag, top = -1; //另一个用来存放数字,1:可以读取,0:不可读取 92 LBTREE p = T; 93 if (T != NULL) 94 { 95 do { 96 while (p != NULL) 97 { 98 STACK1[++top] = p; 99 STACK2[top] = 0; 100 p = p->lchild; 101 } 102 p = STACK1[top]; 103 flag = STACK2[top--]; 104 if (flag == 0) 105 { 106 STACK1[++top] = p; 107 STACK2[top] = 1; 108 p = p->rchild; 109 } 110 else 111 { 112 printf("%c", p->data); 113 p = NULL; 114 } 115 } while (!(p == NULL && top == -1)); 116 } 117 } 118 119 120 void Distroyb(LBTREE T) //销毁二叉树(同样使用递归的方式) 121 { 122 if (T != NULL) 123 { 124 Distroyb(T->lchild); 125 Distroyb(T->rchild); 126 free(T); 127 } 128 } 129 130 131 void main(void) 132 { 133 LBTREE T = NULL; 134 puts("输入二叉树数据"); 135 T=Creat(T); 136 137 puts("按层次遍历输出:"); 138 LAYERORDER(T); 139 puts(""); 140 141 puts("非递归中序遍历:"); 142 INORDER(T); 143 puts(""); 144 145 puts("非递归后续遍历:"); 146 POSTORED(T); 147 148 Distroyb(T); //销毁二叉树 149 }
输入:
A(B(D,E(G)),C(F(,H)))@
以下是结果:
嗝~
codeloop