c语言实现二叉树的建立与前序、中序、后序、层序遍历
2017-09-01 19:09
866 查看
树的节点与函数的定义
typedef char ElemType; typedef struct BiTNode{ ElemType data; struct BiTNode * lchild , * rchild; }BiTNode, * BiTree; void CreateBiTree(BiTree T); BiTree CreateBiTree1(); void Visit(BiTree T); void PreOrder(BiTree T); void InOrder(BiTree T); void PostOrder(BiTree T); void LevelOrder(BiTree T);
树的建立
错误的树的建立函数void CreateBiTree(BiTree T){ char ch; scanf("%c", &ch); if(ch == '#') T = NULL; else{ T = (BiTree)malloc(sizeof(BiTNode)); T->data = ch; CreateBiTree(T->lchild); CreateBiTree(T->rchild); } }
正确的树的建立函数
BiTree CreateBiTree1(){ char ch; BiTree T; scanf("%c", &ch); if(ch == '#') T = NULL; else{ T = (BiTree)malloc(sizeof(BiTNode)); T->data = ch; T->lchild = CreateBiTree1(); T->rchild = CreateBiTree1(); } return T; }
注意比较两个函数的区别:
如果不自己运行调试一遍根本找不出来错误,只有自己动手运行一遍才会发现第一种和第二种方法看似不同,实则差别很大。
本人用第一个函数也调试了很久,把指针一个一个的printf出来,找到问题。
第一个函数建立不了完整的树,因为malloc函数的问题,本来存在的指针经过malloc之后,又重新分配了一个与原来不一样的空间,因此第一个函数进行构造的时候,会有很多指针为空。
使用第二个函数进行构造的好处是:每有一个节点,就会单独的分配一个存储空间。每个几点的左子树和右子树也能够很好的通过递归链接起来。
树的遍历
树的前序,中序,后序遍历直接使用递归就行void Visit(BiTree T){ printf("%c ", T->data); } void PreOrder(BiTree T){ if(T != NULL){ Visit(T); PreOrder(T->lchild); PreOrder(T->rchild); } } void InOrder(BiTree T){ if(T != NULL){ InOrder(T->lchild); Visit(T); InOrder(T->rchild); } } void PostOrder(BiTree T){ if(T != NULL){ PostOrder(T->lchild); PostOrder(T->rchild); Visit(T); } }
树的层序遍历
树的层序遍历需要用到队列,这里引入了队列构造的一些函数typedef BiTree ElemTypeList; typedef struct{ ElemTypeList data[MaxSize]; int front, rear; }SqQueue; void InitQueue(SqQueue * Q); int QueueEmpty(SqQueue Q); int EnQueue(SqQueue * Q, ElemTypeList e); int DeQueue(SqQueue * Q, ElemTypeList * e);
这里需要注意的是,队列的数组是一个指针数组,每一个元素是一个指针,指向的是树的节点BitNode,这样,在编写层序遍历的程序的时候,就非常地简洁。
队列函数的实现:
void InitQueue(SqQueue * Q){ Q->front = Q->rear = 0; } int QueueEmpty(SqQueue Q){ if(Q.front == Q.rear) return 1; return 0; } int EnQueue(SqQueue * Q, ElemTypeList e){ if((Q->rear + 1) % MaxSize == Q->front){ printf("queue is full!"); return 0;}//队列满,牺牲一个存储单元 Q->data[Q->rear] = e; Q->rear = (Q->rear+1) % MaxSize; return 1; } int DeQueue(SqQueue * Q, ElemTypeList * e){ if(QueueEmpty(* Q)) return 0; * e = Q->data[Q->front]; Q->front = (Q->front + 1) % MaxSize; return 1; }
将队列的代码写好之后,层序遍历的思想也是很精髓的。
先将二叉树的根节点入队,然后出队,访问该结点。(注意这个算法的这个该结点的重要性)。如果该结点有左子树,则将左子树入队。如果有右子树,则将右子树入队。如果队列不为空,就出队,再对该出队结点进行循环
void LevelOrder(BiTree T){ SqQueue Q; InitQueue(& Q); EnQueue(& Q, T); BiTree p; while(!QueueEmpty(Q)){ DeQueue(& Q, & p); Visit(p); if(p->lchild != NULL) EnQueue(& Q, p->lchild); if(p->rchild != NULL) EnQueue(& Q, p->rchild); } }
程序的测试
二叉树的性质:n个节点的二叉树有n+1个空指针域因此在输入的时候,有几个数字就会有n+1个‘#’
主函数如下:
#include <stdio.h> #include "tree.h" int main(int argc, const char * argv[]) { BiTree T; printf("please input the tree node:\n"); T = CreateBiTree1(); printf("the PreOrder node:\ ace2 n"); PreOrder(T); printf("\nthe InOrder node:\n"); InOrder(T); printf("\nthe PostOrder node:\n"); PostOrder(T); printf("\nthe LevelOrder node:\n"); LevelOrder(T); printf("\n"); return 0; }
测试的二叉树如图:
测试输入的时候,应该输入的是:
12#46###3#5##
前序遍历的理论结果:1 2 4 6 3 5
中序遍历的理论结果:2 6 4 1 3 5
后序遍历的理论结果:6 4 2 5 3 1
层序遍历的理论结果:1 2 3 4 5 6
其实遍历就按照递归算法的思想就行了。
运行程序得到的结果如下:
可以看到运行的结果是与理想的结果是一致的。
相关文章推荐
- 二叉树的建立以及先序、中序、后序遍历C语言实现
- C语言非递归实现二叉树的先序、中序、后序、层序遍历
- python实现二叉树的建立以及遍历(递归前序、中序、后序遍历,队栈前序、中序、后序、层次遍历)
- 二叉树的遍历:前序,中序,后序,层序--包括递归和非递归实现
- 数据结构--java实现二叉树的先序、中序、后序、层次遍历及根据先序中序建立二叉树
- 二叉树的遍历:前序,中序,后序,层序--包括递归和非递归实现
- Java实现二叉树的前序、中序、后序、层序遍历(非递归方法)
- c语言实现二叉树先序,中序,后序(递归),层次遍历,求叶子节点个数及树的深度,下一篇写非递归的遍历
- Java实现二叉树的前序、中序、后序、层序遍历(非递归方法)
- 二叉树---实现先序、中序、后序和层序遍历
- 二叉树的遍历:前序,中序,后序,层序--包括递归和非递归实现
- 二叉树前序、中序、后序非递归遍历实现(C语言)
- [C/C++] 先序建立二叉树| 先序、中序、后序遍历二叉树| 求二叉树深度、节点数、叶节点数 算法实现
- 二叉树的四种遍历方式 (前序,中序,后序,层序遍历 python实现)
- 二叉树的遍历(前序,中序,后序,层序)--递归和非递归算法实现
- 二叉树的遍历:前序,中序,后序,层序--包括递归和非递归实现
- 二叉树先序,中序,后序、层序遍历递归和非递归实现
- JAVA下实现二叉树的先序、中序、后序、层序遍历(递归和循环)
- 二叉树的遍历(前序、中序、后序、层序),递归和非递归实现
- 二叉树的遍历:前序,中序,后序,层序--包括递归和非递归实现