递归实现(以前序遍历为例,其他的只是输出的位置稍有不同)
- void preorder(bintree t){
- if(t){
- printf("%c ",t->data);
- preorder(t->lchild);
- preorder(t->rchild);
- }
- }
非递归的实现
因为当遍历过根节点之后还要回来,所以必须将其存起来。考虑到后进先出的特点,选用栈存储。数量确定,以顺序栈存储。
- #define SIZE 100
- typedef struct seqstack{
- bintree data[SIZE];
- int tag[SIZE]; //为后续遍历准备的
- int top; //top为数组的下标
- }seqstack;
-
- void push(seqstack *s,bintree t){
-
- if(s->top == SIZE){
- printf("the stack is full\n");
- }else{
- s->top++;
- s->data[s->top]=t;
- }
- }
-
- bintree pop(seqstack *s){
- if(s->top == -1){
- return NULL;
- }else{
- s->top--;
- return s->data[s->top+1];
- }
- }
1、前序遍历
- void preorder_dev(bintree t){
- seqstack s;
- s.top = -1; //因为top在这里表示了数组中的位置,所以空为-1
- if(!t){
- printf("the tree is empty\n");
- }else{
- while(t || s.stop != -1){
- while(t){ //只要结点不为空就应该入栈保存,与其左右结点无关
- printf("%c ",t->data);
- push(&s,t);
- t= t->lchild;
- }
- t=pop(&s);
- t=t->rchild;
- }
- }
- }
2、中序遍历
- void midorder(bintree t){
- seqstack s;
- s.top = -1;
- if(!t){
- printf("the tree is empty!\n");
- }else{
- while(t ||s.top != -1){
- while(t){
- push(&s,t);
- t= t->lchild;
- }
- t=pop(&s);
- printf("%c ",t->data);
- t=t->rchild;
- }
- }
- }
3、后序遍历
因为后序遍历最后还要要访问根结点一次,所以要访问根结点两次。采取夹标志位的方法解决这个问题。
这段代码非常纠结,对自己有信心的朋友可以尝试独立写一下。反正我是写了很长时间。逻辑不难,我画了一张逻辑图:

代码:
- void postorder_dev(bintree t){
- seqstack s;
- s.top = -1;
- if(!t){
- printf("the tree is empty!\n");
- }else{
- while(t || s.top != -1){ //栈空了的同时t也为空。
- while(t){
- push(&s,t);
- s.tag[s.top] = 0; //设置访问标记,0为第一次访问,1为第二次访问
- t= t->lchild;
- }
- if(s.tag[s.top] == 0){ //第一次访问时,转向同层右结点
- t= s.data[s.top]; //左走到底时t是为空的,必须有这步!
- s.tag[s.top]=1;
- t=t->rchild;
- }else {
- while (s.tag[s.top] == 1){ //找到栈中下一个第一次访问的结点,退出循环时并没有pop所以为其左子结点
- t = pop(&s);
- printf("%c ",t->data);
- }
- t = NULL; //必须将t置空。跳过向左走,直接向右走
- }
- }
- }
- }
4、层次遍历:即每一层从左向右输出
元素需要储存有先进先出的特性,所以选用队列存储。
队列的定义:
- #define MAX 1000
-
- typedef struct seqqueue{
- bintree data[MAX];
- int front;
- int rear;
- }seqqueue;
-
-
- void enter(seqqueue *q,bintree t){
- if(q->rear == MAX){
- printf("the queue is full!\n");
- }else{
- q->data[q->rear] = t;
- q->rear++;
- }
- }
-
- bintree del(seqqueue *q){
- if(q->front == q->rear){
- return NULL;
- }else{
- q->front++;
- return q->data[q->front-1];
- }
- }
遍历实现
- void level_tree(bintree t){
- seqqueue q;
- bintree temp;
- q.front = q.rear = 0;
- if(!t){
- printf("the tree is empty\n");
- return ;
- }
- enter(&q,t);
- while(q.front != q.rear){
- t=del(&q);
- printf("%c ",t->data);
- if(t->lchild){
- enter(&q,t->lchild);
- }
- if(t->rchild){
- enter(&q,t->rchild);
- }
- }
- }
5、利用前序遍历的结果生成二叉树
- //递归调用,不存点,想的时候只关注于一个点,因为还会回来的,不要跟踪程序运行,否则容易多加循环
-
- void createtree(bintree *t){
- datatype c;
- if((c=getchar()) == '#')
- *t = NULL;
- else{
- *t = (bintree)malloc(sizeof(BinNode));
- (*t)->data = c;
- createtree(&(*t)->lchild);
- createtree(&(*t)->rchild);
- }
- }
6、二叉树的查找
- bintree search_tree(bintree t,datatype x){
- if(!t){
- return NULL;
- }
- if(t->data == x){
- return t;
- }else{
- if(!search_tree(t->lchild,x)){
- return search_tree(t->rchild,x);
- }
- return t;
- }
- }
7、统计结点个数
- int count_tree(bintree t){
- if(t){
- return (count_tree(t->lchild)+count_tree(t->rchild)+1);
- }
- return 0;
- }
8、比较两个树是否相同
- int is_equal(bintree t1,bintree t2){
- if(!t1 && !t2){ //都为空就相等
- return 1;
- }
- if(t1 && t2 && t1->data == t2->data){ //有一个为空或数据不同就不判断了
- if(is_equal(t1->lchild,t2->lchild))
- if(is_equal(t1->rchild,t2->rchild)){
- return 1;
- }
- }
- return 0;
- }
9、求二叉树的深度
- int hight_tree(bintree t){
- int h,left,right;
- if(!t){
- return 0;
- }
- left = hight_tree(t->lchild);
- right = hight_tree(t->rchild);
- h = (left>right?left:right)+1;
- return h;
- }
|