一、树的定义及相关术语
1.树的定义:
树是有n(n>=0)个有限数据元素的集合。当n=0时,称这棵树为空树。其中非空树,
(1)每个元素称为结点(node);
(2)有一个特定的结点被称为根结点或树根(root)。
(3)除根结点之外的其余数据元素被分为m(m≥0)个互不相交的集合T1,T2,……Tm-1,其中每一个集合Ti(1<=i<=m)本身也是一棵树,被称作原树的子树(subtree)。
2.相关术语:
(1)节点的度:一个节点含有的子树的个数称为该节点的度;
(2)叶节点或终端节点:度为0的节点称为叶节点;
(3)非终端节点或分支节点:度不为0的节点;
(4)双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
(5)孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
(6)兄弟节点:具有相同父节点的节点互称为兄弟节点;
(7)树的度:一棵树中,最大的节点的度称为树的度;
(8)节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
(9)树的高度或深度:树中节点的最大层次;
(10)堂兄弟节点:双亲在同一层的节点互为堂兄弟;
(11)节点的祖先:从根到该节点所经分支上的所有节点;
(12)子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
(13)森林:由m(m>=0)棵互不相交的树的集合称为森林;
二、二叉树的定义及其存储结构
1.二叉树的定义:
二叉树(Binary Tree)是个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个结点。
2.特殊形式的二叉树:
(1)满二叉树:
除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
(2)完全二叉树:
若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
3.二叉树的性质:
(1)一棵非空二叉树的第i层上最多有2^(i-1)个结点(i≥1)。
(2)一棵深度为k的二叉树中,最多具有2^k-1个结点。
(3)对于一棵非空的二叉树,如果叶子结点数为n0,度数为2的结点数为n2,则有: n0=n2+1。即二叉树的叶子节点数等于双分支节点数加1.
(4)具有n个结点的完全二叉树的深度为log2(n+1).
(5)有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:
若i为结点编号则 如果i>1,则其父结点的编号为i/2;
如果2*i<=N,则其左儿子(即左子树的根结点)的编号为2*i;若2*i>N,则无左儿子;
如果2*i+1<=N,则其右儿子的结点编号为2*i+1;若2*i+1>N,则无右儿子。
4.二叉树的存储结构
(1)顺序存储结构
所谓二叉树的顺序存储,就是用一组连续的存储单元存放二叉树中的结点。一般是按照二叉树结点从上至下、从左到右的顺序存储。这样结点在存储位置上的前驱后继关系并不一定就是它们在逻辑上的邻接关系,然而只有通过一些方法确定某结点在逻辑上的前驱结点和后继结点,这种存储才有意义。因此,依据二叉树的性质,完全二叉树和满二叉树采用顺序存储比较合适,树中结点的序号可以唯一地反映出结点之间的逻辑关系,这样既能够最大可能地节省存储空间,又可以利用数组元素的下标值确定结点在二叉树中的位置,以及结点之间的关系。
对于一般的二叉树,如果仍按从上至下和从左到右的顺序将树中的结点顺序存储在一维数组中,则数组元素下标之间的关系不能够反映二叉树中结点之间的逻辑关系,只有增添一些并不存在的空结点,使之成为一棵完全二叉树的形式,然后再用一维数组顺序存储。显然,这种存储会造成空间的大量浪费,不宜用顺序存储结构。
(2)链式存储结构
所谓二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示着元素的逻辑关系。通常有下面两种形式。
1)二叉链表存储
链表中每个结点由三个域组成,除了数据域外,还有两个指针域,分别用来给出该结点左孩子和右孩子所在的链结点的存储地址。结点的存储的结构为:
2)三叉链表存储
每个结点由四个域组成,具体结构为:
其中,data、lchild以及rchild三个域的意义同二叉链表结构;parent域为指向该结点双亲结点的指针。这种存储结构既便于查找孩子结点,又便于查找双亲结点;但是,相对于二叉链表存储结构而言,它增加了空间开销。
5.二叉树的遍历
1.先(根)序遍历的递归算法定义:
若二叉树非空,则依次执行如下操作:
⑴ 访问根结点;
⑵ 遍历左子树;
⑶ 遍历右子树。
2.中(根)序遍历的递归算法定义:
若二叉树非空,则依次执行如下操作:
⑴遍历左子树;
⑵访问根结点;
⑶遍历右子树。
3.后(根)序遍历得递归算法定义:
若二叉树非空,则依次执行如下操作:
⑴遍历左子树;
⑵遍历右子树;
⑶访问根结点。
//输出
void Visit(BiTree T){
if(T->data != '#'){
printf("%c ",T->data);
}
}
//先序遍历
void PreOrder(BiTree T){
if(T != NULL){
//访问根节点
Visit(T);
//访问左子结点
PreOrder(T->lchild);
//访问右子结点
PreOrder(T->rchild);
}
}
//中序遍历
void InOrder(BiTree T){
if(T != NULL){
//访问左子结点
InOrder(T->lchild);
//访问根节点
Visit(T);
//访问右子结点
InOrder(T->rchild);
}
}
//后序遍历
void PostOrder(BiTree T){
if(T != NULL){
//访问左子结点
PostOrder(T->lchild);
//访问右子结点
PostOrder(T->rchild);
//访问根节点
Visit(T);
}
}
6.二叉树代码实现:
#include<iostream.h>
using namespace std;
struct tree
{
int data;
tree *left,*right;
};
class Btree
{
static int n;
static int m;
public:
tree *root;
Btree()
{
root=NULL;
}
void create_Btree(int);
void Preorder(tree *); //先序遍历
void inorder(tree *); //中序遍历
void Postorder(tree *); //后序遍历
void display1() {Preorder(root); cout<<endl;}
void display2() {inorder(root);cout<<endl;}
void display3() {Postorder(root); cout<<endl;}
int count(tree *); //计算二叉树的个数
int findleaf(tree *); //求二叉树叶子的个数
int findnode(tree *); //求二叉树中度数为1的结点数量,这是当初考数据结构时候的最后一道题目
};
int Btree::n=0;
int Btree::m=0;
void Btree::create_Btree(int x)
{
tree *newnode=new tree;
newnode->data=x;
newnode->right=newnode->left=NULL;
if(root==NULL)
root=newnode;
else
{
tree *back;
tree *current=root;
while(current!=NULL)
{
back=current;
if(current->data>x)
current=current->left;
else
current=current->right;
}
if(back->data>x)
back->left=newnode;
else
back->right=newnode;
}
}
int Btree::count(tree *p)
{
if(p==NULL)
return 0;
else
return count(p->left)+count(p->right)+1; //这是运用了函数嵌套即递归的方法。
}
void Btree::Preorder(tree *temp) //这是先序遍历二叉树,采用了递归的方法。
{
if(temp!=NULL)
{
cout<<temp->data<<" ";
Preorder(temp->left);
Preorder(temp->right);
}
}
void Btree::inorder(tree *temp) //这是中序遍历二叉树,采用了递归的方法。
{
if(temp!=NULL)
{
inorder(temp->left);
cout<<temp->data<<" ";
inorder(temp->right);
}
}
void Btree::Postorder(tree *temp) //这是后序遍历二叉树,采用了递归的方法。
{
if(temp!=NULL)
{
Postorder(temp->left);
Postorder(temp->right);
cout<<temp->data<<" ";
}
}
int Btree::findleaf(tree *temp)
{
if(temp==NULL)return 0;
else
{
if(temp->left==NULL&&temp->right==NULL)return n+=1;
else
{
findleaf(temp->left);
findleaf(temp->right);
}
return n;
}
}
int Btree::findnode(tree *temp)
{
if(temp==NULL)return 0;
else
{
if(temp->left!=NULL&&temp->right!=NULL)
{
findnode(temp->left);
findnode(temp->right);
}
if(temp->left!=NULL&&temp->right==NULL)
{
m+=1;
findnode(temp->left);
}
if(temp->left==NULL&&temp->right!=NULL)
{
m+=1;
findnode(temp->right);
}
}
return m;
}
int main()
{
Btree A;
int array[]={7,4,2,3,15,35,6,45,55,20,1,14,56,57,58};
int k;
k=sizeof(array)/sizeof(array[0]);
cout<<"建立排序二叉树顺序: "<<endl;
for(int i=0;i<k;i++)
{
cout<<array[i]<<" ";
A.create_Btree(array[i]);
}
cout<<endl;
cout<<"二叉树节点个数: "<<A.count(A.root)<<endl;
cout<<"二叉树叶子个数:"<<A.findleaf(A.root)<<endl;
cout<<"二叉树中度数为1的结点的数量为:"<<A.findnode(A.root)<<endl;
cout<<endl<<"先序遍历序列: "<<endl;
A.display1();
cout<<endl<<"中序遍历序列: "<<endl;
A.display2();
cout<<endl<<"后序遍历序列: "<<endl;
A.display3();
}
7.
(1)图片来自网络
(2)代码来自http://www.cnblogs.com/elleniou/archive/2012/05/03/2480042.html