二叉树是一种重要的数据结构,本篇包括二叉树的创建、三种二叉树遍历方式(递归与非递归)、计算二叉树结点个数、计算二叉树高度等操作。
typedef char TElemType; typedef struct BiTNode { TElemType data; struct BiTNode *lchild; struct BiTNode *rchild; }BiTNode, *BiTree;
void CreateBiTree(BiTree &T) { TElemType ch; scanf("%c", &ch); if(ch == '\n') return; if(ch == ' ') T = NULL; else { T = (BiTree)malloc(sizeof(BiTNode)); if(!T) return; T->data = ch;//生产根节点 CreateBiTree(T->lchild);//构造左子树 CreateBiTree(T->rchild);//构造右子树 } }
void DestoryBiTree(BiTree &T) { if(T == NULL) return; DestoryBiTree(T->lchild); DestoryBiTree(T->rchild); free(T);T = NULL; }
void PreOrderTraverse(BiTree T, void (*Visit)(TElemType e)) { if(T == NULL) return; Visit(T->data); PreOrderTraverse(T->lchild, Visit); PreOrderTraverse(T->rchild, Visit); }
/* 非递归先序遍历 在遍历某一个二叉(子)树时,以一当前指针记录当前要处理的二叉(左子)树, 以一个栈保存当前树之后处理的右子树。首先访问当前树的根结点数据,接下来 应该依次遍历其左子树和右子树,然而程序的控制流只能处理其一,所以考虑将 右子树的根保存在栈里面,当前指针则指向需先处理的左子树,为下次循环做准 备;若当前指针指向的树为空,说明当前树为空树,不需要做任何处理,直接弹 出栈顶的子树,为下次循环做准 */ void PreOrderTraverse_1(BiTree T, void (*Visit)(TElemType e)) { //定义栈 const int MAXSIZE = 100; struct BiTNode *stack[MAXSIZE], *p; int top = -1; if(T == NULL) return; p = T; while(p || top != -1) { if(p) { Visit(p->data); stack[++top] = p->rchild; p = p->lchild; } else p = stack[top--]; } }
void InOrderTraverse(BiTree T) { if(T == NULL) return; InOrderTraverse(T->lchild); printf("%c", T->data); InOrderTraverse(T->rchild); }
/* 非递归中序遍历 若当前树不为空树,则访问其根结点之前应先访问其左子树,因而先将当前 根节点入栈,然后考虑其左子树,不断将非空的根节点入栈,直到左子树为一空树; 当左子树为空时,不需要做任何处理,弹出并访问栈顶结点,然后指向其右子树,为下次循环做准备 */ void InOrderTraverse_1(BiTree T) { //定义栈 const int MAXSIZE = 100; struct BiTNode *stack[MAXSIZE], *p; int top= -1;//初始化栈 if (T == NULL) return; p = T; while(p || top != -1) { if(p)//根指针进栈,遍历左子树 { stack[++top] = p; p = p->lchild; } else//根指针退栈,访问根节点,遍历右子树 { p = stack[top--]; printf("%c", p->data); p = p->rchild; } } }
void InOrderTraverse_2(BiTree T) { //定义栈 const int MAXSIZE = 100; struct BiTNode *stack[MAXSIZE], *p; int top= -1;//初始化栈 if (T == NULL) return; stack[++top] = T;//根指针进栈 while(top != -1)//栈不空 { while((p = stack[top]))//向左走到尽头 stack[++top] = p->lchild; --top;//空指针退栈 if(top != -1)//访问结点,向右一步 { p = stack[top--]; printf("%c",p->data); stack[++top] = p->rchild; } } }
void PostOrderTraverse(BiTree T) { if (T == NULL) return; PostOrderTraverse(T->lchild); PostOrderTraverse(T->rchild); printf("%c", T->data); }
/* 非递归后序遍历 由于在访问当前树的根结点时,应先访问其左、右子树, 因而先将根结点入栈,接着将右子树也入栈,然后考虑左子树,重复这一过程直到某一左子树为空; 如果当前考虑的子树为空,若栈顶不为空,说明第二栈顶对应的树的右子树未处理,则弹出栈顶, 下次循环处理,并将一空指针入栈以表示其另一子树已做处理; 若栈顶也为空树,说明第二栈顶对应的树的左右子树或者为空,或者均已做处理,直接访问第二栈顶 的结点,访问完结点后,若栈仍为非空,说明整棵树尚未遍历完,则弹出栈顶,并入栈一空指针表示 第二栈顶的子树之一已被处理 */ void PostOrderTraverse_1(BiTree T) { //定义栈 const int MAXSIZE = 100; struct BiTNode *stack[MAXSIZE], *p; int top= -1;//初始化栈 if (T == NULL) return; p = T; while(1) { if(p) { stack[++top] = p; stack[++top] = p->rchild; p = p->lchild; } else if(!p) { p = stack[top--]; if(!p) { p = stack[top--]; printf("%c", p->data); if(top == -1) break; p = stack[top--]; } stack[++top] = NULL; } } }
int BiTreeNodes(BiTree T) { if (T == NULL) return 0; else return 1 + BiTreeNodes(T->lchild) + BiTreeNodes(T->rchild); }
int BiTreeHeight(BiTree T) { if(T == NULL) return 0; else { int lh = BiTreeHeight(T->lchild); int rh = BiTreeHeight(T->rchild); return lh > rh ? lh + 1 : rh + 1; } }
void LevelOrderTraverse(BiTree T) { if (T == NULL) return; SqQueue<BiTNode*> q; BiTNode*p; q.EnQueue(T); while (!q.QueueEmpty()) { q.DeQueue(p); visit(p); if (p->lchild != NULL) q.EnQueue(p->lchild); if (p->rchild != NULL) q.EnQueue(p->rchild); } }层次遍历类似BFS。