我要成为嵌入式高手之3月23日数据结构第六天!!
————————————————————————————
树形结构
特性: 一对多
概念:
由n个结点组成的有限集
有一个根结点;其他结点只有一个前驱结点,但可以有多个后继结点(一对多)
n = 0时为空树
专业词汇:
叶子结点(终端结点 )
只有前驱没有后继
根结点
A
分支节点
B\C\D
结点度
该结点后继结点的个数
度(默认为广度)
深度:这棵树所对应的层数
广度:这棵树里结点度最大的度
二叉树
树的度(广度)为2 且子节点的位置不能交换的数叫做二叉树
满二叉树
在不增加层数的情况下无法再增加一个结点(叶子结点处于同一层、除叶子结点其他结点的度都为2)
k层满二叉树:
第k层结点个数:2^(k-1);
k层结点总个数:2^k-1;
完全二叉树
满二叉树是完全二叉树,完全二叉树不一定是满二叉树
概念:在满二叉树的基础上,若要增加结点只能从上至下、从左至右依次增加;若要删除结点只能从下至上、从右至左依次删除,则剩下的树为完全二叉树
例:有一棵完全二叉树的总结点个数为4847个,求该二叉树的叶子结点个数
答:2424个
二叉树的遍历
解决如何将一对多的树形结构存储到一对一的线性结构中的问题
前序遍历
根结点 左子树 右子树 —— A B C E H D F G 深度优先
中序遍历
左子树 根结点 右子树 —— C B H E A F D G 深度优先
后序遍历
左子树 右子树 根节点 —— C H E B F G D A 深度优先
层序遍历
从上至下、从左至右 逐层遍历 —— A B D C E F G H 广度优先
通过遍历的序列还原二叉树
只知道前序或后序不能还原唯一的二叉树,前序和后序也不能还原唯一二叉树、只有
前序 + 中序 = 唯一二叉树
后序 + 中序 = 唯一二叉树
前序:A B C
前序:A B C 后序:C B A
代码实现二叉树
结点
左子节点指针 数据域 右子节点指针
扩展二叉树
前序遍历:A B C # # E H # # # D F # # G # #
1、创建二叉树
/* 创建一个二叉树 */
TREE_NODE *CreateBtree()
{
DATA_TYPE data = tree[idx++];
if ('#' == data)
{
return NULL;
}
TREE_NODE *pnode = malloc(sizeof(TREE_NODE));
if (NULL == pnode)
{
perror("fail to malloc TREE_NODE");
return NULL;
}
pnode->data = data;
pnode->pl = CreateBtree();
pnode->pr = CreateBtree();
return pnode;
}
2、前序遍历
/* 前序遍历一遍二叉树 */
void PreOrder(TREE_NODE *proot)
{
if (NULL == proot)
{
return ;
}
printf("%c ", proot->data);
PreOrder(proot->pl);
PreOrder(proot->pr);
}
3、中序遍历
void MidOrder(TREE_NODE *proot)
{
if (NULL == proot)
{
return ;
}
MidOrder(proot->pl);
printf("%c ", proot->data);
MidOrder(proot->pr);
}
4、后序遍历
void PosOrder(TREE_NODE *proot)
{
if (NULL == proot)
{
return ;
}
PosOrder(proot->pl);
PosOrder(proot->pr);
printf("%c ", proot->data);
}
5、获取二叉树的结点个数
/* 获取二叉树的结点个数 */
int GetBtreeNodeCnt(TREE_NODE *proot)
{
if (NULL == proot)
{
return 0;
}
return 1+GetBtreeNodeCnt(proot->pl)+GetBtreeNodeCnt(proot->pr);
}
6、获取二叉树的层数
/* 获取二叉树层数 */
int GetBtreeLayerCnt(TREE_NODE *proot)
{
if (NULL == proot)
{
return 0;
}
int lay_l = GetBtreeLayerCnt(proot->pl);
int lay_r = GetBtreeLayerCnt(proot->pr);
return lay_l > lay_r ? lay_l + 1 : lay_r + 1;
}
7、销毁二叉树
void DestroyBtree(TREE_NODE *proot)
{
if (NULL == proot)
{
return ;
}
DestroyBtree(proot->pl);
DestroyBtree(proot->pr);
free(proot);
}
前7项运行结果:
8、二叉树的层序遍历
要依靠队列结构
头文件使用需要注意
哪里需要哪里包含
易知只有在tree.c的层序遍历中需要用到队列相关函数,故只需要在tree.c中包含queue.h
/* 二叉树的层序遍历 */
void LayerOrder(TREE_NODE *proot)
{
QUEUE_LIST *pque = CreateQueueList();
if (NULL == pque)
{
return ;
}
DATA_TYPE outdata;
QUEUE_NODE *pnode = CreateQueueNode(proot);
JoinQueueNode(pque, pnode);
while (!IsEmptyQueue(pque))
{
LeaveQueueNode(pque, &outdata);
printf("%c ", outdata->data);
if (outdata->pl != NULL)
{
pnode = CreateQueueNode(outdata->pl);
JoinQueueNode(pque, pnode);
}
if (outdata->pr != NULL)
{
pnode = CreateQueueNode(outdata->pr);
JoinQueueNode(pque, pnode);
}
}
DestroyQueue(pque);
}
总程序
tree.c
#include "tree.h"
#include "queue.h"
int idx = 0;
char tree[] = "ABC##EH###DF##G##";
/* 创建一个二叉树 */
TREE_NODE *CreateBtree()
{
BTDATA_TYPE data = tree[idx++];
if ('#' == data)
{
return NULL;
}
TREE_NODE *pnode = malloc(sizeof(TREE_NODE));
if (NULL == pnode)
{
perror("fail to malloc TREE_NODE");
return NULL;
}
pnode->data = data;
pnode->pl = CreateBtree();
pnode->pr = CreateBtree();
return pnode;
}
/* 前序遍历一遍二叉树 */
void PreOrder(TREE_NODE *proot)
{
if (NULL == proot)
{
return ;
}
printf("%c ", proot->data);
PreOrder(proot->pl);
PreOrder(proot->pr);
}
void MidOrder(TREE_NODE *proot)
{
if (NULL == proot)
{
return ;
}
MidOrder(proot->pl);
printf("%c ", proot->data);
MidOrder(proot->pr);
}
void PosOrder(TREE_NODE *proot)
{
if (NULL == proot)
{
return ;
}
PosOrder(proot->pl);
PosOrder(proot->pr);
printf("%c ", proot->data);
}
/* 获取二叉树的结点个数 */
int GetBtreeNodeCnt(TREE_NODE *proot)
{
if (NULL == proot)
{
return 0;
}
return 1+GetBtreeNodeCnt(proot->pl)+GetBtreeNodeCnt(proot->pr);
}
/* 获取二叉树层数 */
int GetBtreeLayerCnt(TREE_NODE *proot)
{
if (NULL == proot)
{
return 0;
}
int lay_l = GetBtreeLayerCnt(proot->pl);
int lay_r = GetBtreeLayerCnt(proot->pr);
return lay_l > lay_r ? lay_l + 1 : lay_r + 1;
}
void DestroyBtree(TREE_NODE *proot)
{
if (NULL == proot)
{
return ;
}
DestroyBtree(proot->pl);
DestroyBtree(proot->pr);
free(proot);
}
/* 二叉树的层序遍历 */
void LayerOrder(TREE_NODE *proot)
{
QUEUE_LIST *pque = CreateQueueList();
if (NULL == pque)
{
return ;
}
DATA_TYPE outdata;
QUEUE_NODE *pnode = CreateQueueNode(proot);
JoinQueueNode(pque, pnode);
while (!IsEmptyQueue(pque))
{
LeaveQueueNode(pque, &outdata);
printf("%c ", outdata->data);
if (outdata->pl != NULL)
{
pnode = CreateQueueNode(outdata->pl);
JoinQueueNode(pque, pnode);
}
if (outdata->pr != NULL)
{
pnode = CreateQueueNode(outdata->pr);
JoinQueueNode(pque, pnode);
}
}
DestroyQueue(pque);
}
tree.h
#ifndef _TREE_H_
#define _TREE_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char BTDATA_TYPE;
typedef struct tree_node
{
BTDATA_TYPE data;
struct tree_node *pl;
struct tree_node *pr;
}TREE_NODE;
extern TREE_NODE *CreateBtree();
extern void PreOrder(TREE_NODE *proot);
extern void MidOrder(TREE_NODE *proot);
extern void PosOrder(TREE_NODE *proot);
extern int GetBtreeNodeCnt(TREE_NODE *proot);
extern int GetBtreeLayerCnt(TREE_NODE *proot);
extern void DestroyBtree(TREE_NODE *proot);
extern void LayerOrder(TREE_NODE *proot);
#endif
queue.c
#include "queue.h"
/* 创建队列 */
QUEUE_LIST *CreateQueueList()
{
QUEUE_LIST *plist = malloc(sizeof(QUEUE_LIST));
if (NULL == plist)
{
perror("fail to malloc list");
return NULL;
}
plist->pbegin = NULL;
plist->pend = NULL;
plist->clen = 0;
return plist;
}
QUEUE_NODE *CreateQueueNode(DATA_TYPE data)
{
QUEUE_NODE *pnode = malloc(sizeof(QUEUE_NODE));
if (NULL == pnode)
{
perror("fail to malloc node");
return NULL;
}
pnode->data = data;
pnode->pnext = NULL;
return pnode;
}
/* 判断队列是否为空 */
int IsEmptyQueue(QUEUE_LIST *pque)
{
return NULL == pque->pbegin;
}
/* 入队 */
int JoinQueueNode(QUEUE_LIST *plist, QUEUE_NODE *pnode)
{
QUEUE_NODE *ptmp = NULL;
if (NULL == plist->pbegin)
{
plist->pbegin = pnode;
plist->pend = pnode;
plist->clen++;
}
else
{
ptmp = plist->pend;
ptmp->pnext = pnode;
plist->pend = pnode;
plist->clen++;
}
return 0;
}
/* 出队 */
int LeaveQueueNode(QUEUE_LIST *plist, DATA_TYPE *pdata)
{
if (IsEmptyQueue(plist))
{
return -1;
}
QUEUE_NODE *pnode = plist->pbegin;
plist->pbegin = pnode->pnext;
if (NULL == plist->pbegin)
{
plist->pend = NULL;
}
if (pdata != NULL)
{
*pdata = pnode->data;
}
free(pnode);
plist->clen--;
return 0;
}
/* 清空队列 */
int DeleteQueueAll(QUEUE_LIST *plist)
{
QUEUE_NODE *ptmp = plist->pbegin;
QUEUE_NODE *pfree = NULL;
if (NULL == plist->pbegin && plist->pend == NULL)
{
return -1;
}
while (ptmp != NULL)
{
pfree = ptmp;
ptmp = ptmp->pnext;
plist->pbegin = ptmp;
free(pfree);
plist->clen--;
}
plist->pend = NULL;
return 0;
}
/* 获取队头数据 */
QUEUE_NODE *GetQueueBegin(QUEUE_LIST *plist)
{
if (NULL == plist->pbegin && NULL == plist->pend)
{
return NULL;
}
else
{
return plist->pbegin;
}
}
/* 销毁队列 */
int DestroyQueue(QUEUE_LIST *plist)
{
int ret = 0;
if (NULL == plist->pbegin && plist->pend == NULL)
{
free(plist);
}
else
{
ret = DeleteQueueAll(plist);
if (0 == ret)
{
free(plist);
}
}
return 0;
}
/* 测试:遍历 */
int SearchAllQueue(QUEUE_LIST *plist)
{
QUEUE_NODE *ptmp = plist->pbegin;
if (NULL == plist->pbegin && NULL == plist->pend)
{
printf("NO DATA!\n");
return -1;
}
else
{
while (ptmp != NULL)
{
//printf("%d\n", ptmp->data);
ptmp = ptmp->pnext;
}
}
printf("len = %d\n", plist->clen);
return 0;
}
queue.h
#ifndef _QUEUE_H
#define _QUEUE_H
#include <stdio.h>
#include <stdlib.h>
#include "tree.h"
typedef TREE_NODE* DATA_TYPE;
typedef struct node
{
DATA_TYPE data;
struct node *pnext;
}QUEUE_NODE;
typedef struct list
{
QUEUE_NODE *pbegin;
QUEUE_NODE *pend;
int clen;
}QUEUE_LIST;
extern QUEUE_LIST *CreateQueueList();
extern QUEUE_NODE *CreateQueueNode(DATA_TYPE data);
extern QUEUE_NODE *GetQueueBegin(QUEUE_LIST *plist);
extern int IsEmptyQueue(QUEUE_LIST *pque);
extern int JoinQueueNode(QUEUE_LIST *plist, QUEUE_NODE *pnode);
extern int LeaveQueueNode(QUEUE_LIST *plist, DATA_TYPE *pdata);
extern int SearchAllQueue(QUEUE_LIST *plist);
extern int DeleteQueueAll(QUEUE_LIST *plist);
extern int DestroyQueue(QUEUE_LIST *plist);
#endif
main.c
#include "tree.h"
int main()
{
int cnt = 0;
TREE_NODE *proot = CreateBtree();
if (NULL == proot)
{
return -1;
}
printf("前序遍历:\n");
PreOrder(proot);
putchar('\n');
printf("中序遍历:\n");
MidOrder(proot);
putchar('\n');
printf("后序遍历:\n");
PosOrder(proot);
putchar('\n');
printf("二叉树的结点个数: ");
cnt = GetBtreeNodeCnt(proot);
printf("%d\n", cnt);
printf("二叉树的层数: %d\n", GetBtreeLayerCnt(proot));
printf("二叉树的层序遍历: ");
LayerOrder(proot);
putchar('\n');
DestroyBtree(proot);
return 0;
}