二叉樹遍歷方式和實現,以及二叉樹查找、統計個數、比較、求深度
一、基本概念
每個結點最多有兩棵子樹,左子樹和右子樹,次序不可以顛倒。
性質:
1、非空二叉樹的第n層上至多有2^(n-1)個元素。
2、深度爲h的二叉樹至多有2^h-1個結點。
滿二叉樹:所有終端都在同一層次,且非終端結點的度數爲2。
在滿二叉樹中若其深度爲h,則其所包含的結點數必爲2^h-1。
完全二叉樹:除了最大的層次即成爲一顆滿二叉樹且層次最大那層所有的結點均向左靠齊,即集中在左面的位置上,不能有空位置。
對於完全二叉樹,設一個結點爲i則其父節點爲i/2,2i爲左子節點,2i+1爲右子節點。
二、存儲結構
順序存儲:
將數據結構存在一塊固定的數組中。
-
#define LENGTH 100
-
typedef char datatype;
-
typedef struct node{
-
datatype data;
-
int lchild,rchild;
-
int parent;
-
}Node;
-
-
Node tree[LENGTH];
-
int length;
-
int root;
雖然在遍歷速度上有一定的優勢,但因所佔空間比較大,是非主流二叉樹。二叉樹通常以鏈式存儲。
鏈式存儲:
-
typedef char datatype;
-
-
typedef struct BinNode{
-
datatype data;
-
struct BinNode* lchild;
-
struct BinNode* rchild;
-
}BinNode;
-
-
typedef BinNode* bintree;
三、二叉樹的遍歷
遍歷即將樹的所有結點訪問且僅訪問一次。按照根節點位置的不同分爲前序遍歷(先序遍歷),中序遍歷,後序遍歷。另外還有一個遍歷方式—層次遍歷。
前序遍歷:根節點->左子樹->右子樹
中序遍歷:左子樹->根節點->右子樹
後序遍歷:左子樹->右子樹->根節點
例如:求下面樹的四種遍歷
前序遍歷:abdefgc
中序遍歷:debgfac
後序遍歷:edgfbca
層次遍歷:abcdfeg
四、遍歷的實現
遞歸實現(以前序遍歷爲例,其他的只是輸出的位置稍有不同)
-
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;
-
}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;
-
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){
-
while(t){
-
push(&s,t);
-
s.tag[s.top] = 0;
-
t= t->lchild;
-
}
-
if(s.tag[s.top] == 0){
-
t= s.data[s.top];
-
s.tag[s.top]=1;
-
t=t->rchild;
-
}else {
-
while (s.tag[s.top] == 1){
-
t = pop(&s);
-
printf("%c ",t->data);
-
}
-
t = NULL;
-
}
-
}
-
}
-
}
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;
-
}
轉載地址:點擊打開鏈接