二叉树的建立可以用二叉树性质第六条建立,也可以按照完全二叉树的定义来建立。
遍历主要分为广度优先遍历和深度优先遍历,深度优先遍历又分为递归前序遍历、递归后序遍历、递归中序遍历,和非递归前序遍历、非递归后序遍历、非递归中序遍历。
广度优先遍历主要用队列的思想实现,而深度优先遍历如上述所说用递归和非递归思想实现。
现在说说建立和遍历的实现思想。
二叉树建立的基本思想是:依次输入节点信息,若输入的节点不是虚节点,则建立一个新节点。若新节点是第一个节点,则令其为根节点;否则将新节点作为孩子节点链接到它的双亲节点上。如此反复进行,直到输入结束标志#为止。为使新节点能够与双亲节点正确相连,以及考虑到这种方法中先建立的节点,其孩子节点也一定要先建立的特点,可以设置一个指针型的数组构成的队列来保存已输入的节点的地址,并使队尾(rear)指向当前输入的节点;对头(front)指向这个节点的双亲节点。由于根节点的地址放在队列的第一个单元里,因此当rear为偶数是,rear所指向的节点应作为左孩子与其双亲节点链接;否则rear所指向的节点应作为右孩子预期双亲节点链接。若双亲节点或孩子节点为虚节点,则无需链接。当双亲节点与两个孩子节点链接完毕,才进行出队操作,使对头指针指向下一个待链接的双亲节点。
递归遍历的思想:符合人的思维逻辑,无需多说,只不过要搞清楚算法执行的内部步骤也是不容易的,有兴趣的诸君可以自行尝试。
非递归遍历的思想:(中序遍历为例)使用一个堆栈stack[N]来保存每次调用的参数,这个堆栈的栈顶指针为top,另设一个活动指针p来指向当前访问的节点。当p所指向的节点非空,将该节点的地址进栈,然后将p指向该节点的左孩子节点;当p所指向的节点为空时,从栈顶退出栈顶元素,并访问该节点,然后将p指向该节点的右孩子节点;如此反复,直到p为空并且栈顶指针头top=-1为止。
下面给出实现的代码和运行结果,还是秉持一贯的作风建议一句:将运行结果和代码对照起来学习,效果更明显。其中递归遍历全部实现了,而非递归遍历只实现了中序遍历,其他两种遍历留给诸君进行练习,学了之后总要检验下学会了没有吧?哈哈
/*********************\
Author:Harrykate
Date:2014/9/14
Time:17:08
Name:binarytree
\*********************/
#include "iostream"
#include "malloc.h"
using namespace std;
#define Maxsize 1024
typedef char datatype;
typedef struct node
{
datatype data;
struct node*lchild,*rchild;
}bitree;
bitree*CreatTree()//非递归的方式建立完全二叉树
{
cout<<"连续输入字符建立完全二叉树,并以‘#’结束"<<endl;
char ch;
bitree*Q[Maxsize];
int front,rear;
bitree*root,*s;
root=NULL;
front=1,rear=0;
while ((ch=getchar())!='#')
{
s=NULL;
s=(bitree*)malloc(sizeof(bitree));
s->data=ch;
s->lchild=NULL;
s->rchild=NULL;
rear++;
Q[rear]=s;
if (rear==1)
root=s;
else
{
if(s&&Q[front])
{
if(rear%2==0)
Q[front]->lchild=s;
else
Q[front]->rchild=s;
}
if(rear%2==1)
front++;
}
}
return root;
}
bitree *CreatTree2(int i,int n)//定义的方式建立完全二叉树
//不够通用,仅提供一种参考
{
bitree *root;
root=(bitree*)malloc(sizeof(bitree));
root->data=i;
if(2*i<=n) //若2*i<=n,那么tree的左孩子为tree[2*i];
root->lchild=CreatTree2(2*i,n);
else
root->lchild=NULL;
if(2*i+1<=n)//若2*i+1<=n,那么tree的右孩子为tree[2*i+1];
root ->rchild=CreatTree2(2*i+1,n);
else
root->rchild=NULL;
return root;
}
void PreOrder(bitree*p)//前序递归遍历
{
if (p!=NULL)
{
cout<<"->"<<p->data;
PreOrder(p->lchild);
PreOrder(p->rchild);
}
}
void InOrder(bitree*p)//中序递归遍历
{
if (p!=NULL)
{
InOrder(p->lchild);
cout<<"->"<<p->data;
InOrder(p->rchild);
}
}
void NinOrder(bitree*p)//非递归的中序遍历,其他两种非递归遍历诸君自己实现
{
bitree*stack[Maxsize];
bitree*s=p;
int top=-1;
while (top!=-1||s!=NULL)
{
while (s!=NULL)
{
if (top==Maxsize-1)
{
cout<<"OVERFLOW";
return;
}
else
{
top++;
stack[top]=s;
s=s->lchild;
}
}
s=stack[top];
top--;
cout<<s->data;
s=s->rchild;
}
}
void PostOrder(bitree*p)//后序递归遍历
{
if (p!=NULL)
{
PostOrder(p->lchild);
PostOrder(p->rchild);
cout<<"->"<<p->data;
}
}
void Layer(bitree*p)//用队列实现广度优先遍历
{
bitree*Q[Maxsize];
bitree*s;
int rear=1,front=0;
Q[rear]=p;
while (front<rear)
{
front++;
s=Q[front];
cout<<"->"<<s->data;
if (s->lchild!=NULL)
{
rear++;
Q[rear]=s->lchild;
}
if (s->rchild!=NULL)
{
rear++;
Q[rear]=s->rchild;
}
}
}
int CountLeaf(bitree*p)//计算叶子节点数目
{
if(!p)
return 0;
else if(!p->lchild&&!p->rchild)
return 1;
else
return CountLeaf(p->lchild)+CountLeaf(p->rchild);
}
int Height(bitree*p)//计算数的高度
{
int lc,rc;
if(p==NULL)
return 0;
lc=Height(p->lchild)+1;
rc=Height(p->rchild)+1;
return lc>rc?lc:rc;
}
int main()
{
bitree*p;
int leaf,height;
p=CreatTree();
cout<<"深度优先遍历如下所示"<<endl<<endl;;
cout<<" 前序遍历为";
PreOrder(p);
cout<<endl<<endl;
cout<<" 中序遍历为";
InOrder(p);
cout<<endl<<endl;
cout<<" 后序遍历为";
PostOrder(p);
cout<<endl<<endl;
cout<<"广度优先遍历为";
Layer(p);
cout<<endl<<endl;
leaf=CountLeaf(p);
cout<<"叶子数目为:"<<leaf<<endl<<endl;
height=Height(p);
cout<<"数的高度为:"<<height<<endl<<endl;
return 0;
}
运行结果如下:
终于写完了,代码有点多,工作量比较大。不过诸君能通过这篇博文学会二叉树的基本操作,那也是甚感欣慰的。
鼓掌!!