族谱网 头条 人物百科

2017-10-16
出处:族谱网
作者:阿族小谱
浏览:900
转发:0
评论:0
术语节点的度:一个节点含有的子树的个数称为该节点的度;树的度:一棵树中,最大的节点的度称为树的度;叶节点或终端节点:度为零的节点;非终端节点或分支节点:度不为零的节点;父亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;兄弟节点:具有相同父节点的节点互称为兄弟节点;节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;树的高度或深度:树中节点的最大层次;堂兄弟节点:父节点在同一层的节点互为堂兄弟;节点的祖先:从根到该节点所经分支上的所有节点;子孙:以某节点为根的子树中任一节点都称为该节点的子孙。森林:由m(m>=0)棵互不相交的树的集合称为森林;树的种类无序树:树中任意节点的子节点之间没有顺序关系,这种树称为无序树,也称为自由树;有序树:树中任意节点的子节点之间有顺序关系,这种树称为有序树;...

术语

节点的度 :一个节点含有的子树的个数称为该节点的度;

树的度 :一棵树中,最大的节点的度称为树的度;

叶节点 或 终端节点 :度为零的节点;

非终端节点 或 分支节点 :度不为零的节点;

父亲节点 或 父节点 :若一个节点含有子节点,则这个节点称为其子节点的父节点;

孩子节点 或 子节点 :一个节点含有的子树的根节点称为该节点的子节点;

兄弟节点 :具有相同父节点的节点互称为兄弟节点;

节点的 层次 :从根开始定义起,根为第1层,根的子节点为第2层,以此类推;

树的 高度 或 深度 :树中节点的最大层次;

堂兄弟节点 :父节点在同一层的节点互为堂兄弟;

节点的祖先 :从根到该节点所经分支上的所有节点;

子孙 :以某节点为根的子树中任一节点都称为该节点的子孙。

森林 :由m(m>=0)棵互不相交的树的集合称为森林;

树的种类

无序树:树中任意节点的子节点之间没有顺序关系,这种树称为无序树,也称为自由树;

有序树:树中任意节点的子节点之间有顺序关系,这种树称为有序树;

存储

父节点表示法

存储结构

基本操作

设已有链队列类型LinkQueue的定义及基本操作(参见队列)。

构造空树

清空或销毁一个树也是同样的操作

voidClearTree(PTree*T){T->n=0;}

构造树

voidCreateTree(PTree*T){LinkQueueq;QElemTypep,qq;inti=1,j,l;charc[MAX_TREE_SIZE];/* 临时存放孩子节点数组 */InitQueue(&q);/* 初始化队列 */printf("请输入根节点(字符型,空格为空): ");scanf("%c%*c",&T->nodes[0].data);/* 根节点序号为0,%*c吃掉回车符 */if(T->nodes[0].data!=Nil)/* 非空树 */{T->nodes[0].parent=-1;/* 根节点无父节点 */qq.name=T->nodes[0].data;qq.num=0;EnQueue(&q,qq);/* 入队此节点 */while(i<MAX_TREE_SIZE&&!QueueEmpty(q))/* 数组未满且队不空 */{DeQueue(&q,&qq);/* 节点加入队列 */printf("请按长幼顺序输入节点%c的所有孩子: ",qq.name);gets(c);l=strlen(c);for(j=0;jnodes[i].data=c[j];T->nodes[i].parent=qq.num;p.name=c[j];p.num=i;EnQueue(&q,p);/* 入队此节点 */i++;}}if(i>MAX_TREE_SIZE){printf("节点数超过数组容量\n");exit(OVERFLOW);}T->n=i;}elseT->n=0;}

判断树是否为空

StatusTreeEmpty(PTree*T){/* 初始条件:树T存在。操作结果:若T为空树,则返回TRUE,否则返回FALSE */returnT->n==0;}

获取树的深度

intTreeDepth(PTree*T){/* 初始条件:树T存在。操作结果:返回T的深度 */intk,m,def,max=0;for(k=0;kn;++k){def=1;/* 初始化本节点的深度 */m=T->nodes[k].parent;while(m!=-1){m=T->nodes[m].parent;def++;}if(max<def)max=def;}returnmax;/* 最大深度 */}

获取根节点

