二叉樹系列(3)層序遍歷的非遞迴實現
阿新 • • 發佈:2019-02-05
按照層次序實現二叉樹遍歷。
對於上圖中的二叉樹,層次遍歷的實現結果如下
層次遍歷的過程天然地符合佇列這個資料結構,因此可以用佇列方法來非遞迴地實現層次遍歷。目前還不太清楚如何遞迴地實現層次遍歷,網上看到的一些解法,聲稱採用了遞迴方法進行層次遍歷,但是它們是在while迴圈中進行的遞迴,是一種偽遞迴。由此有可以猜測,可能這種遍歷表現出來的資料訪問方式確實不匹配遞迴的演算法。下面僅僅給出層次遍歷的非遞迴解法。
void level_order_2(link t, void (*visit)(link)) { if(!t) return; std::queue<struct node> que; que.push(*t); while(!que.empty()){ struct node node_p; node_p = que.front(); que.pop(); visit(&node_p); if(node_p.l!=NULL) que.push(*node_p.l); if(node_p.r!=NULL) que.push(*node_p.r); } return; }
下面是完整的檔案,主要實現了二叉樹的前序,中序,後序,層序的遍歷。有bintree.h,bintree.cpp,main.cpp
以下為bintree.h
#ifndef BINTREE_H #define BINTREE_H typedef struct node* link; struct node{ int item; link l,r; }; struct tag_node{ link node_link; bool is_first; }; link init(int VLR[],int LVR[],int n); void pre_order(link t, void (*visit)(link));//遞迴前續遍歷 void pre_order_2(link t, void (*visit)(link));//非遞迴前續遍歷 void in_order(link t, void (*visit)(link));//遞迴中續遍歷 void in_order_2(link t, void (*visit)(link));//非遞迴中續遍歷 void post_order(link t, void (*visit)(link));//遞迴後續遍歷 void post_order_2(link t, void (*visit)(link));//非遞迴後續遍歷第一種 void post_order_3(link t, void (*visit)(link)); //非遞迴後續遍歷第二種 void level_order(link t, int level, void (*visit)(link));//層序遍歷遞迴, void level_order_2(link t, void (*visit)(link));//層序遍歷非遞迴 int count(link t); int depth(link t); int count_leaf(link t); int count_non_leaf(link t); link mirror_tree(link parent_t,link copy_t, int is_left); void destroy(link t); #endif
以下為bintree.cpp
#include <stdlib.h> #include <stack> #include <queue> #include "bintree.h" static link make_node(int item) { link p = new node; p->item = item; p->l = p->r = NULL; return p; } static void free_node(link p) { free(p); } link init(int VLR[], int LVR[], int n) { link t; int k; if(n <= 0) return NULL; for (k =0; VLR[0] != LVR[k];k++); //注意這裡分號的位置 t = make_node(VLR[0]); t->l = init(VLR+1, LVR,k); t->r = init(VLR+1+k, LVR+1+k,n-k-1); return t; } //前序遞迴 void pre_order(link t, void (*visit)(link)) { if(!t) return; visit(t); pre_order(t->l, visit); pre_order(t->r, visit); } //前序非遞迴 void pre_order_2(link t, void (*visit)(link)) { if(t==NULL) return; std::stack<link> s; link p = t; s.push(p); while(!s.empty()) { p = s.top(); s.pop(); visit(p); if(p->r != NULL) s.push(p->r); if(p->l != NULL) s.push(p->l); } } //中序遞迴 void in_order(link t, void (*visit)(link)) { if(!t) return; in_order(t->l, visit); visit(t); in_order(t->r, visit); } //中序非遞迴 void in_order_2(link t, void (*visit)(link)) { std::stack<link> s; link p=t; while( p!=NULL || !s.empty())// p!=NULL這個條件是為了相容第1次迴圈的條件設定。 { while(p!=NULL) { s.push(p); p=p->l; } //找到當前節點的最深最深最深的左兒子 if(!s.empty()) { p=s.top(); visit(p); s.pop(); p=p->r; } } } //後序遞迴 void post_order(link t, void (*visit)(link)) { if(!t) return; post_order(t->l, visit); post_order(t->r, visit); visit(t); } //後序非遞迴第一種 void post_order_2(link t, void (*visit)(link)) { std::stack<link> s; link cur=NULL; //當前結點 link pre=NULL; //前一次訪問的結點 s.push(t); while(!s.empty()) { cur=s.top(); if( (cur->l==NULL&&cur->r==NULL) || ( (pre!=NULL) && (pre==cur->l || pre==cur->r ) ) ) { visit(cur); //如果當前結點沒有孩子結點或者孩子節點都已被訪問過 s.pop(); pre=cur; } else { if(cur->r!=NULL) s.push(cur->r); if(cur->l!=NULL) s.push(cur->l); } } return; } //後序非遞迴第二種 void post_order_3(link t, void (*visit)(link)) { std::stack<tag_node*> s; link p=t; tag_node *temp; while(p!=NULL||!s.empty()) { while(p!=NULL) { tag_node* t_node=(tag_node*)malloc(sizeof(tag_node)); t_node->node_link=p; t_node->is_first=true; s.push(t_node); p=p->l; } if(!s.empty()) { temp=s.top(); s.pop(); if(temp->is_first==true) //表示是第一次出現在棧頂 { temp->is_first=false; s.push(temp); p=temp->node_link->r; } else //第二次出現在棧頂 { visit(temp->node_link); free(temp); p=NULL; //避免下一次迴圈的時候重複找P的最深左子節點 } } } return; } //層序遞迴 void level_order(link t, int level, void (*visit)(link)) { return; } //層序非遞迴 void level_order_2(link t, void (*visit)(link)) { if(!t) return; std::queue<struct node> que; que.push(*t); while(!que.empty()){ struct node node_p; node_p = que.front(); que.pop(); visit(&node_p); if(node_p.l!=NULL) que.push(*node_p.l); if(node_p.r!=NULL) que.push(*node_p.r); } return; } int count(link t) { if(!t) return 0; return 1 + count(t->l) + count(t->r); } int depth(link t) { int dl,dr; if(!t) return 0; dl=depth(t->l); dr=depth(t->r); return 1+ (dr>dl?dr:dl); } int count_leaf(link t) { if(!t) return 0; if( (t->l==NULL) && (t->r==NULL) ) return 1; return count_leaf(t->r)+count_leaf(t->l); } int count_non_leaf(link t) { if(!t) return 0; if( (t->l==NULL) && (t->r==NULL) ) return 0; return 1+count_non_leaf(t->l)+count_non_leaf(t->r); } link mirror_tree(link parent_t,link copy_t, int is_left) { if(!copy_t) return NULL; link new_root=make_node(copy_t->item); if(parent_t!=NULL&&is_left==1)//first_time==1 parent_t->l=new_root; if(parent_t!=NULL&&is_left==0) parent_t->r=new_root; mirror_tree(new_root, copy_t->r, 1); mirror_tree(new_root, copy_t->l, 0); return new_root; } void destroy(link t) { post_order(t,free_node); //post_order的第一個引數是函式指標,所以post_order(t,vist),post_order(t,free_node)都引數合理 }
以下為main.cpp
// tree_traverse_1.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include "bintree.h"
void print_item(link p)
{
printf("%d ",p->item);
}
int main(int argc, char* argv[])
{
//test_data_1
//int pre_seq[] = {4,2,1,3,6,5,7};
//int in_seq[] = {1,2,3,4,5,6,7};
//test_data_2
int pre_seq[] = {4,2,1,8,9,3,6,5,7};
int in_seq[] = {8,1,9,2,3,4,5,6,7};
//test_data_3
//int pre_seq[] = {4,2,1,3,6,5,8,7,9};
//int in_seq[] = {1,2,3,4,8,5,6,7,9};
//link root = init(pre_seq,in_seq,7);
link root = init(pre_seq,in_seq,9);
printf("count=%d, depth=%d, leaf=%d, non_leaf=%d\n",count(root),depth(root),count_leaf(root),count_non_leaf(root));
putchar('\n');
putchar('\n');
pre_order(root, print_item);
putchar('\n');
pre_order_2(root, print_item);
putchar('\n');
in_order(root, print_item);
putchar('\n');
in_order_2(root, print_item);
putchar('\n');
post_order(root, print_item);
putchar('\n');
post_order_2(root, print_item);
putchar('\n');
post_order_3(root, print_item);
putchar('\n');
putchar('\n');
level_order_2(root, print_item);
putchar('\n');
putchar('\n');
link root2 = mirror_tree(NULL,root,-1);
in_order(root2, print_item);
putchar('\n');
putchar('\n');
destroy(root);
destroy(root2);
return 0;
}
以下為main函式的執行結果