1.基本概念
满二叉树:除最后一层外,每一层上的所有节点都有两个子结点,最后一层都是叶子结点。
完全二叉树:满二叉树最后一层,从右往左删除几个结点。堆是一个完全二叉树。
二叉排序树:左子树的值小于根结点,右子树的值大于根结点,且左右子树都是二叉排序树。
平衡二叉树:左右子树深度差的绝对值小于1。
2.二叉树的创建
二叉树结点的定义:
typedef struct Bitnode
{
char data;
struct Bitnode* lchild;
struct Bitnode* rchild;
}BiTNode,*BiTree;
按先序遍历创建二叉树,'#'表示结点为空
void CreateBiTree(BiTree& root)
{
char ch;
cin>>ch;
if(ch == '#') //若输入的是'#',表明二叉树为空,置root为NULL
root = NULL;
else
{
root = new BiTNode;
root->data = ch;
CreateBiTree(root->lchild);
CreateBiTree(root->rchild);
}
}
3.二叉树的遍历
二叉树的遍历分为先序、中序、后序,可以用递归实现。递归的本质是栈结构,也可以用栈来模拟递归实现。
先序遍历递归实现
void PreTraverse(BiTree root)
{
if(root==NULL)
return ;
cout<<root->data<<" ";
PreTraverse(root ->lchild);
PreTraverse(root ->rchild);
}
先序遍历非递归实现
void PreTraverse_NoRecursion(BiTree root)
{
if(root==NULL)
return ;
stack<BiTree> s;
BiTree p=root;
while(p!=NULL||!s.empty())
{
while(p!=NULL)
{
cout<<p->data<<" ";//先访问根结点
s.push(p);//访问左子树之前,记得先把根结点进栈保存
p=p->lchild;//然后才访问左子树
}
if(!s.empty())
{
p=s.top();//pop根结点
s.pop();
p=p->rchild;//访问右子树
}
}
}
中序遍历递归实现
void InTraverse(BiTree root)
{
if(root==NULL)
return ;
InTraverse(root->lchild);
cout<<root->data<<" ";
InTraverse(root->rchild);
}
中序遍历非递归实现
void InTraverse_NoRecursion(BiTree root)
{
if(root==NULL)
return ;
stack<BiTree> s;
BiTree p=root;
while(p!=NULL||!s.empty())
{
while(p!=NULL)
{
s.push(p);//访问左子树之前,记得先把根结点push进栈
p=p->lchild;
}
if(!s.empty())
{
p=s.top();//pop根结点(访问完左子树后)
cout<<p->data<<" ";
s.pop();
p=p->rchild;//访问右子树
}
}
}
后序遍历递归实现
void PostTraverse(BiTree root)
{
if(root==NULL)
return;
PostTraverse(root->lchild);
PostTraverse(root->rchild);
cout<<root->data<<" ";
}
4.分层遍历二叉树,从上到下,从左到右。跟图的广度优先遍历类似,利用队列实现。
void PrintTree(BiTree root)
{
if(NULL==root)
return ;
queue<BiTree> q;
BiTree font;
q.push(root);
while(!q.empty())
{
font=q.front();
q.pop();
cout<<font->data<<" ";
if(font->lchild)//交换顺序,从右往左打印
q.push(font->lchild);
if(font->rchild)
q.push(font->rchild);
}
}
5.二叉树中的结点个数
结点个数=左子树结点个数+右子树结点个数 + 1(根结点) 递归实现
int Get_node_num(BiTree root)
{
if(root==NULL)
return 0;
int left = Get_node_num (root->lchild);
int right = Get_node_num (root->rchild);
return left+right+1;
}
6.二叉树中叶子结点的个数
int Get_leaf_num(BiTree root)
{
if(root==NULL)
return 0;
if(root->lchild==NULL && root->rchild ==NULL)
return 1;
int left = Get_leaf_num(root->lchild);
int right = Get_leaf_num(root->rchild);
return left+right;
}
7.二叉树的深度
int get_depth(BiTree root)
{
if(root==NULL)
return 0;
int ldepth = get_depth(root->lchild);
int rdepth = get_depth(root->rchild);
return ldepth> rdepth ? ldepth+1 : rdepth+1;
}
8.二叉树中结点的最大距离。
分为两种情况:路径经过根结点的最大距离和没有经过时左右子树的最大距离,三者取其大者。
int Max_distance(BiTree root)
{
int distance;
if(root==NULL)
return 0;
else
{
distance = get_depth(root->lchild) + get_depth(root->rchild);
//经过根节点的最大距离等于左子树的深度+右子树的深度
int ldistance = Max_distance(root->lchild);//左子树的最大深度
int rdistance = Max_distance(root->rchild);//右子树的最大深度
distance = (ldistance>distance) ? ldistance : distance;//三者比较取最大值
distance = (rdistance>distance) ? rdistance : distance;
}
return distance;
}
9.根据二叉树的先序和中序遍历,重建二叉树。
前序遍历的第一个值为根节点,在根据中序遍历,可以得到序列左右子树,再递归调用,重建子树。
BiTree Rebuild(char* PreOrder,char* InOrder,int len)
{
if(PreOrder == NULL|| InOrder == NULL || len<=0)
return NULL;
BiTree root = new BiTNode;
root->data = *PreOrder;//前序遍历的第一个值作为根节点
root->lchild = root->rchild = NULL;
char* pStart = InOrder;
char* pEnd = InOrder;
int ChildLen = 0;
while(*PreOrder != *pEnd)//在中序遍历中寻找根节点,划分子树
{
ChildLen++;
if(ChildLen>len)//记录临时长度,防止溢出
break;
pEnd++;
}
int LeftLen = LeftLen = pEnd - pStart;//左子树长度
int RightLen = RightLen = len - LeftLen -1;//右子树长度
if(LeftLen>0)//重建左子树
{
root->lchild = Rebuild(PreOrder+1,InOrder,LeftLen);
}
if(RightLen>0)//重建右子树
{
root->rchild = Rebuild(PreOrder+LeftLen+1,InOrder+LeftLen+1,RightLen);
}
return root;
}
10.二叉树的镜像反转。
自顶向下,先交换根结点的左右孩子,再递归交换根结点左右子树。也可以自底向上,先交换跟结点的左右子树,在交换根结点的左右孩子结点。void MirrorTransform(BiTree &root)
{
if(NULL == root)
return;
BiTree temp;
temp = root->lchild;
root->lchild = root->rchild;
root->rchild = temp;
if(root->lchild)
MirrorTransform(root->lchild);
if(root->rchild)
MirrorTransform(root->rchild);
}