二叉树的性质及实现代码 !!!!

树的重点:二叉树
{
    1.二叉树的存储结构;
    2.二叉树的性质;
    3.二叉树的基本操作;
    4.二叉树的遍历;
    5.线索二叉树;
    6.二叉树的排序;
    7.哈夫曼树
1.二叉树的定义:
    二叉树是n个结点的有穷集合D与D上关系结合R构成的结构。当n=0时,称该二叉树为空二叉树;否则,它便是包含了一个根结点以及两棵不相交的、分别称为左子树与右子树的二叉树。
    二叉树的定义是一个递归定义,因为在定义中又用到了二叉树的概念。
2.二叉树的性质:
    a.具有n个结点的非空二叉树有且仅有n-1个结点。
    b.非空二叉树的第i层最多有2的i-1次方个结点。
    c.深度为h的非空二叉树最多有2的h次方-1个结点。
    d.非空二叉树中,若叶节点的数目为n0,度为2的结点数为n2,则有关系n0 = n2 + 1 成立。
    e.具有n个结点的完全二叉树的深度为h = log2n + 1;
    f.二叉树中编号为i的结点具有以下性质:
        (1)若编号i>1,则编号为i的结点的双亲结点的编号为i/2;当n = 1时,编号为i的结点为二叉树的根结点,没有双亲结点。
        (2)若2i<=n,则编号为i的左孩子结点的编号为2i;若2i > n,则编号为i的结点无左孩子。
        (3)若2i + 1 <= n,则编号为i的结点的右孩子结点的编号为2i + 1;若2i + 1 > n,则编号为i的结点无右孩子;
  二叉树的存储结构:
    1.二叉树的顺序存储结构。
    顺序存储结构,是把二叉树进行编号,从左到右依次进行,然后把没有结点的右结点进行假设,称为“虚结点”。然后把元素存入到数组中。这种存储结构仅对于完全二叉树来说比较方便,但是对于非完全二叉树,尤其是右子树时,很难来说明它的结构形式。并且进行插入和删除操作时,容易造成错误。故不可以这样做。
    2.二叉树的链式存储结构。
链式存储结构来说,又可以分成两种存储的形势
   a.二叉链表结构
      即结点中只存在三个结点,一个数据域,两个指针域。并且,指针域中的指针分别指向了左右两个孩子。如果孩子不存在,则该指针域中存放空。
      b.三叉链表结构
      即在二叉链表的基础上又添加了一个指针域,来指向parents结点。这个属性,将在后续的线索二叉树中很有用。
    总结:
        二叉链表结构灵活,方便,结点的最大数目只受系统最大可用存储空间的限制。一般情况下,二叉链表结构不仅节省空间,而且操作方便。
    3.二叉链表的代码定义:
    #include "stdafx.h"
#include <iostream>
#define MaxSize 100
using namespace std;

typedef struct Node
{
char chElem;
struct Node* lchild,*rchild;
}BTNode,*BTREE;

// 二叉树的建立
void BuildBT(BTREE& T)
{
char chA = ' ';
cin >> chA;
if (chA == ' ')
{
T = NULL; // 建立一个空树;
}
else
{
T = (BTREE)malloc(sizeof(BTNode));
T->chElem = chA;
BuildBT(T->lchild);
BuildBT(T->rchild); // 递归的创建左右子树;
}
}



// 二叉树的复制;
BTREE CopyBT(BTREE& T)
{
BTREE TNEW;
if (T == NULL)
{
return NULL;
}
else
{
TNEW = (BTREE)malloc(sizeof(BTNode));
TNEW->chElem = T->chElem;
TNEW->lchild = CopyBT(T->lchild); // 递归复制左子树;
TNEW->rchild = CopyBT(T->rchild);// 递归复制右子树;
}
return TNEW;
}

// 二叉树的销毁主要方法为:
// 将所有的结点从二叉树中删除,并且释放各结点所占用的空间,然后将
// 跟结点的指针值为NULL,使之成为一棵空的二叉树。
// 当然销毁之前需要遍历二叉树,其中最好的遍历方法就是进行后序遍历。
void DestroyBT(BTREE& T)
{
// T 为二叉树根结点所在的位置
if (T)
{
DestroyBT(T->lchild);
DestroyBT(T->rchild);
free(T);
}
T = NULL;
// 删除并释放二叉树中所有的结点,使之成为一棵空的二叉树;
}



// 递归的使用。求二叉树的叶子的个数。
int Countleaf(BTREE T)
{
if (T == NULL)
{
cout << "没有叶子结点!" << endl;
return 0;
}
if (T->lchild == NULL && T->rchild == NULL)
{
return 1;
}
return Countleaf(T->lchild)+Countleaf(T->rchild);
}

// 求二叉树的深度。
// 算法等于其左子树与右子树最大深度值加上1;
int BTDepth(BTREE T)
{
int leftDepth = 0;
int rightDepth = 0;
if (T == NULL)
{
return 0;
}
else
{
leftDepth = BTDepth(T->lchild);
rightDepth = BTDepth(T->rchild);
if (leftDepth > rightDepth)
{
return rightDepth + 1;
}
else
{
return leftDepth + 1;
}
}
}

// 访问结点,直接输出结点的元素值。
void visit(BTREE T)
{
cout << T->chElem<< " ";
cout << endl;
}

// 二叉树的前序遍历;
void PreOrder(BTREE T)
{
if (T != NULL)
{
visit(T); // 访问T所指的结点;
}
}

// 中序遍历
void MidOrder(BTREE T)
{
if (T != NULL)
{
MidOrder(T->lchild);           // 遍历T所指结点的左子树;
visit(T); // 访问结点中的元素
MidOrder(T->rchild); // 遍历T所指结点的右子树;
}
}

// 后序遍历
void PostOrder(BTREE T)
{
if (T != NULL)
{
PostOrder(T->lchild);
PostOrder(T->rchild);
visit(T);
}
}

// 测试二叉树是否为等价
int IsEqualBT(BTREE& T1,BTREE& T2)
{
if (T1 == NULL && T2 == NULL)
{
cout << "比较的两棵树为空树,因此相等!" << endl;
return 1;
}
if (T1 != NULL && T2 != NULL && T1->chElem == T2->chElem && IsEqualBT(T1->lchild,T2->lchild)
&& IsEqualBT(T1->rchild,T2->rchild))
{
return 1;
}
return 0;
}

// 求二叉树的深度问题
int DepthBT(BTREE& T)
{
BTREE Stack1[MaxSize],p = T;
int Stack2[MaxSize] = {0};
int iCurdepth = 0,iMaxdepth = 0,iTop = -1;
if (T != NULL)
{
iCurdepth = 1;
do 
{
while(p)
{
Stack1[++ iTop] = p; // 当前p所指的结点进栈;
Stack2[iTop] = iCurdepth;   // 当前深度值进栈;
p = p->lchild;   // 将p移动到左孩子结点处;
iCurdepth ++;   // 层次数加1;
}
p = Stack1[iTop];
iCurdepth = Stack2[iTop --];   // 退栈操作;
if (p->lchild == NULL && p->rchild == NULL) // 若p所指的结点为叶结点:
{
if (iCurdepth > iMaxdepth)
{
iMaxdepth = iCurdepth;
}
}
p = p->rchild;
iCurdepth ++;
} while (!(p == NULL && iTop == -1));
}
return iMaxdepth;
}



// 求二叉树结点所在的层次;
// 作个假设:二叉树中存在这样的结点,并且不多于一个。
// 求二叉树中所在层次的方法:利用后续遍历。
//  遍历中,判段是否满足条件,若是满足条件的结点,则此时堆栈中保留
// 的元素个数加1,即为该结点所在的层次数;
int LayerBT(BTREE& T,char chItem)
{
BTREE Stack1[MaxSize],p = T;
int Stack2[MaxSize],iFlag,iTop = -1;
do 
{
while(p)
{
Stack1[++ iTop] = p; // 当前p所指结点进栈;
Stack2[iTop] = 0;// 标志0进栈;
p = p->lchild;
}
p = Stack1[iTop];
iFlag = Stack2[iTop --];   // 退栈;
if (iFlag == 0)
{
Stack1[++ iTop] = p; // 当前p所指结点的地址再次进栈;
Stack2[iTop] = 1; // 标志1进栈;
p = p->rchild;
}
else
{
if (p->chElem == chItem)
{
return iTop + 2; // 求的结点所在的层数;
}
p = NULL;
}
} while (!(p == NULL && iTop == -1));
}

// 二叉树的删除操作;
// 这里的删除操作主要是:删除数据信息为item的那个结点和以该结点为
// 根结点的子树;
// 分两步走:1、遍历找到数据信息为item的元素;
// 2.先将该结点的双亲结点的相应指针域置为null,然后释放以该结点为根结点
// 的子树的所有结点的存储空间;
BTREE DeleteBT(BTREE& T,char chItem)
{
BTREE Stack[MaxSize],q,p = T;
int iTop = -1;
// 如果根结点满足情况,则删除的是整棵二叉树;
if (T->chElem == chItem)  
{
DestroyBT(T);
return NULL;
}
else
{
do 
{
while(p)
{
if (p->chElem == chItem)
{
if (q->lchild == p)
{
q->lchild = NULL; // p的双亲结点的做指针域置空;
}
else
{
q->rchild = NULL;// 否则的话,右指针域置空;
}
DestroyBT(p); // 删除以p为根结点的子树;
return T;
}
Stack[++ iTop] = p; // 当前p所指结点的地址进栈;
q = p; // 保存当前p所指的地址;
p = p->lchild;
}
p = Stack[iTop --];  // 退栈;
q = p; // 保存当前p所指结点的地址;
p = p->rchild;        // 将p移动到其右孩子结点;
} while (!(p == NULL && iTop == -1));
}
}

// 交换所有结点左右子树的位置
// 该操作采用按层次遍历的方法比较合适。遍历中访问一个结点时,就讲
// 该结点的左右子树的位置进行交换。
void ExchangeBT(BTREE& T)
{
BTREE Queue[MaxSize],temp,p = T;
int iFront,iRear;
if (T)
{
Queue[0] = T;
iFront = -1;
iRear = 0;
while(iFront < iRear)
p = Queue[++ iFront]; // 推出队头的元素送到p中
temp = p->lchild;
p->lchild = p->rchild;
p->rchild = temp; // 交换左右子树的位置;
if (p->lchild != NULL)
{
Queue[++ iRear] = p->lchild;   // p 所指结点的左孩子的地址进队;
}
if (p->rchild)
{
Queue[++ iRear] = p->rchild;
}
}
}



int main(int argc,char* argv[])
{
BTREE head;
cout << "树的结点元素为单个字符,请输入一个字符: " <<  endl;
BuildBT(head);
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值