目录
1.介绍
1.1.二叉树
什么是二叉树,想要知道二叉树,我们需先知道树的概念 。树(tree) 是n(n>=0)个结点的有限集。n=0时称为空树。在任何一棵非空树中:1. 有且只有一个特定的称为 根(root) 的结点;2. 当n>1时,其余结点可分为m(m>0)个 互不相交 的有限集,其中每一个集合又是一棵树,并且成为 根的子树(subtree),树是一种一对多的结构。
二叉树,就是度最多只有2的树,通俗的讲,就是每个结点最多只能有两个分支。
1.2.满二叉树
满二叉树就是满足以下性质的二叉树:
1.满二叉树中第 i 层的结点数为 2n-1 个。
2.深度为 k 的满二叉树必有 2k-1 个结点 ,叶子数为 2k-1。
3.满二叉树中不存在度为 1 的结点,每一个分支点中都两棵深度相同的子树,且叶子结点都在最底层。
2.二叉树的存储结构
二叉树的存储结构分为两种,顺序存储和链式存储。
2.1.二叉树的顺序存储
二叉树的存储结构利用数组的形式存储,并按照满二叉树的顺序排序,没有的地方存0即可。
输入方式按照层次自左向右依次输入即可,即是按照满二叉树的顺序。
#include<stdio.h>
#define Max 100
typedef int Sqbitree[Max];
2.2.二叉树的链式存储
二叉树的链式存储结构通过链表的形式实现,首先,作为二叉树,需要两个分支分别代表下一个结点,我们将两个结点分别命名为左、右孩子,以及本身的数据域
typedef struct _bisq
{
int date; //数据域
struct _bisq *lchild; //左孩子
struct _bisq *rchild; //右孩子
}BiNode;
3.二叉树的建立
二叉树的建立分为三种:前序建立,中序建立,以及后序建立。前序建立就是先输入根结点,再输入左子树,最后输入右子树,即根左右;中序建立就是左根右,后序建立就是左右根
这里抽出前序建立进行评说:
二叉树的前需建立通过递归的形式实现,对每一个分支进行建立,直到输入为空(自定义一个字符)
void BiTreeCreate(BiTree *p) //二叉树的前序建立
{
char ch; //数据域初始化
scanf("%c",&ch);
if ( ch == '#' ) //判断是否终止
p = NULL;
else
{
p = (BiTree*)malloc(sizeof(BiTree)); //给该结点赋予空间
if ( !p )
exit(0);
p->data = ch; //前序中序后序的区别就在于此行代码位置
BiTreeCreate(p->lchild); //若上行代码位于这就是中序,后序就在下一行
BiTreeCreate(p->rchild);
/*不要小看代码的位置,由于递归的原因,一个位置的变化引起的因果是很大的*/
}
}
4.二叉树的遍历
4.1.二叉树的递归遍历
二叉树的递归遍历分为前序遍历,中序遍历和后序遍历,代码比较简单,看一下基本都能理解:
void PreorderTraverse(BiTree *p) //遍历函数
{
if ( p == NULL ) //判断树是否为空
return ;
else
{
printf("%c",p->data); //遍历
PreorderTraverse(p->lchild); //左孩子遍历
/*先序中序后序的区别就是printf函数在哪一行的区别,在第一行就是先序,
在第二行就是中序,在第三行就是后序*/
PreorderTraverse(p->rchild); //右孩子遍历
}
}
4.2.二叉树的非递归遍历
非递归遍历如何实现?主要是运用栈先进后出的思想进行遍历,既然要用到栈,我们就需要一些有关栈的函数
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define Max 9999
typedef struct _Sq
{
char data;
int Cishu; //后序遍历需要
struct _Sq *lchild,*rchild;
}BiTree;
typedef struct _stack
{
BiTree *elements[Max];
int top;
}SetStack;
SetStack S;
void setnull() //初始化栈
{
S.top = 0;
}
void push(BiTree *p) //栈入函数
{
S.elements[S.top++]=p;
}
BiTree *pop() //栈出函数
{
return S.elements[--S.top];
}
前序非递归遍历:根左右,扫描二叉树,将根存入栈,再存入左子树,在对左子树进行上一步操作,直到左子树遍历完成,存入右子树,重复操作进行遍历(由于前序和中序思想类似,不再逐个解释)
void preorder(BiTree *p) //前序非递归遍历 (根左右)
{
BiTree *t = p;
while ( t != NULL || S.top !=0 ) //若结点不为空或栈不为空时
{
while ( t != NULL ) //若结点不为空,重复操作,对每一个子树
{
printf("%4c",t->data); //遍历根结点
push(t); //根结点入栈
t = t->lchild; //访问左子树
}
if ( S.top != 0 ) //若栈不为空
{
t = pop(); //出栈上一个存入的结点
t = t->rchild; //对上一个结点的右子树进行遍历
}
}
}
void inorder(BiTree *p) //中序非递归遍历(左根右)
{
BiTree *t = p;
while ( t != NULL || S.top != 0 )
{
while ( p != NULL )
{
push(t);
p = p->lchild;
}
if ( S.top != 0 )
{
t = pop();
printf("%4c",p->data);
t = t->rchild;
}
}
}
后序非递归遍历:特殊处理,由于后序遍历会经过两次根结点,所以会多出一个cishu变量,在第一次经过时不对其进行遍历,直至第二次才遍历
void laorder(BiTree *p) //后序非递归遍历
{
BiTree *t = p;
while ( t != NULL && S.top != 0 )
{
while ( t != NULL )
{
t->Cishu = 1;
push(t);
t = t->lchild;
}
if ( S.top != 0 )
{
t = pop();
if ( t->Cishu == 1 ) //第一次被访问
{
t->Cishu++;
push(t);
t = t->rchild;
}
else
{
if ( t->Cishu == 2 ) //第二次被访问,制空,防止陷入死循环
{
printf("%4c",t->data);
t = NULL;
}
}
}
}
4.3.二叉树的层次遍历
二叉树的层次遍历主要通过队列先进先出的思想实现:所以我们需要一些有关队列的函数
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define Max 9999
typedef struct _Sq{
char date;
struct _Sq *lchild,*rchild;
}BiTree;
//实现思路:利用队列先进先出的思想
typedef struct _queue{
BiTree *elements[Max];
int front;
int real;
}SetQueue;
SetQueue *p;
void InitQueue(){ //队列初始化
p->front = p->real = 0;
}
void Push (BiTree* s) { //入队
p->elements[++p->real] = s;
}
BiTree* Pop() { //出队
return p->elements[++p->front];
}
int empty() { //判断是否队列为空
return p->real == p->front;
}
void levelorder() {
BiTree* t;
if (t != NULL) { //如果树不为空
Push(t); //将当前结点入队
}
while (!empty()) { //判断队列是否空
t = Pop(); //出队
printf("%4c",t->date); //遍历
if (t->lchild != NULL) {
Push(t->lchild); //如果左子树不为空,入队
}
if (t->rchild != NULL) {
Push(t->rchild); //如果右子树不为空,入队
}
}
}
//由于队列先进先出的思想,所有的子树就会排在根结点的后面,按照层次遍历就实现了
//不能理解的可以用笔举个实例,按照代码进行操作
以上就为二叉树的一些遍历方法和建立方法~
如果有什么错误请指出~笔者会及时更改
多多担待~~