二叉树:一种常见的树形结构,每个节点中包含数据域和两个指针域,分别指向左右子树。
特点:
- 每个节点最多有两颗子树,且有左右之分。即其中不存在度大于2的节点
- 第i层至多有2^i-1个节点
- n个节点的树一共有2n个指针域,其中有2n+1个空指针域,因为有2n-1个指向(2n-1个节点有父节点)
除此之外还有一些特殊结构的二叉树:
满二叉树(树中不存在只有一个孩子的父节点,每一层的节点数都为2^i-1)、
完全二叉树(叶子结点只出现在底下两层,且不存在只有右孩子而无左孩子)
代码实现:
/*
tree.h文件,包含了二叉树节点的声明及方法的声明
*/
#ifndef _TREE_H
#define _TREE_H
typedef int BTDataType;
typedef struct BinaryTreeNode
{
BTDataType _data;
struct BinaryTreeNode* _left;
struct BinaryTreeNode* _right;
}BTNode;
//遍历
void BinaryTreePrevOrder(BTNode* root);
void BinaryTreeInOrder(BTNode* root);
void BinaryTreePostOrder(BTNode* root);
BTNode* BinaryTreeCreate(BTDataType* a, int* pi); //初始化二叉树
void BinaryTreeDestory(BTNode* root); //销毁二叉树
int BinaryTreeSize(BTNode* root); //统计二叉树节点数
int BinaryTreeLeafSize(BTNode* root); //统计二叉树叶子结点数
int BinaryTreeLevelKSize(BTNode* root, int k); //统计二叉树第k层节点数
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);//查找某一数据的所在节点
#endif
/*
文件包含了tree.h文件中声明的方法实现及测试
tree.cpp文件,由于在操作中是用了c++中STL库,
所以是.cpp文件,但在实现中除STL库之外均是用c语言实现
*/
#include<iostream>
#include<cstdio>
#include<cassert>
#include<cstdlib>
#include<queue>
#include"tree.h"
using namespace std;
BTNode* BinaryTreeCreate(BTDataType* a,int* pi)
{
static int s_n=0;
if(a[s_n]==*pi)
{
s_n++;
return NULL;
}
BTNode* New=(BTNode*)malloc(sizeof(BTNode));
New->_data=a[s_n];
s_n++;
New->_left=BinaryTreeCreate(a,pi);
New->_right=BinaryTreeCreate(a,pi);
return New;
}
void BinaryTreeDestory(BTNode* root)
{
if(root==NULL)
{
return ;
}
BinaryTreeDestory(root->_left);
BinaryTreeDestory(root->_right);
free(root);
}
int BinaryTreeSize(BTNode* root)
{
if(root==NULL)
{
return 0;
}
int lNum=BinaryTreeSize(root->_left);
int rNum=BinaryTreeSize(root->_right);
return lNum+rNum+1;
}
int BinaryTreeLeafSize(BTNode* root)
{
if(root==NULL)
{
return 0;
}
if(root->_left || root->_right)
{
return BinaryTreeLeafSize(root->_left)+BinaryTreeLeafSize(root->_right);
}
return 1;
}
int BinaryTreeLevelKSize(BTNode* root, int k)
{
assert(root!=NULL);
queue<BTNode*> qu;
qu.push(root);
int level=1;
int levNum=1;
while(!qu.empty())
{
if(k==level)
{
return levNum;
}
BTNode*tmp=qu.front();
qu.pop();
levNum--;
if(tmp->_left)
{
qu.push(tmp->_left);
}
if(tmp->_right)
{
qu.push(tmp->_right);
}
if(levNum==0)
{
level++;
levNum=qu.size();
}
}
return -1;
}
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
if(root==NULL)
{
return NULL;
}
if(root->_data==x)
{
return root;
}
BTNode*lTree=BinaryTreeFind(root->_left,x);
if(lTree)
{
return lTree;
}
BTNode*rTree=BinaryTreeFind(root->_right,x);
if(rTree)
{
return rTree;
}
else{
return NULL;
}
}
void BinaryTreePrevOrder(BTNode* root)
{
if(root==NULL)
{
return;
}
printf("%d",root->_data);
BinaryTreePrevOrder(root->_left);
BinaryTreePrevOrder(root->_right);
}
void BinaryTreeInOrder(BTNode* root)
{
if(root==NULL)
{
return;
}
BinaryTreePrevOrder(root->_left);
printf("%d",root->_data);
BinaryTreePrevOrder(root->_right);
}
void BinaryTreePostOrder(BTNode* root)
{
if(root==NULL)
{
return;
}
BinaryTreePrevOrder(root->_left);
BinaryTreePrevOrder(root->_right);
printf("%d",root->_data);
}
void BinaryTreePrint(BTNode*root)
{
assert(root);
queue<BTNode*> qu;
qu.push(root);
int level=1;
while(!qu.empty())
{
BTNode*tmp=qu.front();
printf("%d ",tmp->_data);
qu.pop();
level--;
if(tmp->_left)
{
qu.push(tmp->_left);
}
if(tmp->_right)
{
qu.push(tmp->_right);
}
if(level==0)
{
putchar('\n');
level=qu.size();
}
}
}
int main()
{
BTNode* root;
int arr[]={0,4,10,23,-1,-1,24,-1,-1,12,25,-1,-1,26,-1,-1,8,13,21,-1,-1,-1,-1};
int flag=-1;
root=BinaryTreeCreate(arr,&flag);
BinaryTreePrint(root);
BTNode* pTree= BinaryTreeFind(root,10);
printf("查找10的节点为:%p,数据为:%d\n",pTree,pTree->_data);
printf("root树的叶子节点个数为:%d\n",BinaryTreeLeafSize(root));
int n;
printf("输入你要查看的哪一层数的节点数");
scanf("%d",&n);
printf("%d层的节点个数为:%d\n",n,BinaryTreeLevelKSize(root,n));
BinaryTreeDestory(root);
return 0;
}
运行结果:
[test@bogon Tree]$ ./tree.out
0
4 8
10 12 13
23 24 25 26 21
查找10的节点为:0x1ea9c60,数据为:10
root树的叶子节点个数为:5
输入你要查看的哪一层数的节点数4
4层的节点个数为:5
其中大多数使用了递归方法,其中稍微不同的是统计第k层节点个数和打印的时候使用queue数据结构来辅助,这其实和实现二叉树的层序遍历相同。主要是借助了队列的先入先出的特点,每次将上层节点入队,每个节点出队时都将其左右孩子入队,统计记录每一层的节点数,当节点数为0时,说明该层节点已经全部出队,此时队列中保存的节点为下层的所有节点。