源代码的调试
在DEVC++中初步运行会报一堆错,而且有好多代码都被打进了注释,修改之后如下
#include<stdio.h>
#include<stdlib.h>
#define M 100
#define Null 0
typedef struct node { /*二叉链表结点结构*/
int data; /*数据域*/
struct node *lchild,*rchild;/*左、右孩子域*/
} bitree;
bitree *que[M]; /*定义一个指针数组,说明队列中的元素类型为bitree指针类型*/
int front=0,rear=0; /*初始化循环队列*/
bitree *creat() { /*建立二叉树的递归算法*/
bitree *t;
int x;
scanf("%d",&x);
if(x==0) t=Null; /*以x=0表示输入结束*/
else {
t=(bitree *)malloc(sizeof(bitree));/*动态生成结点t,分别给结点t的数据域、左右孩子域赋值,给左右孩子域赋值时用到了递归的思想。*/
t->data=x;
t->lchild=creat();
t->rchild=creat();
}
return t;
}
void inorder(bitree *t) { /*中序遍历二叉树的递归算法*/
if(t!=Null) {
inorder(t->lchild);
printf("%4d",t->data);
inorder(t->rchild);
}
}
void enqueue(bitree *t) { /*把bitree类型的结点*t入队列*/
if(front!=(rear+1)%M) { /*判断队列是否已满*/
rear=(rear+1)%M;
que[rear]=t;
}
}
bitree *delqueue() {
if(front==rear) /*判断队列不为空*/
return Null;
front=(front+1)%M;
return (que[front]);
}
void levorder(bitree *t) {/*层次遍历二叉树的算法*/
bitree *p;
if(t!=Null) {
enqueue(t); /*根结点入队*/
while(front!=rear) { /*当当前队列不为空时*/
p=delqueue(); /*输出对头元素,并把其左右孩子入队。此过程一直递归,直到队列为空*/
printf("%4d",p->data);
if(p->lchild!=Null)
enqueue(p->lchild);
if(p->rchild!=Null)
enqueue(p->rchild);
}
}
}
main() { /*主函数*/
bitree *root;
printf("\n");
root=creat();
inorder(root);
printf("\n");
levorder(root);
}
(1) 写出二叉树前序遍历和后序遍历的递归算法,并在主函数中调用它,调试好程序并分析其运行结果。
前后序遍历在书上有写
#include<stdio.h>
#include<stdlib.h>
#define M 100
#define Null 0
typedef struct node { /*二叉链表结点结构*/
int data; /*数据域*/
struct node *lchild,*rchild;/*左、右孩子域*/
} bitree;
bitree *que[M]; /*定义一个指针数组,说明队列中的元素类型为bitree指针类型*/
int front=0,rear=0; /*初始化循环队列*/
bitree *creat() { /*建立二叉树的递归算法*/
bitree *t;
int x;
scanf("%d",&x);
if(x==0) t=Null; /*以x=0表示输入结束*/
else {
t=(bitree *)malloc(sizeof(bitree));/*动态生成结点t,分别给结点t的数据域、左右孩子域赋值,给左右孩子域赋值时用到了递归的思想。*/
t->data=x;
t->lchild=creat();
t->rchild=creat();
}
return t;
}
void preorder(bitree *t) {//前
if(t!=NULL) {
printf("% 4d",t->data);
preorder(t->lchild);
preorder(t->rchild);
}
}
void inorder(bitree *t) { /*中序遍历二叉树的递归算法*/
if(t!=Null) {
inorder(t->lchild);
printf("%4d",t->data);
inorder(t->rchild);
}
}
void postorder(bitree *t) {//后
if(t!=NULL) {
postorder(t->lchild);
postorder(t->rchild);
printf("%4d",t->data);
}
}
void enqueue(bitree *t) { /*把bitree类型的结点*t入队列*/
if(front!=(rear+1)%M) { /*判断队列是否已满*/
rear=(rear+1)%M;
que[rear]=t;
}
}
bitree *delqueue() {
if(front==rear) /*判断队列不为空*/
return Null;
front=(front+1)%M;
return (que[front]);
}
void levorder(bitree *t) {/*层次遍历二叉树的算法*/
bitree *p;
if(t!=Null) {
enqueue(t); /*根结点入队*/
while(front!=rear) { /*当当前队列不为空时*/
p=delqueue(); /*输出对头元素,并把其左右孩子入队。此过程一直递归,直到队列为空*/
printf("%4d",p->data);
if(p->lchild!=Null)
enqueue(p->lchild);
if(p->rchild!=Null)
enqueue(p->rchild);
}
}
}
main() { /*主函数*/
bitree *root;
printf("\n");
root=creat();
printf("前\n");
preorder(root);
printf("\n中\n");
inorder(root);
printf("\n后\n");
postorder(root);
printf("\n层次\n");
levorder(root);
}
(2) 在二叉树的层次遍历中,如果不采用循环队列,而是采用顺序队列,会出现什么问题?
会出现假溢现象
(3) 写出二叉树三种遍历的非递归算法,并在主函数中调用它,调试好程序并分析其运行结构。
这里后序的非递归算法比较难写,需要多想
先序遍历是根-左-右
先遍历左孩子,再将它输出出来。当左孩子遍历完后,取栈顶,找右孩子。此时循环还没有结束,再遍历它的左孩子,右孩子直至孩子全部遍历结束
中序遍历是左-根-右
先把所有左孩子入栈,左孩子入栈结束,取栈顶,输出栈顶元素,遍历右孩子,右孩子入栈
后序遍历是左-右-根
对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时仍不能将其出栈,因为它的右孩子还没有被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就保证了正确的访问顺序。
#include<stdio.h>
#include <stdlib.h>
#define M 100
typedef struct node {
int data;
int cishu;
struct node *lchild;
struct node *rchild; //树节点中cishu是为了计数用。在后序遍历中,子树的根节点在第一次遍历的时候不会输出,只有在第二次遍历的时候才输出。
} bitree;
typedef struct stack {
bitree *elements[M];
int top;
} seqstack; //定义一个储存树类型地址的栈,方便遍历的时候追踪到树的地址。
bitree *root;//定义一个树根
seqstack s;//定义栈
void setnull() { //初始化栈
s.top =0;
}
void push(bitree *temp) { //入栈操作
s.elements[s.top++] = temp;
}
bitree *pop() { //取栈顶并出栈顶
return s.elements[--s.top];
}
int empty() { //判断空栈
return s.top == 0;
}
bitree *creat() { /*建立二叉树的递归算法*/
bitree *t;
int x;
scanf("%d",&x);
if(x==0) t=NULL; /*以x=0表示输入结束*/
else {
t=(bitree*)malloc(sizeof(bitree));//动态生成结点t,分别给结点t的数据域、左右孩子域
t->data=x; //赋值,给左右孩子域赋值时用到了递归的思想。
t->lchild=creat();
t->rchild=creat();
}
return t;
}
void preorder(bitree *t) { //前序遍历的非递归算法
bitree *temp = t;//定义一个树节点,用它来遍历
while(temp != NULL || s.top != 0) {
while(temp != NULL) { //先遍历左孩子,并输出。
printf("%4d",temp->data);
push(temp);
temp = temp->lchild;
}
if(s.top != 0) { //当左孩子遍历完后,取栈顶,找右孩子。此时循环还没有结束,再遍历它的左孩子,直至孩子全部遍历结束。
temp = pop();
temp = temp->rchild;
}
}
printf("\n");
}
void inorder(bitree *t) { //中序遍历的非递归算法
bitree *temp = t;
while(temp != NULL||s.top != 0) {
while(temp != NULL) { //先把左孩子入栈,所有左孩子入栈结束
push(temp);
temp = temp->lchild;
}
if(s.top != 0) { //左孩子入栈结束,取栈顶,输出栈顶元素,遍历右孩子
temp = pop();
printf("%4d",temp->data);
temp = temp->rchild;
}
}
printf("\n");
}
void laorder(bitree *root) { //后序遍历的非递归算法
bitree *temp = root;
while(temp!=NULL||s.top!=0) {
while(temp!= NULL) {
temp->cishu=1; // 当前节点首次被访问
push(temp);
temp=temp->lchild;
}
if(s.top!=0) {
temp=pop( );
if(temp->cishu == 1) { // 第一次出现在栈顶
temp->cishu++;
push(temp);
temp=temp->rchild;
} else if(temp->cishu==2) { //第二次输出并制空,防止陷入死循环
printf("%4d",temp->data);
temp=NULL;
}
}
}
printf("\n");
}
int main() {
bitree *root;//创建根
setnull();//制空栈
root=creat();//创建二叉树:尝试输入:1 2 3 0 0 4 0 0 5 6 0 0 7 0 0
printf("前序遍历:\n");
preorder(root);
printf("中序遍历:\n");
inorder(root);
printf("后序遍历:\n");
laorder(root);
return 0;
}