TElemTypeRoot(PTree*T){/* 初始条件:树T存在。操作结果:返回T的根 */inti;for(i=0;in;i++)if(T->nodes[i].parentnodes[i].data;returnNil;}

获取第i个节点的值

TElemTypeValue(PTree*T,inti){/* 初始条件:树T存在,i是树T中节点的序号。操作结果:返回第i个节点的值 */if(in)returnT->nodes[i].data;elsereturnNil;}

改变节点的值

StatusAssign(PTree*T,TElemTypecur_e,TElemTypevalue){/* 初始条件:树T存在,cur_e是树T中节点的值。操作结果:改cur_e为value */intj;for(j=0;jn;j++){if(T->nodes[j].data==cur_e){T->nodes[j].data=value;returnOK;}}returnERROR;}

获取节点的父节点

TElemTypeParent(PTree*T,TElemTypecur_e){/* 初始条件:树T存在,cur_e是T中某个节点 *//* 操作结果:若cur_e是T的非根节点,则返回它的父节点,否则函数值为"空"*/intj;for(j=1;jn;j++)/* 根节点序号为0 */if(T->nodes[j].data==cur_e)returnT->nodes[T->nodes[j].parent].data;returnNil;}

获取节点的最左孩子节点

TElemTypeLeftChild(PTree*T,TElemTypecur_e){/* 初始条件:树T存在,cur_e是T中某个节点 *//* 操作结果:若cur_e是T的非叶子节点,则返回它的最左孩子,否则返回"空"*/inti,j;for(i=0;in;i++)if(T->nodes[i].data==cur_e)/* 找到cur_e,其序号为i */break;for(j=i+1;jn;j++)/* 根据树的构造函数,孩子的序号>其父节点的序号 */if(T->nodes[j].parent==i)/* 根据树的构造函数,最左孩子(长子)的序号<其它孩子的序号 */returnT->nodes[j].data;returnNil;}

获取节点的右兄弟节点

TElemTypeRightSibling(PTree*T,TElemTypecur_e){/* 初始条件:树T存在,cur_e是T中某个节点 *//* 操作结果:若cur_e有右(下一个)兄弟,则返回它的右兄弟,否则返回"空"*/inti;for(i=0;in;i++)if(T->nodes[i].data==cur_e)/* 找到cur_e,其序号为i */break;if(T->nodes[i+1].parent==T->nodes[i].parent)/* 根据树的构造函数,若cur_e有右兄弟的话则右兄弟紧接其后 */returnT->nodes[i+1].data;returnNil;}

输出树

voidPrint(PTree*T){/* 输出树T。加 */inti;printf("节点个数=%d\n",T->n);printf(" 节点 父节点\n");for(i=0;in;i++){printf(" %c",Value(T,i));/* 节点 */if(T->nodes[i].parent>=0)/* 有父节点 */printf(" %c",Value(T,T->nodes[i].parent));/* 父节点 */printf("\n");}}

向树中插入另一棵树

StatusInsertChild(PTree*T,TElemTypep,inti,PTreec){/* 初始条件:树T存在,p是T中某个节点,1≤i≤p所指节点的度+1,非空树c与T不相交 *//* 操作结果:插入c为T中p节点的第i棵子树 */intj,k,l,f=1,n=0;/* 设交换标志f的初值为1,p的孩子数n的初值为0 */PTNodet;if(!TreeEmpty(T))/* T不空 */{for(j=0;jn;j++)/* 在T中找p的序号 */if(T->nodes[j].data==p)/* p的序号为j */break;l=j+1;/* 如果c是p的第1棵子树,则插在j+1处 */if(i>1)/* c不是p的第1棵子树 */{for(k=j+1;kn;k++)/* 从j+1开始找p的前i-1个孩子 */if(T->nodes[k].parent==j)/* 当前节点是p的孩子 */{n++;/* 孩子数加1 */if(n==i-1)/* 找到p的第i-1个孩子,其序号为k1 */break;}l=k+1;/* c插在k+1处 */}/* p的序号为j,c插在l处 */if(ln)/* 插入点l不在最后 */for(k=T->n-1;k>=l;k--)/* 依次将序号l以后的节点向后移c.n个位置 */{T->nodes[k+c.n]=T->nodes[k];if(T->nodes[k].parent>=l)T->nodes[k+c.n].parent+=c.n;}for(k=0;knodes[l+k].data=c.nodes[k].data;/* 依次将树c的所有节点插于此处 */T->nodes[l+k].parent=c.nodes[k].parent+l;}T->nodes[l].parent=j;/* 树c的根节点的父节点为p */T->n+=c.n;/* 树T的节点数加c.n个 */while(f){/* 从插入点之后,将节点仍按层序排列 */f=0;/* 交换标志置0 */for(j=l;jn-1;j++)if(T->nodes[j].parent>T->nodes[j+1].parent){/* 如果节点j的父节点排在节点j+1的父节点之后(树没有按层序排列),交换两节点*/t=T->nodes[j];T->nodes[j]=T->nodes[j+1];T->nodes[j+1]=t;f=1;/* 交换标志置1 */for(k=j;kn;k++)/* 改变父节点序号 */if(T->nodes[k].parent==j)T->nodes[k].parent++;/* 父节点序号改为j+1 */elseif(T->nodes[k].parent==j+1)T->nodes[k].parent--;/* 父节点序号改为j */}}returnOK;}else/* 树T不存在 */returnERROR;}

删除子树

Statusdeleted[MAX_TREE_SIZE+1];/* 删除标志数组(全局量) */voidDeleteChild(PTree*T,TElemTypep,inti){/* 初始条件:树T存在,p是T中某个节点,1≤i≤p所指节点的度 *//* 操作结果:删除T中节点p的第i棵子树 */intj,k,n=0;LinkQueueq;QElemTypepq,qq;for(j=0;jn;j++)deleted[j]=0;/* 置初值为0(不删除标记) */pq.name="a";/* 此成员不用 */InitQueue(&q);/* 初始化队列 */for(j=0;jn;j++)if(T->nodes[j].data==p)break;/* j为节点p的序号 */for(k=j+1;kn;k++){if(T->nodes[k].parent==j)n++;if(n==i)break;/* k为p的第i棵子树节点的序号 */}if(kn)/* p的第i棵子树节点存在 */{n=0;pq.num=k;deleted[k]=1;/* 置删除标记 */n++;EnQueue(&q,pq);while(!QueueEmpty(q)){DeQueue(&q,&qq);for(j=qq.num+1;jn;j++)if(T->nodes[j].parent==qq.num){pq.num=j;deleted[j]=1;/* 置删除标记 */n++;EnQueue(&q,pq);}}for(j=0;jn;j++)if(deleted[j]==1){for(k=j+1;kn;k++){deleted[k-1]=deleted[k];T->nodes[k-1]=T->nodes[k];if(T->nodes[k].parent>j)T->nodes[k-1].parent--;}j--;}T->n-=n;/* n为待删除节点数 */}}

层序遍历树

voidTraverseTree(PTree*T,void(*Visit)(TElemType)){/* 初始条件:二叉树T存在,Visit是对节点操作的应用函数 *//* 操作结果:层序遍历树T,对每个节点调用函数Visit一次且仅一次 */inti;for(i=0;in;i++)Visit(T->nodes[i].data);printf("\n");}

孩子链表表示法

存储结构

/*树的孩子链表存储表示*/typedefstructCTNode{// 孩子节点intchild;structCTNode*next;}*ChildPtr;typedefstruct{ElemTypedata;// 节点的数据元素ChildPtrfirstchild;// 孩子链表头指针}CTBox;typedefstruct{CTBoxnodes[MAX_TREE_SIZE];intn,r;// 节点数和根节点的位置}CTree;

森林、树与二叉树的转换

见二叉树相应章节

参考文献

 

 


免责声明:以上内容版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。感谢每一位辛勤著写的作者,感谢每一位的分享。

——— 没有了 ———
编辑:阿族小谱

更多文章

更多精彩文章
评论 {{commentTotal}} 文明上网理性发言,请遵守《新闻评论服务协议》
游客
发表评论
  • {{item.userName}} 举报

    {{item.content}}

    {{item.time}} {{item.replyListShow ? '收起' : '展开'}}评论 {{curReplyId == item.id ? '取消回复' : '回复'}}

    回复评论
加载更多评论
打赏作者
“感谢您的打赏,我会更努力的创作”
— 请选择您要打赏的金额 —
{{item.label}}
{{item.label}}
打赏成功!
“感谢您的打赏,我会更努力的创作”
返回
打赏
私信

推荐阅读

· 树
定义雪曼将军树真双子叶植物或是松柏门二次生长(英语:secondarygrowth)的示意图,每一季木质部会生长,使树干、树枝及根变粗虽然树是一个常用的词语,但没有一个广为认同的定义,不管是植物学上的定义或是日常生活的定义都没有。最广泛的定义,树是一种有细长茎(或树干),可以支持叶子或枝条离地面相当的高度。树也常用高度来定义,高度在0.5至10米(1.6至32.8英尺)的较小植物一般会称为灌木,所以树木的最小高度也只是大致的定义而已。以此定义来看,像香蕉树及番木瓜树等高大的草本植物也算是树。另一个范围较窄的定义是树有木质且会二次生长(英语:secondarygrowth)的茎,也就是除了每年因分生组织而高度增加以外,茎也会每年往外加粗。此定义下,像棕榈树、香蕉树及番木瓜树不论高度多高,都不能视为是树。有些单子叶植物可以在另一个较松一点的定义下归类为树,Joshuatree、棕榈和竹子没有二...
· 树
定义如果一个无向简单图G满足以下相互等价的条件之一,那么G是一棵树:G是没有回路的连通图。G没有回路,但是在G内添加任意一条边,就会形成一个回路。G是连通的,但是如果去掉任意一条边,就不再连通。G是连通的,并且3顶点的完全图K3{\displaystyleK_{3}}不是G的子图。G内的任意两个顶点能被唯一路径所连通。如果无向简单图G有有限个顶点(设为n个顶点),那么G是一棵树还等价于:G是连通的,有n−1条边,并且G没有简单回路。如果一个无向简单图G中没有简单回路,那么G是森林。性质一棵树中每两个点之间都有且只有一条路径(指没有重复边的路径)。一颗有N个点的树有N-1条边,也就是连接N个点所需要的最少边数。所以如果去掉树中的一条边,树就会不连通。如果在一棵树中加入任意的一条边,就会得到有且只有一个环的图。这是因为这条边连接的两个点(或是一个点)中有且只有一条路径,这条路径和新加的边连在一...
· 榧树
外部链接(简体中文)中国数字植物标本馆中的相关内容:榧树
· 桉树
形态一般为常绿乔木;枝、叶花有芳香;叶子通常互生,有柄,全缘羽状脉,多为镰刀形;早春开白色、红色或黄色花,多为伞形或头状花序,萼片与花瓣连合成帽状体(花盖),开花时脱落;蒴果成熟时顶端3-5裂;种子多数有角棱。
· 桧树
大概是在二千年以前吧,有一个富人对自己的妻子非常爱护,夫妻俩相亲相爱,生活非常幸福,遗憾的是他们一直没有小孩。他们的房屋前有一座花园,里面有一棵高大的桧树。一年冬天,外面下起了大雪,大地披上了白色的银装,妻子站在桧树下,一边欣赏着雪景,一边削着苹果,一不留神,小刀切到了手指头,滴滴鲜血流出来洒在了雪地上。看着白雪衬托着的鲜红血点,她深深地叹了一口气说道:“唉——!要是我有一个孩子,他的皮肤像雪一般的白嫩,又透着血一样的红润,我该是多么的幸福啊!”说着想着,她的心情变得兴奋起来,仿佛自己的愿望真的就要成为现实一样。冬天过去了,春风吹来,卸去了披在大地身上的银装,又给她换上了绿色的外套,朵朵鲜花点缀着翠绿的田野;当树木吐露出春芽时,嫩枝又开始被拂去枝头的残花,小鸟在树丛间欢快地飞来跳去,唱着赞美春天的歌声。面对这生机盎然的大自然,富人的妻子满怀希望,心中充满了喜悦。初夏来临,温暖的阳光又催开了...

关于我们

关注族谱网 微信公众号,每日及时查看相关推荐,订阅互动等。

APP下载

下载族谱APP 微信公众号,每日及时查看
扫一扫添加客服微信