实例介绍
【实例截图】
【核心代码】
#include<stdio.h>
#include<stdlib.h>
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
#define OVERFLOW -2
#define INFEASIBLE -1
#define ERROR 0
#define FALSE 0
#define TRUE 1
#define OK 1
typedef int Status;
typedef char TElemType;
//---------二叉树的二叉线索存储表示-------
typedef enum {Link, Thread}PointerTag; //Link==0:指针,Thread==1:线索
typedef struct BiThrNode{
TElemType data;
struct BiThrNode *lchild, *rchild; //左右孩子指针
PointerTag LTag,RTag; //左右标志
}BiThrNode, *BiThrTree;
typedef BiThrTree SElemType;
//------Stack的储存结构----------
typedef struct Stack
{
SElemType *base; //存储空间的基址,在栈构造之前和销毁之后,base的值为NULL
SElemType *top; //栈顶指针
int stacksize; //当前已分配的存储空间,以元素为单位
} SqStack; //顺序栈类型
//-------Stack的函数声明---------
Status InitStack(SqStack &S) //构造一个空栈
{
S.base = (SElemType*)malloc(STACK_INIT_SIZE*sizeof(SElemType)); //分配存储空间
if(!S.base)
{ printf("分配存储失败!\n");
exit(OVERFLOW);
}
S.top = S.base; //S为空栈,S.top=S.base等于0
S.stacksize = STACK_INIT_SIZE; //栈的空间初始容量值
return OK;
}
Status GetTop(SqStack S,SElemType &e) //若栈不空,用 e返回栈顶元素 (注意这里的应用,后面会用到)
{
if(S.top==S.base)
return ERROR;
e = *(S.top-1);
return OK;
}
Status Push(SqStack &S,SElemType e) //入栈
{
if(S.top-S.base >= S.stacksize) //栈满,追加存储空间
{
S.base = (SElemType*)realloc(S.base,
(S.stacksize STACKINCREMENT)*sizeof(SElemType)); //通过realloc动态扩容
if(!S.base) //判断扩容是否成功
{
printf("存储空间不足,且扩展失败!");
exit(OVERFLOW);
}
S.top = S.base S.stacksize; //更新栈顶指针
S.stacksize = STACKINCREMENT; //更新栈的存储空间大小
}
*S.top = e; //将元素入栈,使S.top加1
return OK;
}
Status Pop(SqStack &S, SElemType &e) //栈顶元素出栈,赋给元素e
{
if(S.top==S.base) //栈空
return ERROR;
e = * --S.top; //栈顶元素出栈,并将S.top减1
return OK;
}//Pop
Status StackEmpty(SqStack S) //判断栈是否为空
{
if(S.top == S.base)
return TRUE;
else
return FALSE;
}
BiThrTree pre; //全局变量始终指向刚刚访问过的节点
//---------二叉树函数实现----------
Status CreateBiThrTree(BiThrTree &T) //先序构造二叉树,字符表示树,空格字符表示空树
{ char ch;
ch=getchar();
if(ch=='#')T=NULL;
else{
if(!(T=(BiThrNode *)malloc(sizeof(BiThrNode))))
{
printf("存储分配失败!");
exit(OVERFLOW);
}
T->data = ch; //生成根节点
CreateBiThrTree(T->lchild); //构造左子树
CreateBiThrTree(T->rchild); //构造右子树
}
return OK;
}//CreatBiTree
Status visit(TElemType e) //访问节点
{
printf("%c",e);
return OK;
}
Status PreOrderTraverse(BiThrTree T,Status(*visit)(TElemType )) //先序遍历
{
if(T){
if(visit(T->data)) //访问根节点
if(PreOrderTraverse(T->lchild,visit)) //先序遍历左子树
if(PreOrderTraverse(T->rchild,visit)) //先序遍历右子树
return OK;
return ERROR;
}
else return OK;
}//PreOrderTraverse
Status InOrderTraverse(BiThrTree T, Status( *visit)(TElemType )) // 中序遍历
{
if (T) {
InOrderTraverse(T->lchild, visit); // 中序遍历左子树
(*visit)(T->data); // 访问根结点
InOrderTraverse(T->rchild, visit); // 中序遍历右子树
}
return OK;
}
Status PostOrderTraverse (BiThrTree T, Status( *visit)(TElemType )) // 后序遍历二叉树
{
if (T) {
PostOrderTraverse(T->lchild, visit); //后序遍历左子树
PostOrderTraverse(T->rchild, visit);//后序遍历右子树
(*visit)(T->data); // 访问根结点
}
return OK;
}
Status PreOrderTraverse_nr(BiThrTree T,Status(*visit)(TElemType e)) //非递归前序遍历
{
BiThrTree p;
p = T;
SqStack S; // 声明栈S
InitStack(S);
while (!StackEmpty(S)|| p) //边遍历边打印,并存入栈中,以后需要借助这些根节点进入右子树
{
if(p)
{
if(!visit(p->data))return ERROR;
Push(S,p);
p = p->lchild;
}
else //当p为空时,说明根和左子树都遍历完了,该进入右子树了
{
Pop(S,p); //s.pop();
p = p->rchild;
}//else
}//while
return OK;
}
Status InOrderTraverse_nr(BiThrTree T,Status(*visit)(TElemType e)) //非递归中序遍历(nr,nonrecursively,非递归地)
{
BiThrTree p;
p = T;
SqStack S; // 声明栈S
InitStack(S);
while (!StackEmpty(S)|| p) //边遍历边打印,并存入栈中,以后需要借助这些根节点进入右子树
{
if(p)
{
Push(S,p);
p = p->lchild;
}
else //当p为空时,说明根和左子树都遍历完了,该进入右子树了
{
Pop(S,p);
if(!visit(p->data))return ERROR;
p = p->rchild;
}//else
}//while
return OK;
}//InOrderTrayerse_nr
Status PostOrderTraverse_nr(BiThrTree T,Status(*visit)(TElemType e))//非递归后序遍历
{
SqStack S; // 声明栈S
InitStack(S);
BiThrTree pCur, pLastVisit; //pCur:当前访问节点,pLastVisit:上次访问节点
pCur = T;
pLastVisit = NULL;
while (pCur) //先把pCur移动到左子树最下边
{
Push(S,pCur);
pCur = pCur->lchild;
}
while (!StackEmpty(S))
{
//走到这里,pCur都是空,并已经遍历到左子树底端(看成扩充二叉树,则空,亦是某棵树的左孩子)
Pop(S,pCur);
if (pCur->rchild == NULL || pCur->rchild == pLastVisit) //一个根节点被访问的前提是:无右子树或右子树已被访问过
{
if(!visit(pCur->data))return ERROR; //访问结点
pLastVisit = pCur; //修改最近被访问的节点
}
/*这里的else语句可换成带条件的else if:
else if (pCur->lchild == pLastVisit)//若左子树刚被访问过,则需先进入右子树(根节点需再次入栈)
因为:上面的条件没通过就一定是下面的条件满足。仔细想想!
*/
else
{
Push(S,pCur); //根节点再次入栈
pCur = pCur->rchild; //进入右子树,且可肯定右子树一定不为空
while (pCur)
{
Push(S,pCur);
pCur = pCur->lchild;
}
}
}
return OK;
}
Status CountLeaf(BiThrTree T) //返回指针T所指二叉树中所有叶子结点个数
{
int m,n;
if (!T ) return 0;
if (!T->lchild && !T->rchild) return 1;
else{
m = CountLeaf( T->lchild);
n = CountLeaf( T->rchild);
return (m n);
} //else
} // CountLeaf
Status Depth(BiThrTree T) // 返回二叉树的深度
{
int depthLeft=0,depthRight=0,depthval=0;
if ( !T )
depthval = 0;
else
{
depthLeft = Depth( T->lchild );
depthRight= Depth( T->rchild );
depthval = 1 (depthLeft > depthRight ?
depthLeft : depthRight);
}
return depthval;
}
Status InThreading(BiThrTree p) //中序线索化
{
if(p)
{
InThreading(p->lchild); //左子树线索化
if(!p->lchild) //若没有左孩子
{
p->LTag = Thread; //当前结点前驱线索
p->lchild = pre; //左孩子指针指向前驱
}
else
p->LTag = Link;
if(!pre->rchild) //前驱没有右孩子
{pre->RTag = Thread; //后继线索
pre->rchild = p; //前驱的右孩子指针指向后继(当前节点p)
}else
p->RTag = Link;
pre = p; //保持pre指向p的前驱
InThreading(p->rchild); //右子树线索化
}
return OK;
}// InThreading
Status InOrderThreading(BiThrTree &Thrt, BiThrTree T) //中序遍历二叉树T,并将其中序线索化,Thrt指向头结点。
{
if(!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))
{
printf("分配内存失败!\n");
exit(OVERFLOW);
}
Thrt->LTag = Link;
Thrt->RTag = Thread; //建立头结点
Thrt->rchild = Thrt; //左指针回指
if(!T)
Thrt->lchild = Thrt; //若二叉树为空,则左指针回指
else
{
Thrt->lchild = T;
pre = Thrt;
InThreading(T); //中序遍历进行中序线索化
pre->rchild = Thrt;
pre->RTag = Thread; //最后一个结点线索化
Thrt->rchild = pre;
}
return OK;
}//InOrderThreading
Status InOrderTraverse_Thr(BiThrTree T, Status (*Visit)(TElemType)) //中序遍历二叉线索书T的非递归算法
{ //T指向头结点,头结点的左链lchild指向根节点
BiThrTree p2;
p2=T->lchild; //p指向根节点
while(p2!=T) //空树或遍历结束时,p==T
{
while(p2->LTag==Link)
p2=p2->lchild; //直到最左
if(!visit(p2->data)) //访问其左子树为空的结点
return ERROR;
while(p2->RTag==Thread && p2->rchild != T)//如果该结点的后继不是头结点,访问它的后继结点
{
p2 = p2->rchild; //p2->RTag线索, p2->rchild指向其后继
visit(p2->data); //访问后继结点
}
p2 = p2->rchild; //更新当前结点
}
return OK;
}//InOrderTraverse_Thr
void display()//登陆界面
{ int n,m=1;
BiThrTree T;
BiThrTree Thrt;
printf(" ◆◇◆◇◆◇◆◇◆◇◆◇◆◇◆◇\n");
printf(" ◆ 欢迎使用 B126二叉树 ◆\n");
printf(" ◆◇◆◇◆◇◆◇◆◇◆◇◆◇◆◇\n\n");
printf(" 测试二叉树:AB#CD###EFGH##K####\n");
printf("请按先序次序输入树(#代表空树):\n");
CreateBiThrTree(T);
do{
printf("★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆\n");
printf("☆请输入你想操作的序号: ★\n");
printf("★ 0)退出 ☆\n");
printf("☆ 1)先序遍历 ★\n");
printf("★ 2)先序遍历(非递归) ☆\n");
printf("☆ 3)中序遍历 ★\n");
printf("★ 4)中序遍历(非递归) ☆\n");
printf("☆ 5)后序遍历 ★\n");
printf("★ 6)后序遍历(非递归) ☆\n");
printf("☆ 7)统计叶子结点个数 ★\n");
printf("★ 8)计算二叉树的深度 ☆\n");
printf("☆ 9)中序线索树二叉树 ★\n");
printf("★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆\n");
scanf("%d",&n);
if(n<0||n>9)
{
printf("您输入的序号不正确,请重新输入:\n");
scanf("%d",&n);
}
switch(n)
{
case 0:printf("Goodbye!\n");m =0 ;exit(0);break;
case 1:{printf("先序遍历一棵树:\n");PreOrderTraverse(T,visit);printf("\n");break;}
case 2:{printf("先续遍历一棵树(非递归实现): \n");PreOrderTraverse_nr(T,visit);printf("\n");break;}
case 3:{printf("中续遍历一棵树: \n");InOrderTraverse(T,visit);printf("\n");break; }
case 4:{printf("中续遍历一棵树(非递归实现): \n");InOrderTraverse_nr(T,visit);printf("\n");break;}
case 5:{printf("后续遍历一棵树: \n");PostOrderTraverse (T,visit);printf("\n"); break;}
case 6:{printf("后续遍历一棵树(非递归实现): \n");PostOrderTraverse_nr(T,visit);printf("\n");break;}
case 7:{printf("统计叶子结点个数 \n");printf("%d\n",CountLeaf (T));break;}
case 8:{printf("计算二叉树的深度:\n");printf("%d\n", Depth(T));break;}
case 9:{printf("输出中序线索树二叉树的内容:\n");InOrderThreading(Thrt, T);InOrderTraverse_Thr(Thrt,visit);printf("\n");break;}
}
}
while(m!=0);
}
//
int main()
{
//BiThrTree T;
//BiThrTree Thrt;
display();
return 0;
}
标签: 树
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明


网友评论
我要评论