一、树
一种非线性的数据结构,树的结点包含一个数据及若干指向子树的分支。
结点拥有的子树数称为结点的度。度为0的结点称为叶结点,度不为0的结点称为分支结点。
树的度定义为所有结点中度的最大值。
树中结点的最大层次称为树的高度或深度。
二、二叉树
一个根结点上最多有两个结点的树称为二叉树。
满二叉树:二叉树中所有分支结点的度数都为2,且叶结点都在同一层次上。
完全二叉树:如果一棵具有n个结点的高度为k的二叉树,它每一个结点都与高度为k的满二叉树中编号为1-n的结点一一对应,则这棵二叉树称为完全二叉树。
同样结点数的二叉树,完全二叉树的高度最小。
主要性质:
1.在二叉树的第 i 层最多有 2^(i-1) 个结点。
2.深度为k 的二叉树最多有(2^k ) - 1 个结点
3.对于任何的一棵二叉树,如果其叶结点有n0个,度为2的非叶结点有n2个,则 n0 = n2 + 1。===>n1+2n2 = n0+n1+n2-1
4.具有n 个结点的完全二叉树的高度为log2n +1
5.编号从0开始,左孩子结点的编号为2n+1,右孩子结点的编号为2n+2
编号从1开始,左孩子结点的编号为2n, 右孩子结点的编号为2n+1
BTree.h文件
#ifndef _BTREE_H_
#define _BTREE_H_
typedef enum{FALSE, TRUE} BOOL;
typedef enum{LEFT, RIGHT} MOUNTWAY;//挂载
typedef char BTreeData;
typedef struct btreeNode // 二叉树的结点
{
BTreeData data; // 数据
struct btreeNode *lchild; // 左孩子结点指针
struct btreeNode *rchild; // 右孩子结点指针
}BTreeNode;
typedef struct btree // 二叉树
{
BTreeNode *root; // 指向根节点的指针
}BTree;
BTree* BTree_Create();//创建树
typedef void (*PFUNC)(BTreeNode *node, int level);//函数指针
//PFUNC是一个指针变量,它指向一个函数
1、插入位置 用二进制表示路径
0 代表左 1代表右 100(4) 左左右
右左左 001(1) ===> 无法确定步数
需要另一个参数:步数 (4 3) (1, 3)
2、挂载方式
btree 要插入的二叉树
data 要插入的数据
path 插入位置的路径
steps 从根节点开始走的步数
mw 原来的结点挂载到新节点后的方式
BOOL BTree_Insert(BTree *btree, BTreeData data, int path, int steps, MOUNTWAY mw);//插入结点
void BTree_Display(BTree *btree, PFUNC callback);//打印
BOOL BTree_Delete(BTree *btree, int path, int steps);//删除结点
int BTree_Count(BTree* btree);//获取树的结点数
int BTree_Height(BTree* btree);//获取树的高度
int BTree_Degree(BTree* btree);//获取树的度
void BTree_Destroy(BTree *btree);//销毁树
#endif // _BTREE_H_BTree.h文件
BTree.c文件
#include "BTree.h"
#include <stdlib.h>
创建树
BTree* BTree_Create()
{
BTree* btree = (BTree*)malloc(sizeof(BTree)/sizeof(char));//申请空间
if (NULL == btree)
return NULL;
btree->root = NULL; // 空的树
return btree;//返回内存地址
}
插入结点
BOOL BTree_Insert(BTree *btree, BTreeData data, int path, int steps, MOUNTWAY mw)
{
if (NULL == btree)//入口参数检测
return FALSE;
BTreeNode *node = (BTreeNode*)malloc(sizeof(BTreeNode)/sizeof(char));//申请新的结点空间
if (NULL == node)
return FALSE;
node->data = data;//赋值
node->lchild = NULL;
node->rchild = NULL;
BTreeNode *parent = NULL; // 父节点
BTreeNode *tmp = btree->root; // 根节点
int way = 0;
while (steps>0 && tmp != NULL)//找到要插入数位置,保存要插入位置的根结点
{
way = path & 1;
path >>= 1;
parent = tmp;//需要保存要插入位置根结点的值
if (LEFT == way)
tmp = tmp->lchild;
else
tmp = tmp->rchild;
steps--;
}
if(LEFT == mw)//挂载
node->lchild = tmp;
else
node->rchild = tmp;
if (parent != NULL)//考虑父结点位空的情况
{
if (LEFT == way)
parent->lchild = node;
else
parent->rchild = node;
}
else
btree->root = node;//根节点的父结点为空
return TRUE;
}
删除结点
void r_delete(BTreeNode *node)
{
if (NULL == node)
return;
r_delete(node->lchild); // 删除左结点
r_delete(node->rchild); // 删除右结点
free(node); // 删除自己
}
删除结点(与插入结点类似)
BOOL BTree_Delete(BTree *btree, int path, int steps)
{
if (NULL == btree)
return FALSE;
BTreeNode *parent = NULL; // 父节点
BTreeNode *tmp = btree->root; // 根节点
int way = 0;
while (steps>0 && tmp != NULL)
{
way = path & 1;
path >>= 1;
parent = tmp;
if (LEFT == way)
tmp = tmp->lchild;
else
tmp = tmp->rchild;
steps--;
}
if (NULL != parent)
{
if (LEFT == way)
parent->lchild = NULL;
else
parent->rchild = NULL;
}
else
btree->root = NULL;
r_delete(tmp);
return TRUE;
}
获取树的结点:左结点数+右结点数+1(根结点)
int r_count(BTreeNode *node)
{
if (NULL == node)
return 0;
int lc = r_count(node->lchild); // 左子树的结点数
int rc = r_count(node->rchild); // 右子树的结点数
return lc+rc+1;
}
int BTree_Count(BTree* btree)
{
if (NULL == btree)
return 0;
return r_count(btree->root);
}
获取树的高度:左子树的高度与右子树的高度中大的值+1
int r_height(BTreeNode *node)
{
if (NULL == node)
return 0;
int lh = r_height(node->lchild); // 左子树的高度
int rh = r_height(node->rchild); // 右子树的高度
return (lh>rh?lh:rh)+1;
}
int BTree_Height(BTree* btree)
{
if (NULL == btree)
return 0;
return r_height(btree->root);
}
获取树的度:左子树的度与右子树的度中大的值(假如根节点的度为1时)
(这个是重点)
int r_degree(BTreeNode *node)
{
if (NULL == node)
return 0;
int degree = 0;
if (NULL != node->lchild)
degree++;
if (NULL != node->rchild)
degree++;
if (1 == degree)
{
int ld = r_degree(node->lchild); // 左子树的度
int rd = r_degree(node->rchild); // 右子树的度
if (degree < ld)
degree = ld;
if (degree < rd)
degree = rd;
}
return degree;
}
int BTree_Degree(BTree* btree)
{
if (NULL == btree)
return 0;
return r_degree(btree->root);
}
销毁树
void BTree_Destroy(BTree *btree)
{
if (NULL == btree)
return;
r_delete(btree->root); // 删除根节点
free(btree); // 删除树
}
打印(运用递归的方式打印)
具体打印方式由main函数进行定义
void r_display(BTreeNode *node, PFUNC callback, int level)
{
callback(node, level); // 1、打印自己
if (NULL == node)
{
return;
}
if (node->lchild != NULL || node->rchild != NULL)
{
r_display(node->lchild, callback, level+1); // 2、打印左结点
r_display(node->rchild, callback, level+1); // 3、打印右结点
}
}
void BTree_Display(BTree *btree, PFUNC callback)
{
if (NULL == btree)
return;
r_display(btree->root, callback, 1);
}
前序遍历(递归)
void pre_order(BTreeNode* node)
{
if (node == NULL)
return;
printf ("%4c", node->data); // 根
pre_order(node->lchild); // 左
pre_order(node->rchild); // 右
}
中序遍历(递归)
void mid_order(BTreeNode* node)
{
if (node == NULL)
return;
mid_order(node->lchild); // 左
printf ("%4c", node->data); // 根
mid_order(node->rchild); // 右
}
后序遍历(递归)
void last_order(BTreeNode* node)
{
if (node == NULL)
return;
last_order(node->lchild); // 左
last_order(node->rchild); // 右
printf ("%4c", node->data); // 根
}
main.c文件
#include <stdio.h>
#include "BTree.h"
void myprint(BTreeNode *node, int level)//用类似于tree的方式来打印
{
int i;
for (i = 1; i < level; i++)
{
printf ("----");
}
if (node != NULL)
printf ("%c\n", node->data);
else
printf ("\n");
}
int main()
{
BTree* btree = BTree_Create();
if (NULL == btree)
return -1;
// printf ("二叉树创建成功\n");
BTree_Insert(btree, 'A', 0, 0, LEFT);
BTree_Insert(btree, 'B', 0, 1, LEFT);
BTree_Insert(btree, 'C', 1, 1, LEFT);
BTree_Insert(btree, 'D', 0, 2, LEFT);
BTree_Insert(btree, 'E', 2, 2, LEFT);
BTree_Insert(btree, 'F', 1, 2, LEFT);
BTree_Insert(btree, 'J', 6, 3, LEFT);
BTree_Insert(btree, 'H', 1, 3, LEFT);
BTree_Display(btree, myprint);
printf ("前序遍历: ");
pre_order(btree->root);
printf ("\n");
printf ("中序遍历: ");
mid_order(btree->root);
printf ("\n");
printf ("后序遍历: ");
last_order(btree->root);
printf ("\n");
return 0;
}
验证结果为:
非递归方式实现前序遍历(借助链式栈实现)
void pre1(BTreeNode *root)
{
if(root == NULL)
return;
LinkStack *stack = CreateStack();
BTreeNode* p = root;
while (p != NULL || !StackEmpty(stack))
{
while(p)
{
printf ("%4c", p->data);//打印
Push(stack, p);//入栈
p = p->lchild;//遍历左子树
}
if (!StackEmpty(stack))
{
Pop (stack, &p);//出栈
p = p->rchild;//遍历右子树
}
}
}
非递归方式实现中序遍历 (借助链式栈来实现)
void mid1(BTreeNode *root)
{
if(root == NULL)
return;
LinkStack *stack = CreateStack();
BTreeNode* p = root;
while (p != NULL || !StackEmpty(stack))
{
while(p)
{
Push(stack, p);//入栈
p = p->lchild;//遍历左子树
}
if (!StackEmpty(stack))
{
Pop (stack, &p);//出栈
printf ("%4c", p->data);//打印
p = p->rchild;//右子树遍历
}
}
}