二叉树是一种使用二叉链表的数据结构的形式来存储数据和读取数据的
其独特的非线性结构有其独到的优势
这次试验是有关二叉树的相关操作,三种遍历方式(递归版本和非递归版本)和层序遍历(用线性的方式来遍历非线性的数据结构),以及求深度和各种节点的个数
以下就是实现二叉树的各种操作的代码(代码中间有相应的注释):
#include <stdio.h>
#include <stdlib.h>
typedef struct tree
{
int data;//数据域
struct tree *lchild;//左孩子的指针域
struct tree *rchild;//右孩子的指针域
}tree;
tree *stack[20];//存储结点指针
int top=-1;//栈顶指针
tree *queue[20];//存储结点指针的队列
int front = -1,rear = -1;//队列头尾指针
int number1;//记录叶子节点个数
int number2;//记录单孩子节点个数
int number3;//记录双孩子节点个数
tree *create()
{
tree *t;
int number;
t=(tree *)malloc(sizeof(tree));
scanf("%d",&number);
if(number==0) t=NULL;
else
{
t=(tree *)malloc(sizeof(tree));
t->data=number;
t->lchild=create();
t->rchild=create();
}
return t;
}
///
//递归实现三种遍历
//先序遍历(pre_order)
void pre_order(tree *s)
{
if(NULL!=s)
{
printf("%-3d",s->data);
pre_order(s->lchild);
pre_order(s->rchild);
}
}
//中序遍历(in_order)
void in_order(tree *s)
{
if(NULL!=s)
{
in_order(s->lchild);
printf("%-3d",s->data);
in_order(s->rchild);
}
}
//后续遍历(post_order)
void post_order(tree *s)
{
if(NULL!=s)
{
post_order(s->lchild);
post_order(s->rchild);
printf("%-3d",s->data);
}
}
/
/
//非递归实现三种遍历
//非递归前序遍历
void _pre_order(tree *s)
{
tree *p;
//判断根节点不为空
if(NULL!=s)
stack[++top]=s;
while(top>-1)
{
//先访问根节点
p=stack[top--];
printf("%-3d",p->data);
//右孩子先入栈
if(NULL!=p->rchild)
stack[++top]=p->rchild;
//左孩子再入栈
if(NULL!=p->lchild)
stack[++top]=p->lchild;
}
}
//非递归中序遍历
void _in_order(tree *s)
{
//重新初始化栈顶指针
top=-1;
tree *p;
if(NULL!=s)
p=s;
while(top>-1||NULL!=p)
{
//左孩子入栈
while(NULL!=p)
{
stack[++top]=p;
p=p->lchild;
}
if(top>-1)
{
//出栈访问节点
p=stack[top--];
printf("%-3d",p->data);
//访问右孩子
p=p->rchild;
}
}
}
//非递归后续遍历
void _post_order(tree *s)
{
tree *p;
//重新初始化栈顶指针
int sign,top=-1;
if(s!=NULL)
{
do
{
/* s所有左节点入栈 */
while (s!=NULL)
{
top++;
stack[top]=s;
s=s->lchild;
}
/* p指向栈顶前一个已访问节点 */
p=NULL;
/* 置b为已访问 */
sign=1;
while(top!=-1&&sign)
{
/* 取出栈顶节点 */
s=stack[top];
/* 右孩子不存在或右孩子已访问则访问b */
if(s->rchild==p)
{
printf("%-3d",s->data);
top--;
/* p指向被访问的节点 */
p=s;
}
else
{
/* b指向右孩子节点 */
s=s->rchild;
/* 置未访问标记 */
sign=0;
}
}
}while (top!=-1);
}
}
//
//层序遍历
void level_order(tree *s)
{
tree *temp = s;
if(!temp) return;
queue[++front] = temp;//根节点进队列
while(1)
{
temp = queue[++rear];//出队列
if(temp)
{
printf("%-3d",temp->data);
if(temp->lchild)
queue[++front] = temp->lchild;//左孩子进队列
if(temp->rchild)
queue[++front] = temp->rchild;//右孩子进队列
}
else
break;
}
}
//
//
//二叉树的深度
int depth(tree *s)
{
tree *temp = s;
int left,right;//记录左右两边子树的结点个数
if(!temp) return 0;
else
{
//先遍历左边
left = depth(temp->lchild);
//再遍历右边
right = depth(temp->rchild);
//返回节点个数
return left > right ? left + 1 : right + 1;
}
}
//
//
//二叉树的节点个数
int node_number(tree *s)
{
tree *temp = s;
if(!temp) return 0;
else
return (node_number(temp->lchild) + 1 + node_number(temp->rchild));
}
//
//
//二叉树的叶子节点个数
int final_node_number(tree *s)
{
tree *temp = s;
if(!s) return 0;
if(!temp->lchild && !temp->rchild) ++number1;//左右节点同时为空才是叶子节点
else
{
final_node_number(temp->lchild);
final_node_number(temp->rchild);
}
return number1;
}
//
//
//二叉树的单孩子节点个数
int one_son_node(tree *s)
{
tree *temp = s;
if(!s) return 0;
if(!temp->lchild && temp->rchild)
{
number2++;
one_son_node(temp->rchild);//左孩子为空,继续遍历右孩子
}
else
if(temp->lchild && !temp->rchild)
{
number2++;
one_son_node(temp->lchild);//右孩子为空继续遍历左孩子
}
else
{
one_son_node(temp->lchild);
one_son_node(temp->rchild);
}
return number2;
}
//
//
//二叉树的双孩子节点个数
int two_son_node(tree *s)
{
tree *temp = s;
if(!s) return 0;
if(temp->lchild && temp->rchild)
{
++number3;
two_son_node(temp->lchild);
two_son_node(temp->rchild);
}
else
if(!temp->lchild && temp->rchild)//左孩子为空,继续遍历右孩子
two_son_node(temp->rchild);
else
if(temp->lchild && !temp->rchild)//有孩子为空,继续遍历左孩子
two_son_node(temp->lchild);
return number3;
}
//
//
//销毁一棵二叉树
void destory(tree *s)
{
tree *temp = s;
if(!temp) return ;
tree *left = temp->lchild,*right = temp->rchild;
free(temp);
destory(left);
destory(right);
}
//
int main(void)
{
//创建根节点
tree *root;
//create the binary tree
root=create();
printf("递归版本如下所示:");
//先序遍历(pre_order)
printf("\n先序遍历如下所示:");
pre_order(root);
//中序遍历(in_order)
printf("\n中序遍历如下所示:");
in_order(root);
//后续遍历(post_order)
printf("\n后序遍历如下所示:");
post_order(root);
printf("\n\n非递归版本如下所示:");
//非递归前序遍历
printf("\n先序遍历如下所示:");
_pre_order(root);
//非递归中序遍历
printf("\n中序遍历如下所示:");
_in_order(root);
//非递归后序遍历
printf("\n后序遍历如下所示:");
_post_order(root);
printf("\n层序遍历如下所示:");
level_order(root);
printf("\n\n该二叉树的深度为:%d",depth(root));
printf("\n该二叉树的结点个数为:%d",node_number(root));
printf("\n该二叉树的叶子节点个数为:%d",final_node_number(root));
printf("\n该二叉树的单孩子节点个数为:%d",one_son_node(root));
printf("\n该二叉树的双孩子节点个数为:%d",two_son_node(root));
printf("\n");
//销毁一棵二叉树
destory(root);
return 0;
}
百说不如一图,以下是结果的截图和二叉树的结构图:
继续更新--------------
这次添加二叉查找树的两个功能函数,一个是判断是否为二叉查找树(二叉树的构造方法跟上面的一样),另一个是对二叉查找树进行关键字的查找
个人认为二叉查找树的关键字查找有点类似于折半查找,二叉查找树本身就是一个按照树形结构排序好了的树结构,如果根节点为空则返回NULL值,如果根节点跟关键字相同就查找成功,如果关键字大于节点就往右子树查找,如果比节点小,就往左子树查找,然后依次递归(也有可以用迭代的方法来替代)
一下就是两个功能函数还有结果截图:
第一个是判断是否为二叉查找树的函数:
//检查是否为二叉查找树
int check_binary_tree_search(tree *s)
{
tree *temp = s;
if(temp->data > temp->lchild->data && temp->data < temp->rchild->data)
return 1;
else
{
check_binary_tree_search(temp->lchild);
check_binary_tree_search(temp->rchild);
}
return 0;
}
然后是进行查找的函数(递归版本):
//二叉查找树的查找(递归版本)
int binary_tree_search(tree *s,int key)
{
tree *temp = s;
if(!s) return NULL;
if(key == temp->data) return 1;
else
if(key > temp->data)
return binary_tree_search(temp->rchild);
return binary_tree_search(temp->lchild);
}
查找的函数(迭代版本):
//二叉查找树的查找
int binary_tree_search(tree *s,int key)
{
tree *temp = s;
while(temp)
{
if(key == temp->data)
return 1;
else
if(key > temp->data)
temp = temp->rchild;
else
temp = temp->lchild;
}
return 0;
}
以下是用上面的函数构造的一颗二叉查找树的结构:
以下是进行调试的结果截图: