您好,欢迎来到小奈知识网。
搜索
您的当前位置:首页数据结构--树

数据结构--树

来源:小奈知识网
二叉树

对任何一课二叉树n0=n2+1

BiTNode 或者*BiTree binarytreenode二叉树结点 二叉树的遍历有先(根)序,中(根)序,后(根)序 Preorder 都是将根结点作为参数传入 Inorder Postorder //递归算法

void Preorder(BiTree T) {

if(!T) return NULL;//有可能为空树 else{

visit(T);

Preorder(T->lchild); Preorder(T->rchild); } }

//中序非递归(用栈往上反)算法

核心就三句话:指针或栈不空就循环;指针不空就进栈,左走;否则出栈,访问,向右走 Status InOrderTraverse(BiTree T) {

InitStack(S);p=T;

while(p||!StackEmpty(S))//或者在循环之前将p进栈,那么条件改为(!StackEmpty(S)) {

if(p) {push(S,p);p=p->lchild;} else {

pop(S,p);visit(p); p=p->rchild; } }

return OK; }

//先序非递归(跟中序的唯一差别在于访问p的时机不同) Status PreOrderTraverse(BiTree T) {

InitStack(S);p=T;

while(p||!StackEmpty(S))//只有第一次循环栈是空的 {

if(p) {visit(p);push(S,p);p=p->lchild;} else {

pop(S,p); p=p->rchild; } }

return OK; }

//后序非递归

基本思想:需要区分两次进栈的不同返回点 typedef struct { BTNode *ptr;

enum{0,1,2} mark; } PMType;

void PostOrder_Stack(Bitree T) {

PMType a; InitStack(S); Push(S,{T,0});

while(!StackEmpty(S)) {

Pop(S,a);

switch(a.mark) {

case 0://左子树还没有访问 Push(S,{a.ptr,1});

if(a.ptr->lchild) Push(S,{a.ptr->lchild,0}); break;

case 1://左子树访问完了 Push(S,{a.ptr,2});

if(a.ptr->rchild) Push(S,{a.ptr->rchild,0}); break;

case 2://右子树访问完了 visit(a.ptr); } } }

中序非递归

GoFarLeft 取最左下角,没有左孩子的那个顶点,要用到栈

BiTNode GoFarLeft(BiTree T,Stack *s){ if(!T) return NULL; while(T) {

Push(s,T); T=T->lchild; }

return T;//这个时候T没有左孩子 }

//核心思想,找中序下第一个结点,访问完过后找后继,他或者是右子树中序下第一个结点(右子树最左下角结点),或者是刚刚入栈的的结点(双亲结点) void Inorder_I(BiTree T) {

Stack *s;

if(!T) return NULL; else {

p=GoFarLeft(T,s);//找中序下访问的第一个结点 while(p){ visit(p);

if(p->rchild)//如果有右子树,那下一个就是右子树中序下第一个 p=GoFarLeft(p->rchild);

else if(!IsStackEmpty(s))//如果没有右子树,后继就是他的父结点 p=Pop(s); else

p=NULL; }

} }

//统计叶子结点个数,改自先序遍历的递归算法 CountLeaf

void CountLeaf(BiTree T,int &count) {

if((!T->lchild)&&(!T->rchild)) count++; else{

CountLeaf(T->lchild,count); CountLeaf(T->rchild,count); } }

//求二叉树的深度 Depth depthLeft

depthRight depthVal

int Depth(BiTree T) {

if(!T)return 0;//空树深度为0 else{

depthLeft=Depth(T->lchild); depthRight=Depth(T->rchild);

depthval=1+(depthLeft>depthRight? depthLeft:depthRight); } }

//求值为x的结点在二叉树中的层数 int GetDepth(GiTree &T,int x) {

if(T==NULL) return NULL; if(T->data==x) return 1; else{

j=GetDepth(T->lchild,x); i=GetDepth(T->rchild,x); return (i>j?i:j)+1; } }

//复制二叉树.复制左子树,复制右子树,利用指向左右子树的指针和给定数据建立根结点。递归

GetTreeNode 建立根结点 TelemType e树元素类型 lptr rptr

BiTNode GetTreeNode(TElemType e,BiTNode *lptr,BitNode *rptr) {

if(!T=(BiTree)malloc(sizeof(BiTNode))) exit(OVERFLOW); else{

T->data=e;T->lchild=lptr;T->rchild=rptr; }

return T; }

CopyTree newlptr newrptr

newT

重要提示,对于递归算法,你就按照递归局部的去理解,不要整个树或者图遍历去理解 BiTNode CopyTree(BiTree T) {

if(!T) return NULL; if(T->lchild)

newlptr=CopyTree(T->lchild);//如果有左子树就复制左子树 else

newlptr=NULL;

if(T->rchild)

newrptr=CopyTree(T->rchild);//如果有右子树就复制右子树 else

newrpt=NULL:

newT=GetTreeNode(T->data,newlptr,newrptr);//利用复制好的左右子树指针 return newT; }

//建立二叉树的存储结构(改自先序递归算法)创建根结点,创建左子,创建右子 Status

CreateBiTree ch

Status CreateBiTree(BiTree &T)//在已给指针下创建二叉树 {

scanf(&ch);//ch=getchar(); if(ch=='#') return NULL; else{

if(!(T=(BiTree)malloc(sizeof(BiTNode)))) exit(OVERFLOW); T->data=ch;

CreateBiTree(T->lchild); CreateBiTree(T->rchild); } }

