之前做过排序算法与单链表的总结(见前面的博文),现把二叉树的给补上。本文主要从二叉树的建立,二叉树结点个数统计,二叉树的遍历和二叉排序树几个方面进行介绍总结。
1、二叉树的建立
先建立二叉树的结点
// 定义二叉树的结点
typedef struct btreenode
{
char data; // 数据域
struct btreenode *lchild; // 左孩子指针
struct btreenode *rchild; // 右孩子指针
}btnode, *btnodePoint;
注意btnode, *btnodePointbtnode定义的是结构体变量,btnodePoint定义的是结构体指针变量
btnode *bt与btnodePoint bt是等价的,bt都是结构体指针变量
详见 http://blog.sina.com.cn/s/blog_8bba7b400102w2qj.html
定义好二叉树结点后,开始创建二叉树
/******************************************************
* 函数名称:btnode *CtreateBinaryTree(char *str)
* 参 数:str----待创建二叉树的先序遍历字符序列
* 函数功能:根据先序遍历规则创建指定的二叉树
* 返 回 值:创建二叉树的根结点
* 说 明:无
******************************************************/
btnode *CtreateBinaryTree(char *str)
{
btnode *bt;
char x;
static int i=0;
//scanf("%c", &x);
x = str[i++]; // 取出结点数据域的值
if(x=='#') // #表示无对应结点
bt = NULL;
else
{
bt = (btnode *)malloc(sizeof(btnode));
bt->data = x;
bt->lchild = CtreateBinaryTree(str);
bt->rchild = CtreateBinaryTree(str);
}
return bt;
}
2、二叉树结点个数统计及二叉树高度
2.1、二叉树中叶子结点个数
/**************************************************************
* 函数名称:unsigned int LeafNodeNum(btnode *bt)
* 参 数:bt----二叉树的根结点
* 函数功能:统计二叉树度为0的结点(叶子结点)个数
* 返 回 值:二叉树度为0的结点(叶子结点)个数
* 说 明:无左孩子和右孩子的结点为叶子结点
**************************************************************/
unsigned int LeafNodeNum(btnode *bt)
{
static unsigned int num=0;
if(bt != NULL)
{
if(bt->lchild==NULL && bt->rchild==NULL)
num++;
num = LeafNodeNum(bt->lchild);
num = LeafNodeNum(bt->rchild);
}
return num;
}
2.2、二叉树中一度结点个数
/**************************************************************
* 函数名称:unsigned int OneDegree(btnode *bt)
* 参 数:bt----二叉树的根结点
* 函数功能:统计二叉树度为1的结点个数
* 返 回 值:二叉树度为1的结点个数
* 说 明:只有一个左孩子或只有一个右孩子的结点为度为1的结点
**************************************************************/
unsigned int OneDegree(btnode *bt)
{
static unsigned int num=0;
if(bt != NULL)
{
if((bt->lchild==NULL && bt->rchild!=NULL) || (bt->lchild!=NULL && bt->rchild==NULL))
num++;
num = OneDegree(bt->lchild);
num = OneDegree(bt->rchild);
}
return num;
}
2.3、二叉树中二度结点个数
/**************************************************************
* 函数名称:unsigned int OneDegree(btnode *bt)
* 参 数:bt----二叉树的根结点
* 函数功能:统计二叉树度为2的结点个数
* 返 回 值:二叉树度为2的结点个数
* 说 明:既有左孩子又有右孩子的结点为度为2的结点
**************************************************************/
unsigned int TwoDegree(btnode *bt)
{
static unsigned int num=0;
if(bt != NULL)
{
if(bt->lchild!=NULL && bt->rchild!=NULL)
num++;
num = TwoDegree(bt->lchild);
num = TwoDegree(bt->rchild);
}
return num;
}
2.4、二叉树的高度
/**************************************************************
* 函数名称:unsigned int BinaryTreeHigh(btnode *bt)
* 参 数:bt----二叉树的根结点
* 函数功能:计算二叉树的高度
* 返 回 值:二叉树的高度值
* 说 明:二叉树的高度为二叉树中结点层次的最大值。
若一棵二叉树为空,则其高度为0;否则其高度等于左子树
和右子树的最大高度加1,即:
h(bt) = 0 (bt=NULL)
h(bt) = max{h(bt->lchild), h(bt->rchild)}+1 (其他)
**************************************************************/
unsigned int BinaryTreeHigh(btnode *bt)
{
unsigned int h, lh, rh;
if(bt == NULL)
h = 0;
else
{
lh = BinaryTreeHigh(bt->lchild);
rh = BinaryTreeHigh(bt->rchild);
h = lh>rh ? lh+1 : rh+1;
}
return h;
}
3、二叉树的遍历
3.1、二叉树的先序遍历
/**************************************************************
* 函数名称:void PreOrder(btnode *bt)
* 参 数:bt----二叉树的根结点
* 函数功能:二叉树的先序遍历
* 返 回 值:无
* 说 明:根结点---左孩子---右孩子
**************************************************************/
void PreOrder(btnode *bt)
{
if(bt != NULL)
{
printf("%-2c", bt->data);
PreOrder(bt->lchild);
PreOrder(bt->rchild);
}
}
3.2、二叉树的中序遍历
/**************************************************************
* 函数名称:void InOrder(btnode *bt)
* 参 数:bt----二叉树的根结点
* 函数功能:二叉树的中序遍历
* 返 回 值:无
* 说 明:左孩子---根结点---右孩子
**************************************************************/
void InOrder(btnode *bt)
{
if(bt != NULL)
{
InOrder(bt->lchild);
printf("%-2c", bt->data);
InOrder(bt->rchild);
}
}
3.3、二叉树的后序遍历
/**************************************************************
* 函数名称:void PostOrder(btnode *bt)
* 参 数:bt----二叉树的根结点
* 函数功能:二叉树的后序遍历
* 返 回 值:无
* 说 明:左孩子---右孩子---根结点
**************************************************************/
void PostOrder(btnode *bt)
{
if(bt != NULL)
{
PostOrder(bt->lchild);
PostOrder(bt->rchild);
printf("%-2c", bt->data);
}
}
3.4、二叉树的层次遍历
/**************************************************************
* 函数名称:void PreOrder(btnode *bt)
* 参 数:bt----二叉树的根结点
* 函数功能:二叉树的层次遍历
* 返 回 值:无
* 说 明:将层次遍历的各结点依次存入数组中,之后依次取出
**************************************************************/
void LeverlOrder(btnode *bt)
{
//btnodePoint queue[20], p; // 队列大小需根据结点个数来调整,p为临时结点指针
btnode *queue[20], *p;
int front=0, rear=0; // 设置队头与队尾
if(bt)
{
queue[rear++] = bt; // 先将二叉树的根结点入队
while(front!=rear) // 如果相等,则表示二叉树遍历完成
{
p = queue[front++]; // 顺序将层次遍历得到的结点出队
printf("%-2c", p->data);
// 如果左子树不为空,将左孩子结点存入队列中
if(p->lchild!=NULL)
queue[rear++] = p->lchild; // 先放左孩子
// 如果右子树不为空,将右孩子结点存入队列中
if(p->rchild!=NULL)
queue[rear++] = p->rchild; // 再放右孩子
}
}
}
3.5、二叉树的深度优先遍历
/**************************************************************
* 函数名称:void DeepOrder(btnode *bt)
* 参 数:bt----二叉树的根结点
* 函数功能:二叉树的深度优先遍历
* 返 回 值:无
* 说 明:将深度优先遍历的各结点依次存入数组中,之后依次取出
**************************************************************/
void DeepOrder(btnode *bt)
{
btnodePoint queue[10], p;
int front=0, rear=0;
if(bt)
{
queue[rear++] = bt;
while(front!=rear)
{
p = queue[front++];
printf("%-2c", p->data);
if(p->rchild!=NULL)
queue[rear++] = p->rchild;
if(p->lchild!=NULL)
queue[rear++] = p->lchild;
}
}
}
4、二叉排序树
4.1、二叉排序树的建立
/**************************************************************
* 函数名称:btnode *CreateSortBinaryTree(char str[])
* 参 数:str----待创建二叉树的先序遍历字符序列
* 函数功能:创建一个二叉排序树
* 返 回 值:创建的二叉排序树的根结点
* 说 明:先创建一个空树,之后将每个结点值插入二叉排序树中,
逐步建立二叉排序树
**************************************************************/
btnode *CreateSortBinaryTree(char str[])
{
btnode *SortBinaryTreeRoot=(btnode *)malloc(sizeof(btnode)); // 申请结点空间
static int i=0;
SortBinaryTreeRoot = NULL; // 创建一个空二叉树
while(str[i]!='\0')
{
if(str[i]!='#') // '#'表示按照先序遍历创建二叉树的空结点
// 依次将每个结点插入二叉排序树中,逐步建立完整的二叉排序树
SortBinaryTreeRoot = InsertNodeToSortTree(SortBinaryTreeRoot, str[i]);
i++;
}
return SortBinaryTreeRoot; // 返回建立的二叉排序树的根结点
}
4.2、判断二叉树是否为二叉排序树
/**************************************************************
* 函数名称:unsigned int IsSortBinaryTree(btnode *bt)
* 参 数:bt----二叉树的根结点
* 函数功能:判断给定的二叉树是否为二叉排序树
* 返 回 值:是,返回1;否,返回0
* 说 明:利用二叉排序树的性质及层次遍历的思想进行判断
**************************************************************/
unsigned int IsSortBinaryTree(btnode *bt)
{
int front=0, rear=0; // 设置队头与队尾
btnodePoint queue[20], p; // 队列大小需根据结点个数来调整,p为临时结点指针
if(bt!=NULL)
{
queue[rear++] = bt; // 先将二叉树的根结点入队
while(front!=rear) // 如果相等,则表示二叉树遍历完成
{
p = queue[front++]; // 顺序将层次遍历得到的结点出队
// 如果左子树不为空,且父结点的值大于等于左孩子结点的值,
// 那么符合二叉排序树规则,将左孩子结点存入队列中
if(p->lchild!=NULL && p->data >= p->lchild->data)
queue[rear++] = p->lchild; // 先放左孩子
// 如果右子树不为空,且父结点的值小于等于右孩子结点的值,
// 那么符合二叉排序树规则,将右孩子结点存入队列中
if(p->rchild!=NULL && p->data <= p->rchild->data)
queue[rear++] = p->rchild; // 再放右孩子
// 不符合二叉排序规则,则返回0
if((p->lchild!=NULL&&p->data < p->lchild->data) || (p->rchild!=NULL&&p->data > p->rchild->data))
return 0;
}
return 1; // 二叉树遍历完成,且都符合二叉排序树规则,则返回1
}
else // 二叉树为空
return 0;
}
4.3、二叉排序树的插入
/**************************************************************
* 函数名称:btnode *InsertNodeToSortTree(btnode *bt, char val)
* 参 数:bt----二叉排序树的根结点
val---待插入结点的数据域值
* 函数功能:二叉排序树的插入结点操作
* 返 回 值:插入结点后的二叉排序树的根结点
* 说 明:利用二叉排序树的性质(二分查找的思想)进行插入结点
**************************************************************/
btnode *InsertNodeToSortTree(btnode *bt, char val)
{
if(bt==NULL) // 二叉排序树为空,直接将新结点赋值给根结点
{
// 初始化新插入的结点
btnode *newnode=(btnode *)malloc(sizeof(btnode));
newnode->data = val;
newnode->lchild = NULL;
newnode->rchild = NULL;
bt = newnode;
}
else // 如果二叉排序树不为空
{
if(bt->data >= val) // 需要在父结点的左边插入新结点
bt->lchild = InsertNodeToSortTree(bt->lchild, val);
else // 需要在父结点的右边插入新结点
bt->rchild = InsertNodeToSortTree(bt->rchild, val);
}
return bt;
}