一、基本概念
每个结点最多有两棵子树,左子树和右子树,次序不可以颠倒。
性质:
1、非空二叉树的第n层上至多有2^(n-1)个元素。
2、深度为h的二叉树至多有2^h-1个结点。
满二叉树:所有终端都在同一层次,且非终端结点的度数为2。
在满二叉树中若其深度为h,则其所包含的结点数必为2^h-1。
完全二叉树:除了最大的层次即成为一颗满二叉树且层次最大那层所有的结点均向左靠齐,即集中在左面的位置上,不能有空位置。
对于完全二叉树,设一个结点为i则其父节点为i/2,2i为左子节点,2i+1为右子节点。
二、存储结构
链式存储:
</pre><pre name="code" class="cpp">typedef char datatype; typedef struct BinNode{ <span style="white-space:pre"> </span>datatype data; <span style="white-space:pre"> </span>struct BinNode* lchild; <span style="white-space:pre"> </span>struct BinNode* rchild; }BinNode; typedef BinNode* bintree;
三、二叉树的遍历
遍历即将树的所有结点访问且仅访问一次。按照根节点位置的不同分为前序遍历,中序遍历,后序遍历。
递归实现(以前序遍历为例,其他的只是输出的位置稍有不同)前序遍历:根节点->左子树->右子树
中序遍历:左子树->根节点->右子树
后序遍历:左子树->右子树->根节点
非递归的实现void preorder(bintree t){ if(t){ cout<<t->data; preorder(t->lchild); preorder(t->rchild); } }
1、前序遍历
2、中序遍历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; } } }
3、后序遍历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; } } }
- 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、比较两个树是否相同9、求二叉树的深度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; }
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; }