//线索二叉树 BiThrNode

LTag RTag 左右标志

Link Thread 左右标志的取值,分别代表0,1,指向孩子,指向前趋或后继 //中序遍历中序线索二叉树(可以达到非递归不用栈的效果) 问题1:第一个结点?最左下(没有左孩子的)结点

问题2:后继结点?若有右子树,为右子树中序下第一个结点(最左下) 否则,为后继线索所指向的结点 InOrderTraverse_Thr

void InOrderTraverse_Thr(BiTree T) {

if(!T) return NULL;

p=T->lchild; //注意这个T不是树的根结点而是另加的头结点 while(p!=T){

while(p->LTag==Link) p=p->lchild;visit(p); while(p->RTag==Thread && p->rchild!=T) { p=p->rchild;visit(p);}//有后继找后继

p=p->rchild; //没后继那肯定有右子树,进右子树 } }

//先序遍历中序线索二叉树

void PreOrderTraverse_Thr(BiTree T) {

if(!T) return NULL;

p=T->lchild; //注意这个T不是树的根结点而是另加的头结点 while(p!=T){

while(p->LTag==Link) {visit(p);p=p->lchild;} visit(p);

while(p->RTag==Thread && p->rchild!=T) { p=p->rchild;}//有后继找后继

p=p->rchild; //没后继那肯定有右子树,进右子树 } }

//建立中序线索链表(改自中序的递归算法) InThreading BiThrTree

void InThreading(BiThrTree p) {

if(p){

InThreading(p->lchild);

if(!p->lchild) {p->LTag=1;p->lchild=pre;} if(!pre->rchild) {pre->RTag=1;pre->rchild=p;} pre=p;

InThreading(p->rchild); } }

InOrderThreading

BiThrTree 线索二叉链表的结点类型 Thrt 线索二叉链表的头结点 pre p

注意头结点的左孩子指向后继,右孩子指向前趋,与其他结点相反 Status InOrderThreading(BiThrTree T){//将树的根结点传入 if(!(Thrt=(BiThrTree)malloc(sizeof(BiThrNode)))) exit(OVERFLOW);

Thrt->lchild=T;Thrt->LTag=Link;Thrt->RTag=Thread;Thrt-rchild=NULL; if(!T) Thrt-rchild=Thrt; else {

InThreading(T);//当p为空时线索化结束,pre指向最后一个结点 pre->RTag=Thread;pre->rchild=Thrt; Thrt->rchild=pre; }

return OK; } 树

//求树的深度 TreeDepth

CSTree 采用孩子兄弟链表进行存储 firstchild nextsibling

int TreeDepth(CSTree T){ if(!T) return NULL; else {

h1=TreeDepth(p->firstchild); h2=TreeDepth(p->nextsibling);

return ((h1+1)>h2? (h1+1):h2);//注意兄弟结点与根结点是在同一层的 } // 所以取他的深度作为树的深度不需要加一 }

//输出二叉树上从根到所有叶子结点的路径 AllPath BiTree Stack

void AllPath(BiTree T,Stack s){ if(T){

Push(s,T);

if(!T->lchild&&!T->rchild) PrintStack(s); else{

AllPath(T->lchild); AllPath(T->rchild); } Pop(s); } }

//输出森林中所有从根到叶子的路径 firstchild nextfibling

与上面的算法有两点不同

不同点一:左子树空的结点就是森林的叶结点

不同点二:不同的兄弟结点是在不同的路径上,所以每次向右走当前结点退栈 void OutPath(BiTree T,Stack &s){ if(T){

Push(s,T);

if(!T->firstchlid) printfStack(s); else

OutPath(T->firstchild); Pop(s);T=T->nextsibling; } }

//建立树的二叉链表存储结构 CreateTree CSTree 树类型

GetTreeNode 创建结点 GetHead 取得队头元素 firstchild nextsibling

根据输入的数队建立结点,在队列中寻找双亲结点,判断双亲结点是否有孩子,如果没有,直接连上,如果有,那么连到同样以该结点为双亲的刚刚建立的结点上 void CreateTree(CSTree T){ T=NULL;

for(scanf(&fa,&ch);ch!='#';scanf(&fa,&ch);){ p=GetTreeNode(ch); EnQueue(p);

if(fa='#') p=T;//输入的是第一个结点 else {

GetHead(Q,s);

while(s->data!=ch)

{DeQueue(Q,s);GetHead(Q,s);}

if(!s->firstchild) {s->firstchild=p;r=p;} else {r->nextsibling=p;r=p;} } } }

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- huatuo3.com 版权所有 蜀ICP备2023022190号-1

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务