二叉樹是數據結構中一種非常重要的結構,熟練的掌握二叉樹的創建,遍歷是打好編程基礎的關鍵。對於遍歷,不能僅僅只掌握遞歸遍歷,還應掌握效率更高地非遞歸遍歷。對於非遞歸的先序、中序、後序遍歷要用到棧(在之前的博文中已經提到了具體的實現過程),而在層次遍歷中要使用到另一種數據結構——隊列,這個在之前博文中沒有提到,因此在本篇博文中將會給出簡單實現。
在本篇博文中給出的代碼實現了:二叉樹的創建、二叉樹的遞歸、非遞歸的先、中、後序以及層次遍歷七種遍歷算法。話不多說,下面給出代碼(僅供參考):
因爲要用到棧和隊列,因此在這代碼一併給出,方便大家運行。
“LinkStack.h”:
#ifndef _LINKSTACK_H
#define _LINKSTACK_H
#include<stdlib.h>
#include<stdio.h>
#include"BiTree.h"
//定義棧中數據的類型
typedef BiTree LStackElem;
//定義棧元素的結構
typedef struct SNode
{
LStackElem data;
struct SNode * next;
}SNode, *LinkNode;
//定義棧的結構
typedef struct
{
LinkNode node; //棧頂指針(相當於鏈表中的頭指針)
int size; //棧的大小
}LinkStack;
//初始化棧
void init_link_stack(LinkStack &S);
//進棧
void push(LinkStack &S, LStackElem e);
//出棧
void pop(LinkStack &S, LStackElem &e);
//判斷棧是否爲空
int is_stack_empty(LinkStack S);
//獲得棧頂元素
void get_top(LinkStack S, LStackElem &e);
#endif
"LinkQueue.h":
#ifndef _LINKQUEUE_H
#define _LINKQUEUE_H
#include"BiTree.h"
typedef BiTree QueueElem;
typedef struct QNode
{
QueueElem data;
struct QNode * next;
}QNode;
typedef struct
{
QNode * top; //隊列頭指針
QNode * bottom; //隊列尾指針
int size; //隊列大小
}LinkQueue;
//初始化隊列
void init_link_queue(LinkQueue &Q);
//入隊列
void in_link_queue(LinkQueue &Q, QueueElem e);
//出隊列
void out_link_queue(LinkQueue &Q, QueueElem &e);
//隊列是否爲空
int is_queue_empty(LinkQueue Q);
#endif
"BiTree.h":
#ifndef _BITREE_H
#define _BITREE_H
//定義二叉樹中存儲的數據類型
typedef int BiNodeElem;
//定義二叉樹的結構
typedef struct BiNode
{
BiNodeElem data;
struct BiNode * lchild;
struct BiNode * rchild;
}BiNode, *BiTree;
//初始化一棵僅含根節點的二叉樹,根節點的值爲e
void init_bitree(BiTree &T, BiNodeElem e);
//產生樹節點
BiNode * creat_bitree_node(BiNodeElem e, BiNode * lchild, BiNode * rchild);
//增加左子樹
void add_lchild(BiNode * &binode, BiNode * lchild);
//增加右子樹
void add_rchild(BiNode * &binode, BiNode * rchild);
//遞歸先序遍歷
void pro_order_recursion(BiTree T);
//遞歸中序遍歷
void infix_order_recursion(BiTree T);
//遞歸後序遍歷
void post_order_recursion(BiTree T);
//非遞歸先序遍歷
void pro_order_no_recursion(BiTree T);
//非遞歸中序遍歷
void infix_order_no_recursion(BiTree T);
//非遞歸後序遍歷
void post_order_no_recursion(BiTree T);
//層次遍歷
void hierarchy_order(BiTree T);
#endif
"LinkStack.c":
#include"LinkStack.h"
//初始化棧
void init_link_stack(LinkStack &S)
{
S.node = (SNode *)malloc(sizeof(SNode));
S.node->next = NULL;
S.size = 0;
}
//進棧
void push(LinkStack &S, LStackElem e)
{
LinkNode p = (LinkNode)malloc(sizeof(SNode));
p->data = e;
p->next = S.node->next;
S.node->next = p;
++S.size;
}
//出棧
void pop(LinkStack &S, LStackElem &e)
{
if(is_stack_empty(S))
{
printf("棧爲空,不能出棧。\n");
return;
}
e = S.node->next->data;
LinkNode p = S.node->next;
S.node->next = S.node->next->next;
free(p);
--S.size;
}
//判斷棧是否爲空
int is_stack_empty(LinkStack S)
{
if(S.size == 0)
return 1;
else
return 0;
}
//獲得棧頂元素
void get_top(LinkStack S, LStackElem &e)
{
e = S.node->next->data;
}
"LinkQueue.c":
#include"LinkQueue.h"
#include<stdio.h>
#include<stdlib.h>
//初始化隊列
void init_link_queue(LinkQueue &Q)
{
Q.top = Q.bottom = (QNode *)malloc(sizeof(QNode));
Q.top->next = NULL;
Q.size = 0;
}
//入隊列(尾插法)
void in_link_queue(LinkQueue &Q, QueueElem e)
{
QNode * p = (QNode *)malloc (sizeof(QNode));
p->data = e;
p->next = NULL;
Q.bottom->next = p;
Q.bottom = p;
++Q.size;
}
//出隊列
void out_link_queue(LinkQueue &Q, QueueElem &e)
{
if(Q.size > 0)
{
e = Q.top->next->data;
QNode * p = Q.top->next;
Q.top->next = Q.top->next->next;
if(Q.bottom == p)
Q.bottom = Q.top;
free(p);
--Q.size;
}
}
//隊列是否爲空
int is_queue_empty(LinkQueue Q)
{
if(Q.size == 0)
return 1;
else
return 0;
}
"BiTree.c":
#include"BiTree.h"
#include"LinkStack.h"
#include"LinkQueue.h"
#include<stdio.h>
#include<stdlib.h>
//初始化一棵僅含根節點的二叉樹,根節點的值爲e
void init_bitree(BiTree &T, BiNodeElem e)
{
T = (BiNode *) malloc(sizeof(BiNode));
T->data = e;
T->lchild = NULL;
T->rchild = NULL;
}
//產生樹節點
BiNode * creat_bitree_node(BiNodeElem e, BiNode * lchild, BiNode * rchild)
{
BiNode * pTree = (BiNode *)malloc(sizeof(BiNode));
pTree->data = e;
pTree->lchild = lchild;
pTree->rchild = rchild;
return pTree;
}
//增加左子樹
void add_lchild(BiNode * &binode, BiNode * lchild)
{
if(binode != NULL)
binode->lchild = lchild;
}
//增加右子樹
void add_rchild(BiNode * &binode, BiNode * rchild)
{
if(binode != NULL)
binode->rchild = rchild;
}
//遞歸先序遍歷
void pro_order_recursion(BiTree T)
{
if(T != NULL)
{
printf("%d ",T->data);
pro_order_recursion(T->lchild);
pro_order_recursion(T->rchild);
}
}
//遞歸中序遍歷
void infix_order_recursion(BiTree T)
{
if(T != NULL)
{
infix_order_recursion(T->lchild);
printf("%d ",T->data);
infix_order_recursion(T->rchild);
}
}
//遞歸後序遍歷
void post_order_recursion(BiTree T)
{
if(T != NULL)
{
post_order_recursion(T->lchild);
post_order_recursion(T->rchild);
printf("%d ",T->data);
}
}
//非遞歸先序遍歷
void pro_order_no_recursion(BiTree T)
{
LinkStack S;
init_link_stack(S);
//把根節點指針賦值給p
BiNode * p = T;
while( NULL != p || !is_stack_empty(S))
{
//打印當前節點,其左節點依次進棧
while(NULL != p )
{
printf("%d ",p->data);
push(S,p);
p = p->lchild;
}
if(!is_stack_empty(S))
{
pop(S,p);
p = p->rchild;
}
}
}
//非遞歸中序遍歷
void infix_order_no_recursion(BiTree T)
{
LinkStack S;
init_link_stack(S);
//把根節點指針賦值給p
BiNode * p = T;
while( NULL != p || !is_stack_empty(S))
{
//左節點依次進棧
while(NULL != p)
{
push(S,p);
p = p->lchild;
}
if(!is_stack_empty(S))
{
pop(S,p);
printf("%d ",p->data);
p = p->rchild;
}
}
}
//非遞歸後序遍歷
void post_order_no_recursion(BiTree T)
{
LinkStack S;
init_link_stack(S);
BiNode * p = T;
//存儲最近一次訪問的節點
BiNode * visited =NULL;
while(NULL != p || !is_stack_empty(S))
{
//直接寫p 更爲簡單,不需要寫NULL !=p
while(p)
{
push(S,p);
p = p->lchild;
}
if(!is_stack_empty(S))
{
pop(S,p);
//如果不存在右子樹,或右子樹被訪問
/*
解析一下:根據上面的while循環,棧頂元素必然不存在左子樹;如何存在右子樹,又根據後序遍歷的特點,
最近一次被訪問的節點,必然是該節點的右子樹
*/
if( !p->rchild || p->rchild == visited)
{
printf("%d ",p->data);
visited = p;
p = NULL;
}
else
{
push(S,p);
p = p->rchild;
}
}
}
}
//層次遍歷
void hierarchy_order(BiTree T)
{
LinkQueue Q;
init_link_queue(Q);
BiNode * p;
if(T)
{
in_link_queue(Q,T);
while(!is_queue_empty(Q))
{
out_link_queue(Q,p);
printf("%d ",p->data);
if(p->lchild)
in_link_queue(Q,p->lchild);
if(p->rchild)
in_link_queue(Q,p->rchild);
}
}
}
"main.c":
#include"LinkStack.h"
#include"LinkQueue.h"
#include"BiTree.h"
int main()
{
BiTree T;
init_bitree(T,10);
BiNode * lchild = creat_bitree_node(20,NULL,creat_bitree_node(40,NULL,NULL));
add_lchild(T, lchild);
BiNode * rchild1 = creat_bitree_node(50,creat_bitree_node(60,NULL,NULL),creat_bitree_node(70,NULL,NULL));
BiNode * rchild = creat_bitree_node(30, NULL, rchild1);
add_rchild(T,rchild);
printf("構造的樹的結果如下:\n");
printf(" 10\n");
printf(" / \\\n");
printf(" 20 30\n");
printf(" \\ \\ \n");
printf(" 40 50\n");
printf(" /\\\n");
printf(" 60 70\n\n");
printf("遞歸先序遍歷的結果:\n");
pro_order_recursion(T);
printf("\n");
printf("遞歸中序遍歷的結果:\n");
infix_order_recursion(T);
printf("\n");
printf("遞歸後序遍歷的結果:\n");
post_order_recursion(T);
printf("\n");
printf("\n===============================================\n\n");
printf("非遞歸先序遍歷的結果:\n");
pro_order_no_recursion(T);
printf("\n");
printf("非遞歸中序遍歷的結果:\n");
infix_order_no_recursion(T);
printf("\n");
printf("非遞歸後序遍歷的結果:\n");
post_order_no_recursion(T);
printf("\n");
printf("非遞歸層次遍歷的結果:\n");
hierarchy_order(T);
printf("\n");
return 0;
}
運行結果如下:
與大家分享,共同學習,相互提高,如有疑問或建議,請留言。