特点:每个结点最多有两颗子树,所以二叉树中不存在度大于2的结点。二叉树的左右子树不能任意颠倒(有序),如果某结点只有一颗子树,一定要指明它是左子树还是右子树。
二叉树的分类
1 斜树
所有结点都只有左子树的二叉树称为左斜树,所有结点都只有右子树的二叉树称为右斜树;左斜树和右斜树统称为斜树。特点:每一层只有一个结点,斜树的结点个数与其深度相同。
2 满二叉树
在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,那么这棵二叉树称为满二叉树。特点:叶子只能出现在最下一层;只有度为0和度为2的结点。
3 完全二叉树
对一颗具有n个结点的二叉树按层序编号,如果编号i的结点与同样深度的满二叉树中编号为i的结点在二叉树中的位置完全相同,则这棵树称为完全二叉树。特点:深度为k的完全二叉树在k-1层是满二叉树;叶子结点只能出现在最下两层,且最下层的叶子结点都集中在左侧连续的位置;如果有度为1的结点,只可能有一个,且该结点只有做左孩子。
二叉树的基本性质
1:在一棵二叉树中,如果叶子结点的个数为n0,度为2的结点个数为n2,则n0=n2+1。
2:二叉树的第i层上最多有2^(i-1)个结点。
3:在一棵深度为k的二叉树中,最多有2^k-1个结点。
4:具有n个结点的完全二叉树的深度为[log2n]+1
(向下取整)。
5:对一颗棵具有n个结的完全二叉树从1开始按层序编号,则对于编号为i的结点,有如下关系成立
①如果i>1,则结点i的双亲编号为i/2向下取整,否则结点i是根结点,无双亲。
②如果2i<=n,则结点i的左孩子的编号为2i,否则结点i无左孩子。
③如果2i+1<=n,则结点i的右孩子的编号为2i+1,否则结点i无右孩子。
二叉树的存储结构
顺序存储结构
用一维数组存储二叉树的结点,用结点的存储位置(下标)表示结点之间的逻辑关系。
对于一般的二叉树,可以按照完全二叉树进行层序编号,然后再用一维数组顺序存储。
具体步骤:
1:将二叉树按完全二叉树编号。根结点的编号为1,若某结点i有左孩子,则其左孩子的编号为2i;若某结点i有右孩子,则其右孩子的编号为2i+1。
2:将二叉树的结点按照编号顺序存储到一维数组中。
#include<iostream>
using nameapace std;
const int size=100;
template<class Type>
class LinearBinTree
{
private:
Type Data[size];
int last;
public:
LinearBinTree():last(0){
for(int i=0;i<size;i++)
Data[i]=Type(-111);
}
~LinearBinTree(){}
bool AddNode(Type);
bool IsEmpty(){return last==0;}
bool IsFull(){return size-1<=last;}
void Print();
void PreOrderTraversal();
};
template<class Type>
bool LinearBinTree<Type>::AddNode(Type x)
{
if(IsFull())
return false;
if(IsEmpty())
{
Data[1]=x;
last=1;
return true;
}
int i=1;
while(i)
{
if(Data[i]==Type(-111))
{
Data[i]=x;
last=(i>last?i:last);
return true;
}
if(Data[i]>x)
i=2*i;
else
i=2*i+1;
return false;
}
template<class Type>
void LinearBinTree<Type>::Print()
{
for(int i=1;i<=last;i++)
{
if(Data[i]==Type(-111))
continue;
cout<<Data[i]<<" ";
}
cout<<endl;
}
二叉链表的存储结构及遍历
令二叉树的每个结点对应一个链表结点,链表结点除了存放二叉树结点的数据信息外,还要存放指示左右孩子的指针。
二叉链表结点结构
template<typename T>
struct BiNode{
T data;
BiNode *lchild,rchild;
};
#include<iostream>
#include<string>
using namespace std;
struct BiNode{
char data;
BiNode *l,*r;
};
class BiTree{
public:
BiTree(){root=great();}
~BiTree(){release(root);}
void preorder(){preorder(root);}
void inorder(){inorder(root);}
void postorder(){postorder(root);}
private:
BiNode *great();
void release(BiNode *bt);
void preorder(BiNode *bt);
void inorder(BiNode *bt);
void postorder(BiNode *bt);
BiNode *root;
};
BiNode *BiTree::great()//构建
{
BiNode *bt;
char a;
cin>>a;
if(a=='#') bt=NULL;
else{
bt=new BiNode;
bt->data=a;
bt->l=great();
bt->r=great();
}
return bt;
}
void BiTree::preorder(BiNode *bt)//前序遍历
{
if(bt==NULL) return;
else{
cout<<bt->data;
preorder(bt->l);
preorder(bt->r);
}
}
void BiTree::inorder(BiNode *bt)//中序遍历
{
if(bt==NULL) return;
else{
inorder(bt->l);
cout<<bt->data;
inorder(bt->r);
}
}
void BiTree::postorder(BiNode *bt)//后序遍历
{
if(bt==NULL) return;
else{
postorder(bt->l);
postorder(bt->r);
cout<<bt->data;
}
}
void BiTree::release(BiNode *bt)
{
if (bt==NULL) return;
else{
release(bt->l);
release(bt->r);
delete bt;
}
}
int main()
{
string s;
while(1){
BiTree t;
cin>>s;
t.preorder();
cout<<endl;
t.inorder();
cout<<endl;
t.postorder();
cout<<endl;
if(s=="Y"){
continue;
}
else if(s=="N")
break;
}
return 0;
}
二叉链表的推广:三叉链表
为了能够高效地解决孩子寻找双亲结点的问题,由二叉链表的基础之上,结点新添加一个parent域,用于存储孩子的父亲。
结构体如下:
struct TriNode
{
T data;
TriNode *lchild,*rchild,*parent;
}
这种存储结构既便于寻找孩子结点,又便于查找双亲结点。