一、树形结构概述
树形结构是数据结构中的一种逻辑关系结构,在此逻辑结构中数据元素之间满足一对多的分层结构关系,也称分层结构。
1.所有的数据节点中的起始节点,有且仅有一个,也称为根节点。
没有直接前驱,可以有多个直接后继节点。
2.末尾节点,可以有一个或者多个,也称为叶节点,或者树叶。
每一个节点没有直接后继节点,有且仅有一个直接前驱节点。
3.中间的节点,也称为内部节点。
每一个节点有且仅有一个直接前驱节点;可以有多个直接后继节点。
二、树的定义
树是n个节点的有序集合,它满足两个条件:
1.有且仅有一个特定的根节点;
2.其余节点可以分为m个互不相交的有序集合T1,T2,......Tm,其中每个集合又是一棵树,称为其根的子树。
三、二叉树的定义
二叉树是n个节点的有限集合,它或者是空集,或者是由一个根节点以及两棵互不相交、分别称为左右子树的二叉树组成。二叉树与普通有序树不同,二叉树严格区分左右孩子,即使只有一个子节点也会区分。
四、实例:
创建如下图的二叉树,分别输出层次遍历、先序遍历、中序遍历、后序遍历;
所谓的遍历,指的是沿某条搜索路径周游二叉树,对树中的每一个节点访问一次且仅访问一次;
对于二叉树的遍历方式:主要分为递归遍历和分层遍历实现。
在对于二叉树的遍历过程中,如果去根节点,左子树和右子树也是二叉树,可以采用相同的遍历思路实现对左子树和右子树遍历过程。所以在对于二叉树的遍历可以采用递归遍历算法实现。
具体实现:
1.树和队列结构类型定义
//节点数据域类型定义
typedef int data_t;
//节点数据类型的定义
typedef struct binTree{
data_t data;//结点本身数据
struct binTree *lchild;//左孩子节点空间地址
struct binTree *rchild;//右孩子节点空间地址
}binTree_t;
//链队列定义
typedef struct node{
binTree_t *addr;
struct node *next;
}node_t;
typedef struct linkqueue{
node_t *front;
node_t *rear;
}linkqueue_t;
2.创建二叉树和队列
//创建完全二叉树
binTree_t * CreateBinTree(int i,int n)
{
binTree_t *btree;
//创建根节点
btree = malloc(sizeof(binTree_t));
if(btree == NULL)
return NULL;
memset(btree,0,sizeof(binTree_t));
btree->data = i; //根节点数据域存储的是节点编号
//左子树设置
if(2*i<=n)
btree->lchild = CreateBinTree(2*i,n);
else
btree->lchild = NULL;
//右子树设置
if(2*i+1<=n)
btree->rchild = CreateBinTree(2*i+1,n);
else
btree->rchild = NULL;
return btree;
}
//创建链队列
linkqueue_t * CreateLinkQueue()
{
linkqueue_t *queue;
queue = malloc(sizeof(linkqueue_t));
if(queue == NULL)
return NULL;
queue->front = malloc(sizeof(node_t));
if(queue->front == NULL)
{
free(queue);
return NULL;
}
queue->rear = queue->front;
return queue;
}
三、队列操作
//入队
int EnLinkQueue(linkqueue_t * queue,binTree_t *myaddr)
{
node_t * p;
if(queue == NULL)
return -1;
//创建入队结点并初始化
p = malloc(sizeof(node_t));
if(p == NULL)
return -1;
p->addr = myaddr;
//入队
p->next = NULL;
queue->rear->next = p;
queue->rear = p;
return 0;
}
//获得队列元素
int GetLinkQueue(linkqueue_t *queue,binTree_t **myaddr)
{
if(queue == NULL)
return -1;
if(queue->front->next == NULL)
return -1;
*myaddr = queue->front->next->addr;
return 0;
}
//出队
int DeLinkQueue(linkqueue_t *queue)
{
node_t *p;
if(queue == NULL)
return -1;
if(queue->front->next == NULL)
return -1;
//出队
p = queue->front->next;
queue->front->next = p->next;
free(p);
//出队的结点为最后一个结点
if(queue->front->next == NULL)
queue->rear = queue->front;
return 0;
}
//判断链队列为空
int isEmptyLinkQueue(linkqueue_t *queue)
{
return (queue->front == queue->rear);
}
四、分层遍历
//分层遍历
void layer_order(binTree_t * btree)
{
binTree_t *myaddr;
//创建空队列
linkqueue_t * queue;
queue = CreateLinkQueue();
if(queue == NULL)
return;
//遍历根节点,并将节点入队
printf("%d ",btree->data);
EnLinkQueue(queue,btree);
while(!isEmptyLinkQueue(queue))
{
GetLinkQueue(queue,&myaddr);
DeLinkQueue(queue);
//遍历左子节点
if(myaddr->lchild != NULL)
{
printf("%d ",myaddr->lchild->data);
EnLinkQueue(queue,myaddr->lchild);
}
//遍历右子节点
if(myaddr->rchild != NULL)
{
printf("%d ",myaddr->rchild->data);
EnLinkQueue(queue,myaddr->rchild);
}
}
printf("\n");
}
五、树的遍历
//前序遍历
void pre_order(binTree_t * btree)
{
if(btree == NULL)
return ;
printf("%d ",btree->data);//遍历根节点
pre_order(btree->lchild);//遍历左节点
pre_order(btree->rchild);//遍历右节点
}
//中序遍历
void mid_order(binTree_t * btree)
{
if(btree == NULL)
return ;
pre_order(btree->lchild);//遍历左节点
printf("%d ",btree->data);//遍历根节点
pre_order(btree->rchild);//遍历右节点
}
//后序遍历
void after_order(binTree_t * btree)
{
if(btree == NULL)
return ;
pre_order(btree->lchild);//遍历左节点
pre_order(btree->rchild);//遍历右节点
printf("%d ",btree->data);//遍历根节点
}
六、主函数调用
int main()
{
binTree_t *btree;
//创建完全二叉树:根节点编号为1,最大节点编号为12
btree = CreateBinTree(1,12);
if(btree == NULL)
return -1;
//分层遍历
layer_order(btree);
//先序遍历
pre_order(btree);
printf("\n");
//中序遍历
mid_order(btree);
printf("\n");
//后序遍历
after_order(btree);
printf("\n");
return 0;
}