完全二叉树的概念:对一棵满二叉树,从下向上,从右向左,依次去掉若干个结点形成的二叉树称为完全二叉树。
btree.h //二叉树头文件,用于声明数据类型和相关函数
#ifndef __BTREE_H__
#define __BTREE_H__
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef char dataype_bt; //声明二叉树中存放的数据类型,便于后续更改
typedef struct btreenode{ //二叉树的节点结构:存放的数据 该节点的左子节点地址及右子节点地址。注意和单链表的区别,二叉树是非线性存储,单链表是线性存储
dataype_bt data;
struct btreenode *lchild,*rchild;
}btree_node,*btree_pnode;
extern btree_pnode create_btree1(void); //通过递归方法创建一个二叉树
extern void create_btree(btree_pnode *T); //通过递归方法创建一个二叉树(功能同上)
extern void pre_order(btree_pnode t); //采用递归方法先序遍历
extern void unpre_order(btree_pnode t); //采用非递归方法先序遍历
extern void mid_order(btree_pnode t); //采用递归方法中序遍历
extern void post_order(btree_pnode t); //采用递归方法后序遍历
extern void level_order(btree_pnode t); //层次遍历
extern void travel(char const *str,void (*pfun)(btree_pnode),btree_pnode t); //将上面的函数作为参数传入该函数(函数的回调),实现二叉树的创建 和 遍历,其中参数str可以是回调函数的功能描述
#endif
btree.c //二叉树相关函数的实现方法
#include "btree.h"
#include "linkqueue.h" //链式队列的头文件,关于链式队列的相关函数实现方法请查看博主相关链式队列的文章,这里不做细讲
#include "linkstack.h" //链式栈的头文件,关于链式栈的相关函数实现方法请查看博主相关链式栈的文章,这里不做细讲
btree_pnode create_btree1(void) //通过递归方法创建一个二叉树
{
dataype_bt ch;
btree_pnode new;
scanf("%c",&ch);
if('#'==ch)
{
return NULL;
}
else
{
//创建根结点
new=(btree_pnode)malloc(sizeof(btree_node));
if(NULL==new)
{
perror("malloc");
exit(-1);
}
new->data=ch;
//用相同方法创建左子数
new->lchild=create_btree1();
//用相同方法创建右子数
new->rchild=create_btree1();
}
return new;
}
void create_btree(btree_pnode *T) //通过递归方法创建一个二叉树(功能同上)
{
dataype_bt ch;
scanf("%c",&ch);
if('#'==ch)
{
return ;
}
else{
//创建根结点
(*T)=(btree_pnode)malloc(sizeof(btree_node));
if(NULL==(*T))
{
perror("malloc");
exit(-1);
}
(*T)->data=ch;
//用相同方法创建左子数
create_btree(&((*T)->lchild));
//用相同方法创建右子数
create_btree(&((*T)->rchild));
}
}
void pre_order(btree_pnode t) //采用递归方法先序遍历
{
if(t!=NULL)
{
//访问根结点
printf("%c",t->data);
//先序遍历左子树
pre_order(t->lchild);
//先序遍历右子树
pre_order(t->rchild);
}
}
void unpre_order(btree_pnode t) //采用非递归方法先序遍历
{
linklist top;//top为指向栈顶结点的指针
top=stack_create();//初始化链式栈
/*
该函数包含的头文件 和 实现方法如下:
#include "linkstack.h" //链式栈的头文件,关于链式栈的相关函数实现方法请查看博主相关链式栈的文章,这里不做细讲
linklist stack_create()
{
linklist s;
if((s=(linklist)malloc(sizeof(listnode)))==NULL){
puts("malloc failed");
return NULL;
}
s->next=NULL;
return s;
}
*/
while(t!=NULL || !(stack_empty(top))){
/*
该函数包含的头文件 和 实现方法如下:
#include "linkstack.h" //链式栈的头文件,关于链式栈的相关函数实现方法请查看博主相关链式栈的文章,这里不做细讲
int stack_empty(linklist s) //判断栈是否为空(1表示空,0表示非空)
{
return (s->next==NULL ? 1:0);
}
*/
if(t!=NULL){
printf("%c",t->data);
if(t->rchild !=NULL)
stack_push(top,t->rchild); //入栈
/*
该函数包含的头文件 和 实现方法如下:
#include "linkstack.h" //链式栈的头文件,关于链式栈的相关函数实现方法请查看博主相关链式栈的文章,这里不做细讲
int stack_push(linklist s,datatype_ls value) //入栈
{
linklist p;
if((p=(linklist)malloc(sizeof(listnode)))==NULL)
{
puts("malloc failed");
return -1;
}
p->data = value;
p->next=s->next;
s->next = p;
return 0;
}
*/
t=t->lchild;
}else
t=stack_pop(top); //出栈
/*
该函数包含的头文件 和 实现方法如下:
#include "linkstack.h" //链式栈的头文件,关于链式栈的相关函数实现方法请查看博主相关链式栈的文章,这里不做细讲
datatype_ls stack_pop(linklist s) //出栈
{
linklist p;
datatype_ls ret;
p=s->next;
s->next=p->next;
ret=p->data;
free(p);
p=NULL;
return ret;
}
*/
}
stack_free(top); //释放栈
/*
该函数包含的头文件 和 实现方法如下:
#include "linkstack.h" //链式栈的头文件,关于链式栈的相关函数实现方法请查看博主相关链式栈的文章,这里不做细讲
void stack_free(linklist s) //释放栈
{
linklist p;
printf("free:");
p=s;
while(p)
{
s=s->next;
printf("%d ",p->data);
free(p);
p=s;
}
putchar(10); //10 表示 回车符('\n')
}
*/
}
void mid_order(btree_pnode t) //采用递归方法中序遍历
{
if(t!=NULL)
{
//中序遍历左子树
mid_order(t->lchild);
//访问根结点
printf("%c",t->data);
//中序遍历右子树
mid_order(t->rchild);
}
}
void post_order(btree_pnode t) //采用递归方法后序遍历
{
if(t!=NULL)
{
//后序遍历左子树
post_order(t->lchild);
//后序遍历右子树
post_order(t->rchild);
//访问根结点
printf("%c",t->data);
}
}
void level_order(btree_pnode t) //层次遍历
{
link_pqueue q;
init_linkqueue(&q);//初始化链式队列
/*
该函数包含的头文件 和 实现方法如下:
#include "linkqueue.h" //链式队列的头文件,关于链式队列的相关函数实现方法请查看博主相关链式队列的文章,这里不做细讲
void init_linkqueue(link_pqueue *Q) //创建队列
{
//申请front和rear的空间
*Q=(link_pqueue)malloc(sizeof(link_queue));
if((*Q)==NULL)
{
perror("malloc");
exit(-1);
}
//申请头结点空间
(*Q)->front=(linkqueue_pnode)malloc(sizeof(linkqueue_node));
if((*Q)->front==NULL)
{
perror("malloc");
exit(-1) ;
}
(*Q)->front->next=NULL;
(*Q)->rear=(*Q)->front;
return;
}
*/
while(t!=NULL)
{
//访问t指向的结点数据
printf("%c",t->data);
//当t的左指针不为空,则入队
if(t->lchild!=NULL)
in_linkqueue(t->lchild,q);
/*
该函数包含的头文件 和 实现方法如下:
#include "linkqueue.h" //链式队列的头文件,关于链式队列的相关函数实现方法请查看博主相关链式队列的文章,这里不做细讲
bool in_linkqueue(datatype data,link_pqueue q) //入队
{
linkqueue_pnode new;
//申请数据结点空间
new=(linkqueue_pnode)malloc(sizeof(linkqueue_node));
if(new==NULL)
{
puts("入队失败!");
return false;
}
//将数据存储在申请的空间
new->data=data;
//将new指向的结点插入到链式队列中
new->next=q->rear->next; //这里等价于new->next = NULL;
q->rear->next=new;
//让rear指针指向新的队尾结点
q->rear=q->rear->next; //等价于q->rear = new;
return true;
}
*/
//当t的右指针不为空,则入队
if(t->rchild!=NULL)
in_linkqueue(t->rchild,q);
//队列不为空,则出队
if(!is_empty_linkqueue(q))
out_linkqueue(q,&t);
/*
该函数包含的头文件 和 实现方法如下:
#include "linkqueue.h" //链式队列的头文件,关于链式队列的相关函数实现方法请查看博主相关链式队列的文章,这里不做细讲
bool out_linkqueue(link_pqueue q,datatype *D) //出队
{
linkqueue_pnode t;
//判断队列是否空
if(is_empty_linkqueue(q)){
printf("队列已空!\n");
return false;
}
//出队
t=q->front;
q->front =q->front->next;
*D=q->front->data;
free(t);
return true;
}
*/
else
break;
}
free_linkqueue(q); //释放队列
/*
该函数包含的头文件 和 实现方法如下:
#include "linkqueue.h" //链式队列的头文件,关于链式队列的相关函数实现方法请查看博主相关链式队列的文章,这里不做细讲
void free_linkqueue(link_pqueue q) //释放队列
{
link_pqueue p;
p = q->front;
while(p)
{
q->front = q->front->next;
free(p);
p = q->front;
}
free(q);
}
*/
}
void travel(char const *str,void (*pfun)(btree_pnode),btree_pnode t) //将上面的函数作为参数传入该函数(函数的回调),实现二叉树的创建 和 遍历,其中参数str可以是回调函数的功能描述
{
printf("%s",str);
pfun(t);
puts("");
}