1. 程式人生 > >二叉樹系列(3)層序遍歷的非遞迴實現

二叉樹系列(3)層序遍歷的非遞迴實現

按照層次序實現二叉樹遍歷。


對於上圖中的二叉樹,層次遍歷的實現結果如下


層次遍歷的過程天然地符合佇列這個資料結構,因此可以用佇列方法來非遞迴地實現層次遍歷。目前還不太清楚如何遞迴地實現層次遍歷,網上看到的一些解法,聲稱採用了遞迴方法進行層次遍歷,但是它們是在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函式的執行結果