二叉树的性质:
性质1:若规定根结点的层数为0,则一棵非空二叉树的第i层上最多有2i(i≥0)个结点。
性质2:若规定只有根结点的二叉树的深度为0,则深度为k的二叉树的最大结点数是2k+1-1(k≥-1)个。
性质3:对于一棵非空的二叉树,如果叶结点个数为 n0,度为2的结点数为 n2,则有n0=n2+1。
性质4:具有n个结点的完全二叉树的深度k为大于或等于lb(n+1) -1的最小整数。
性质5:对于具有n个结点的完全二叉树,如果按照从上至下和从左至右的顺序对所有结点从0开始顺序编号,则对于序号为i(0≤i<n)的结点,有:
(1)如果i>0,则序号为i结点的双亲结点的序号为(i-1)/2(“/”表示整除);如果i=0,则序号为i结点为根结点,无双亲结点。
(2)如果2i+1<n,则序号为i结点的左孩子结点的序号为2i+1;如果2i+1≥n,则序号为i结点无左孩子。
(3)如果2i+2<n,则序号为i结点的右孩子结点的序号为2i+2;如果2i+2≥n,则序号为i结点无右孩子。
性质5告诉我们,如果把完全二叉树按照从上至下和从左至右的顺序对所有结点顺序编号,则可以用一维数组存储完全二叉树。此时,完全二叉树中任意结点的双亲结点下标、左孩子结点下标和右孩子结点下标都可以根据该结点的序号计算得出。
头文件
/*
二叉树节点结构体
*/
typedef struct Node{
DataType data;
struct Node *leftChild;
struct Node *rightChild;
}BiTreeNode;
/*
初始化
*/
void Initiate(BiTreeNode **root){
*root=(BiTreeNode*)malloc(sizeof(BiTreeNode));
(*root)->leftChild=NULL;
(*root)->rightChild=NULL;
}
/*
做插入节点
若当前节点curr非空,则左插入
*/
BiTreeNode *InsertLeftNode(BiTreeNode *curr,DataType x){
BiTreeNode *s,*t;
if(curr==NULL) return NULL;
t = curr->leftChild;//保存原来curr所指节点的左子树指针
s = (BiTreeNode*)malloc(sizeof(BiTreeNode));
s->data=x;
s->leftChild=t; //新节点的左子树为原来curr的左子树
s->rightChild=NULL;
curr->leftChild=s;
return curr->leftChild;//返回新插入节点的指针
}
/*
右插入
*/
BiTreeNode *InsertRightNode(BiTreeNode *curr,DataType x){
BiTreeNode *s,*t;
if(curr==NULL) return NULL;
t = curr->leftChild;//保存原来curr所指节点的左子树指针
s = (BiTreeNode*)malloc(sizeof(BiTreeNode));
s->data=x;
s->rightChild=t; //新节点的左子树为原来curr的右子树
s->leftChild=NULL;
curr->leftChild=s;
return curr->leftChild;//返回新插入节点的指针
}
/*
由于二叉树中每个结点允许有左孩子结点和右孩子结点,
所以在释放某个结点的存储空间前必须先释放该结点左孩子结点的存储空间和右孩子结点的存储空间,
因此,撤销二叉树操作必须是后序遍历的具体应用
*/
void Destroy(BiTreeNode **root){
if((*root)!=NULL&&(*root)->leftChild!=NULL){
Destroy(&(*root)->leftChild); //撤销左孩子
}
if((*root)!=NULL&&(*root)->rightChild!=NULL){
Destroy(&(*root)->rightChild); //撤销右孩子
}
}
/*
打印二叉树
逆时针旋转90°打印
n为缩进层,初始为0
*/
void PrintBiTree(BiTreeNode *root,int n){
int i;
if(root==NULL) return; //递归出口
PrintBiTree(root->rightChild,n+1); //打印右子树
//访问根节点
for(i=0;i<n-1;i++) printf(" ");
if(n>0){
printf("---");
printf("%c\n",root->data);
}
PrintBiTree(root->leftChild,n+1); //打印左子树
}
/*
查找数据元素
*/
BiTreeNode *Search(BiTreeNode *root,DataType x){
BiTreeNode *find=NULL; //初始化标记失败
if(root!=NULL){
if(root->data == x){
find = root; //查找成功
}else{
find=Search(root->leftChild,x);//左子树查找
if(find==NULL){
find = Search(root->rightChild,x);//右子树查找
}
}
}
return find;
}
void Visit(DataType item){
printf("%c ",item);
}
/*
左删除子树
*/
BiTreeNode *DeleteLeftTree(BiTreeNode *curr){
if(curr==NULL||curr->leftChild==NULL) return NULL;
Destroy(&curr->leftChild);
curr->leftChild=NULL;
return curr;
}
/*
右子树删除
*/
BiTreeNode *DeleteRightTree(BiTreeNode *curr){
if(curr==NULL||curr->rightChild==NULL) return NULL;
Destroy(&curr->rightChild);
curr->rightChild=NULL;
return curr;
}
/*
前序遍历或者后序遍历加上一个中序遍历可以确定唯一的二叉树
前序遍历
根节点->左子树->右子树
*/
void PreOrder(BiTreeNode*root,void visit(DataType item)){
if(root!=NULL){
visit(root->data);
PreOrder(root->leftChild,visit);
PreOrder(root->rightChild,visit);
}
}
/*
中序遍历
左子树->根节点->右子树
*/
void InOrder(BiTreeNode*root,void visit(DataType item)){
if(root!=NULL){
PreOrder(root->leftChild,visit);
visit(root->data);
PreOrder(root->rightChild,visit);
}
}
/*
后序遍历
左子树->右子树 ->根节点
*/
void PostOrder(BiTreeNode*root,void visit(DataType item)){
if(root!=NULL){
PreOrder(root->leftChild,visit);
PreOrder(root->rightChild,visit);
visit(root->data);
}
}
测试
#include <stdio.h>
#include <stdlib.h>
typedef char DataType;
#include"BiTree.h"
int main(){
BiTreeNode *root,*p,*find;
char x='a';
Initiate(&root);
p=InsertLeftNode(root,'A');
p=InsertLeftNode(p,'B');
p=InsertLeftNode(p,'D');
p=InsertRightNode(p,'G');
p=InsertLeftNode(root->leftChild,'C');
InsertLeftNode(p,'E');
InsertRightNode(p,'F');
PrintBiTree(root,0);
printf("前序遍历:");
PreOrder(root->leftChild,Visit);
printf("\n中序遍历:");
InOrder(root->leftChild,Visit);
printf("\n后序遍历:");
PostOrder(root->leftChild,Visit);
find=Search(root,x);
if(find!=NULL){
printf("\n数据元素%c在二叉树中",x);
}else{
printf("\n数据元素%c不在二叉树中",x);
}
Destroy(&root);
return 0;
}