二叉树是重要的数据结构内容,我们今天再来讲一下二叉树相关知识点。
定义与结构
首先再次明确一下什么是二叉树:
二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树。
一颗正常的二叉树。
我们怎么在计算机中储存二叉树呢没也就是说它的结构是什么样的呢,这就要用到我们的链表了。
类似于指针,也需要用到结构体,数据域指针域一应俱全。
struct node{
char data;//类型也可为int等
node*left;
node*right;
};
二叉树的遍历方式
二叉树的遍历方法一共有四种:前序遍历,中序遍历,后序遍历,层序遍历。
我们分别来看一遍他们是如何实现的
先序遍历:也叫前序遍历,就是从左向右的结点开始(先左子叶后右子叶),每走一个节点就输出,到达空节点就返回。例如上面的二叉树,先经过A,第一遍就输出,之后到B,D,G都是一遍输出,之后G接着输出,继续,G的左节点为空,返回G,此时第二遍经过G,G的右节点为空,返回G,第三遍,之后回溯到D,向D的右节点遍历,重复上述操作。先序遍历的结果就是 ABDGHICEJF .
中序遍历:同样是先左后右,但是要遍历两次才输出结果,按照上面的结果就是 GDIHBAJECF .
后序遍历:遍历三次才输出,结果:GIHDJEFCA .
代码实现:
void beh(node*root){
if(root){
cout<<root->data;
mid(root->l);
mid(root->r);
}
}
void mid(node*root){
if(root){
mid(root->l);
cout<<root->data;
mid(root->r);
}
}
void las(node*root){
if(root){
las(root->l);
las(root->r);
cout<<root->data;
}
}
代码还是十分好理解的,只要节点不为空,就输出;例如先序遍历,先输出,后遍历。
单独说一下层序遍历,层序遍历顾名思义就是一层一层的输出,这里的代码实现有点复杂。
这里我们要用到一个指针数组(指针的数组),即装着指针的数组,例如我们有个指针数组
int *p[N],它的含义就是指针数组里面装着N个int类型的指针,也就是地址。
void level(struct node* root)
{
if (root == NULL)
return;
int head = 1, tail = 1;
q[tail++] = root;
while (head < tail)
{
cout << q[head]->data;
if (q[head]->l)
q[tail++] = q[head]->l;
if (q[head]->r)
q[tail++] = q[head]->r;
head++;
}
}
解释一遍代码:思路是用一个先行指针先记录树的节点,之后让后行指针输出该节点的值并判断左右节点是否为空,若不为空,先行指针就把先左节点存入指针数组,再把右节点地址存入指针数组,为了更新数组所以要 tail++ ,那么这种算法巧妙在什么地方呢?它是怎么做到层序遍历而不丢失节点?还是先行指针和后行指针的作用。
例如:tail先存入整个root的地址,由于tail++,故此时q[head]存的是root的首地址即A的地址,之后输出,A的左节点不为空,先行指针存入,右节点也不为空,存入。此时我们看状态q[1]是A的地址,q[2]是B的地址,q[3]是C的地址,此时先行指针tail的值为4,但指针数组为q[3],最后head++,更新值为head=2,输出q[2]的值B,之后判断q[2]->l是否为空,q[2]是谁来着?B!B的左节点不为空,存入,此时更新q[4]的地址为D,到这里,大家应该都明白了,之后不断更新就完了。