//概述
//线性结构用于描述数据元素之间的线性关系,实际应用的数据元素之间的关系错综复杂,很难用线性关系描述,这就用到非线性结构,
//树它描述客观世界中事务之间的层次关系,一切具有层次关系的问题都可以用树来描述
//例如,家族的族谱,各种社会结构,(操作系统的文件系统中,用树表示目录结构)(编译程序中,用树表示源程序的语法结构)
#pragma mark --树的定义
//树,是有n(n>=0)个结点的有限集合,当n=0时称为空树,否则在任意非空树种
//1>必须有一个特定的成为根的结点
//2>剩下的结点被分成m>=0个互不相交集合T1,T2,...Tm,这些集合的每一个元素有事树,树T1,T2...Tm都成为根的子树
//特性.每个子树互不相交,每个结点只属于一棵树(或子树),只有一个双亲
#pragma mark --树的基本术语
//树包含若干个结点以及若干指向子树的分支
//度(degree) 结点拥有的子树成为结点的度 度为0的结点成为叶子(leaf)或者终端结点
//树的度是树中各个结点的最大数
//孩子(child) 双亲(parent) 兄弟(sibling) 祖父, 堂兄弟,子孙
//结点的层次(level)从根定义开始,跟为第一层,若某结点在C层,其子树的根在第C+1层
//深度(depth) 树中结点的最大层次
//有序树,即树的子树的位置不能互换,否则成为无序树
//森林(forest) 是有m(m>=0)颗互不相交的集合.对于树种每个结点而言,子树的集合就是森林
#pragma mark --树的基本操作
//1>初始化操作:INITATE(T).置T为空树
//2>求根函数 ROOT(T)或者ROOT(x).求树T的根或结点x所在树的根结点.若T是空或x不在任何一棵树上,函数的值为空
//3>求双亲函数 PARENT(T,x) 求树中结点x的双亲结点,若结点x是树T的根结点或结点x不在T中,则函数值为空
//4>求孩子结点的函数 Child(T,x,i);求树中结点x的第i个孩子结点,若结点x是树的叶子,或树无第i个孩子,或者结点x不在树上返回空
//5>求右兄弟函数 Right_Sibling(T,x),求树中结点x右边的兄弟,若x是树最右边的孩子,或者x不在t上返回空
//6建树函数 creatTree(x,F)生成一颗以结点x为根,以森林F为子树森林的树
//7,插入子树操作 Inser_Child(y,i,x)
//8.删除子树操作 Del_Child(x,i)
//9.遍历操作 traverse(T)//按照摸个顺序依次访问树中的各个结点,并使每个结点只被访问一次
//10清除树操作 Clear(T)将树置空
//由于树的形态很多,研究起来问题太复杂,所以研究讨论规范化的二叉树,二叉树的性质,存储结构和运算,然后给出二叉树和一般树的转换规则,这样就解决了树的存储结构和运算
//二叉树的概念
//二叉树是结点的有限集合,这个集合是空的或者只有一个根结点或者两两棵互不相交的左子树或者右子树组成
//二叉树的特点,每个结点最多有两个子树,度数<=2 ,二叉树子树有左二叉树和右二叉树之分,有次序的
#pragma mark 二叉树的5种基本形态
//1.空二叉树2.仅有根结点的二叉树3.右子树为空的二叉树,4左子树为空的二叉树5,左右均为非空的二叉树
//满二叉树,深度为K 且结点为2的k次方-1 的为满二叉树
//所有的结点从上往下,从左往右一次编号就得到了一个顺序表
//完全二叉树,是满二叉树的自己,且编号与满二叉树编号一致,只是数量不满
#pragma mark 二叉树的基本操作和树的基本操作基本一致
#pragma mark 二叉树的性质
//1>第i层 最多有 2的i次方 -1个结点(i>=1)
//2>深度为K的二叉树最多有2的k次方-1的结点(k>=1)
//3>对于任何一颗二叉树T,如果终端结点数为n0,度数为2的结点数为n2,则n0=n2+1
//4>具有n个结点的完全二叉树的深度为log2 n +1
//5>具有n个结点的完全二叉树 n>=i>=1
//1..i=1 结点是二叉树的跟,无双亲 i>1则双亲时结点i/2
//2..2*i>n 结点i无左孩子,否则其左孩子是2*i
//3...2*i+1>n 结点无右孩子,否则其右孩子是结点2*i+1
#pragma mark 二叉树的顺序存储结构 //将编号放入一维数组
//1> 完全二叉树 1,2,3,4,5,6,7,8,9,10,11,12 tr[i]的双亲 tr[(i+1)/2-1],左右孩子tr[2i],tr[2i+1];
//2 一般二叉树 1,2,3,4,5,0,0,0,0,6,7 空间浪费
#pragma mark 二叉树的链式存储
//二叉链表(左右孩子指针+data)
//三叉链表(左右孩子+双亲+data)
#pragma mark 二叉树的遍历,
//按照一定的规则和次序走遍二叉树的所有结点,使每个结点都被访问一次,而且只被访问一次,遍历的目的,在于得到二叉树中各个结点的一种线性队列,使非线性的二叉树线性化
//1>DLR(先根序遍历)1,2,4,8,9,5,10,11,3,6,12,7
//2>LDR(中根序遍历)8,4,9,2,10,5,11,1,12,6,3,7
//3>LRD(后根序遍历)8,9,4,10,11,5,2,12,6,7,3,1
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef char ElemType;
//通过第一个孩子和下一个兄弟来确定整个树
typedef struct TNode
{
ElemType data;
struct TNode *firstChild,*nextSibling;
}TNode,*Tree;
//初始化一个节点
Tree initTree(ElemType e){
Tree pT;
pT=(TNode*)malloc(sizeof(TNode));
pT->firstChild=NULL;
pT->nextSibling=NULL;
pT->data=e;
return pT;
}
//删除树
void deletTree(Tree*T){
if (*T==NULL) {
return;
}
deletTree(&(*T)->nextSibling);
deletTree(&(*T)->firstChild);
free(*T);
*T=NULL;
}
//遍历树并打印
void prinTree(Tree T){
if (NULL==T) {
return;
}else {
printf("%c ",T->data);
/*
//如果不习惯递归,可以这样写
Tree p = T->firstChild;
while(p != NULL)
{
printTree(p);
p = p->nextSibling;
}
*/
//注释掉的部分等价于如下两行:
prinTree(T->firstChild);
prinTree(T->nextSibling);
}
}
//求树的高度
int treeDepth (Tree T){
int hmax = 0;
int subTreeDepth = 0;
if(NULL == T)
return 0;
Tree p = T->firstChild;
while(p != NULL)
{
subTreeDepth = treeDepth(p);
p = p->nextSibling;
if(subTreeDepth > hmax)
hmax=subTreeDepth;
}
return hmax+1;
}
//全局变量记录找到的元素的地址
Tree result;
void locateElem(Tree T,ElemType e)
{
if(NULL == T)
return;
if(T->data == e)
result = T;
/*
Tree p = T->firstChild;
while(p != NULL)
{
locateElem(p,e);
p = p->nextSibling;
}
*/
locateElem(T->firstChild,e);
locateElem(T->nextSibling,e);
}
//返回子节点的指针
Tree findChild(Tree T,ElemType e)
{
result = NULL;
locateElem(T,e);
//如果没有找到或者该节点是叶子节点,返回空
if(NULL == result && NULL == result->firstChild)
return NULL;
else
return result->firstChild;
}
//返回兄弟节点的指针
Tree findSibling(Tree T,ElemType e)
{
result = NULL;
locateElem(T,e);
//如果没有找到或者该节点没有右兄弟,返回空
if(NULL == result && NULL == result->nextSibling)
return NULL;
else
return result->nextSibling;
}
//插入子树
bool insertTree(Tree T,Tree Tadd,ElemType e)
{
result = NULL;
locateElem(T,e);
if(result != NULL)
{
Tadd->nextSibling = result->firstChild;
result->firstChild = Tadd;
return true;
}
else
return false;
}
//删除子树
bool deleteSubTree(Tree T,ElemType e)
{
result = NULL;
locateElem(T,e);
//先判断result有什么节点
if(result->firstChild != NULL)
{
deletTree(&(result->firstChild));
return true;
}
else
return false;
}
int main(int argc, const char * argv[]) {
Tree t=initTree(‘a‘);
prinTree(t);
insertTree(t, t, ‘b‘);
prinTree(t);
return 0;
}
二叉树
#include <stdio.h>
#include <stdlib.h>
/*
二叉树操作(包含二叉树创建、销毁、计算深度、结点数目、先序遍历、中序遍历、后序遍历、二叉树线索化遍历)
时间:2015-1-2 22:21
说明:二叉树操作(包含二叉树创建、销毁、计算深度、结点数目、先序遍历、中序遍历、后序遍历、二叉树线索化遍历)
*/
/*声明一个枚举类型来表示指针域状态,Link=0表示指向左右孩子,Thread=1表示指向前驱或者后继*/
typedef enum{Link=0,Thread=1}PointerTag;
typedef struct BiTNode
{
char data;
struct BiTNode *lchild,*rchild;
PointerTag LTag,RTag;//定义标志位
}BiTNode,*BiTree;
/*
函数名称:CreateBinaryTree(BiTree *T)
说明:创建二叉树,以输入‘#‘作为空指针标志,按先序遍历的顺序输入二叉树中各个结点
*/
void CreateBinaryTree(BiTree *T)
{
char ch;
scanf("%c",&ch);
if(ch==‘#‘)
*T=NULL;
else
{
*T=(BiTree)malloc(sizeof(BiTNode));
if(!(*T))//容错判断,申请内存空间失败时返回
return;
(*T)->data=ch;
CreateBinaryTree(&((*T)->lchild));
if((*T)->lchild)//当存在左孩子时将标志位定义为Link
//if(((*T)->lchild)!=NULL)
(*T)->LTag=Link;
CreateBinaryTree(&((*T)->rchild));//当存在右孩子时将标志位定义为Link
if((*T)->rchild)
(*T)->RTag=Link;
}
}
/*先序遍历二叉树*/
void PreOrderTraverse(BiTree T)
{
if(!T)
return;
else
{
printf("%c",T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
/*中序遍历二叉树*/
void InOrderTraverse(BiTree T)
{
if(T==NULL)
return;
else
{
InOrderTraverse(T->lchild);
printf("%c",T->data);
InOrderTraverse(T->rchild);
}
}
/*后序遍历二叉树*/
void PostOrderTraverse(BiTree T)
{
if(!T)
return;
else
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c",T->data);
}
}
/*计算二叉树深度*/
int BinaryDepth(BiTree T)
{
int ldepth,rdepth;
if(!T)
return 0;
else
{
ldepth=BinaryDepth(T->lchild);
rdepth=BinaryDepth(T->rchild);
return (ldepth>rdepth?ldepth+1:rdepth+1);
}
}
/*计算结点数量*/
int NodeCount(BiTree T)
{
if(!T)
return 0;
else
return (NodeCount(T->lchild)+NodeCount(T->rchild)+1);
}
/*销毁一个二叉树*/
void DestoryBinaryTree(BiTree *T)
{
if(*T)
{
if((*T)->lchild)
DestoryBinaryTree(&((*T)->lchild));
if((*T)->rchild)
DestoryBinaryTree(&((*T)->rchild));
free(*T);
*T=NULL;
}
}
/*********线索化二叉树操作*********/
BiTree pre; /* 全局变量,始终指向刚刚访问过的结点 */
/*中序线索化*/
void InThreading(BiTree T)
{
if(T)
{
InThreading(T->lchild);
/*当没有左孩子时前驱线索*/
if(!T->lchild)
{
T->LTag=Thread;
T->lchild=pre;
}
/*当没有右孩子时后继线索*/
if(!pre->rchild)
{
pre->RTag=Thread;
pre->rchild=T;
}
pre=T;/* 保持pre指向前驱 */
InThreading(T->rchild);
}
}
/*中序遍历二叉树T,并将其线索化,head为头指针
在线索二叉树中头结点lchild左孩子指向二叉树的根结点,
rchild右孩子指向中序遍历时访问的最后一个结点;
二叉树的中序遍历序列中第一个结点的lchild指针和最后一个孩子的rchild指向头结点
*/
void InOrderThreading(BiTree *head,BiTree T)
{
*head=(BiTree)malloc(sizeof(BiTNode));
if(!*head)/*如果创建失败*/
return;
/*初始化头结点*/
(*head)->LTag=Link;
(*head)->RTag=Thread;
(*head)->rchild=*head;/*头指针回指*/
if(!T)/*对传入第2个参数进行合法性检测,并采取相应处理,当T为空时*/
{
(*head)->lchild=(*head);
}
else
{
(*head)->lchild=T;//当T为非空时头结点指向二叉树的根结点T
pre=(*head);
InThreading(T);
/*对最后一个结点线索化*/
pre->RTag=Thread;
pre->rchild=*head;
(*head)->rchild=pre;/*头结点指向中序遍历最后一个结点*/
}
}
/*中序遍历一棵二叉线索树T(T为头结点)*/
void InOrderTraverseThreadTree(BiTree T)
{
BiTree p;
p=T->lchild;
while(p!=T)/*当还未遍历迭代完整棵二叉树,空树或遍历结束时p=T*/
{
while(p->LTag==Link)
{
p=p->lchild;
}
printf("%c ",p->data);
while((p->rchild!=T)&&(p->RTag==Thread))
{
p=p->rchild;
printf("%c ",p->data);
}
p=p->rchild;
}
}
int main(int argc, char *argv[])
{
BiTree T,H;
printf("请创建一棵二叉树(如:‘ABDH##I##EJ###CF##G##‘)\n");
CreateBinaryTree(&T);
printf("\n二叉树的深度为:%d,结点数目为:%d\n",BinaryDepth(T),NodeCount(T));
printf("\n先序遍历的结果是:\n");
PreOrderTraverse(T);
printf("\n中序遍历的结果是:\n");
InOrderTraverse(T);
printf("\n后序遍历的结果是:\n");
PostOrderTraverse(T);
printf("\n对二叉树进行中序线索化\n");
InOrderThreading(&H,T);
printf("\n中序遍历线索二叉树的结果是:\n");
InOrderTraverseThreadTree(H);
printf("\n摧毁一棵二叉树\n");
DestoryBinaryTree(&T);
printf("\n二叉树的深度为:%d,结点数目为:%d\n",BinaryDepth(T),NodeCount(T));
return 0;
}
时间: 2024-11-08 02:17:22