树和森林的表示方法+树和森林的遍历

说明:本文内容和图片来自课件内容 !!!

一、树的三种存储结构

1. 双亲表示法 

2. 孩子链表表示法  

3. 树的二叉链表(孩子-兄弟)存储表示法

二、树与二叉树的转换

1.  树转换为二叉树  树转换为二叉树的步骤:

加线:在兄弟结点之间加一连线;

抹线:对任何结点,除了其最左的孩子 外,抹掉该结点原先与其孩子之间的连线;

旋转:将水平的连线和原有的连线,以树根结点为轴心,按顺时针方向粗略地旋转450

2.  二叉树还原成树  二叉树还原成树的步骤

加线:如果p结点是双亲结点的左孩子;则将p结点的右孩子,右孩子的右孩子,……,沿着右分支搜索到的所有右孩子都分别与p结点的双 亲用线连接起来;

抹线:抹掉原二叉树中所有结点与右孩子的连线;

调整: 将结点按层次排列,形成树的结构.

3.  森林转换成二叉树

 森林和二叉树的对应关系

森林 F = ( T1, T2, …, Tn );T1 = ( roott11, t12, …, t1m );

二叉树 B =( LBT, Node(root), RBT );

由森林转换成二叉树转换规则为:

F = Φ,则 B = Φ;

否则,ROOT( T1 ) 对应得到Node(root);由 (t11, t12, …, t1m ) 对应得到 LBT;由 (T2, T3,…, Tn ) 对应得到 RBT

森林转换成二叉树的步骤:

转换:将森林中的每一颗树转换成二叉树;

连线:将各颗转换后的二叉树的根结点相连;

旋转:将添加的水平线和原有的连线,以第一颗树的根结点为轴心,按顺时针方向旋转450

树的遍历有三种搜索策略:

先根遍历:若树不空,则先访问根结点,然后依次先根遍历各棵子树

后根遍历:若树不空,则先依次后根遍历各棵子树,然后访问根结点。

按层次遍历:若树不空,则自上而下自左至右访问树中每个结点。(用队列+递归实现)

有趣的是,树的后序遍历竟然是对应的二叉树的中序遍历!!!

二、森林的遍历可以分解成三部分:

1。森林中第一棵树的根结点;2。森林中第一棵树的子树森林;3。森林中其它树构成的森林。

 森林的先序遍历:若森林不空,则1.  访问森林中第一棵树的根结点;2.  先序遍历森林中第一棵树的子树森林;

   3.  先序遍历森林中(除第一棵树之外)其余树构成的森林

森林的中序遍历:若森林不空,则1. 中序遍历森林中第一棵树的子树森林;2.  访问森林中第一棵树的根结点;

  3. 中序遍历森林中(除第一棵树之外)其余树构成的森林。

森林的后序遍历:若森林不空,则1. 后序遍历森林中第一棵树的子树森林;2. 后序遍历森林中(除第一棵树外)其余树构成的森林。

  3. 访问森林中第一棵树的根结点;(不存在)

当以二叉链表作树的存储结构时,树的先根遍历和后根遍历可借用二叉树的先序遍历和中序遍历的算法实现之!!!

总结:树的遍历和二叉树遍历的对应关系

三、树的遍历的应用

1。输出树中所有从根到叶子的路径 :

先序递归遍历,在遍历过程中使用堆栈保存路径

 算法基本步骤:如果树空,则退出;

否则:结点进栈,如果树的叶子结点,则打印路径(栈中结点);否则先序遍历第一个颗子树;结点出栈;

依次先序遍历第一个颗子树的兄弟;

void AllPath( Bitree T, Stack& S ) {
  // 输出森林中所有从根到叶的路径
  if(T){
    Push(S, T->data );
    if ( !T->firstchild ) Printstack(S); //一条路径
       else AllPath( T->firstchild, S );  //遍历第一颗树
    Pop(S);
    AllPath( T->nextsibling,S);  //遍历第一颗树的兄弟
     } // if
} // OutPath

2。构造树的存储结构

要求:从键盘输入一个字符序列,构造一棵树。

问题1)字符序列的输入形式? 2)树的存储结构?

 假设以二元组 ( 双亲, 结点 ) 的形式,自上而下自左而右依次输入树的各边建立树的孩子-兄弟链表

void CreatTree( CSTree &T ) {
    T = NULL;
    for( scanf(&fa, &ch); ch!=' '; scanf(&fa,&ch);)
    {
	p = GetTreeNode(ch);    // 创建结点
	EnQueue(Q, p);       // 指针入队列尾
	if (fa == ' ')  T = p;    // 所建为根结点
        else {	
            GetHead(Q,s);  // 取队列头元素(指针值)
        while (s->data != fa ) { // 查询双亲结点,出队
            DeQueue(Q,s); 
            GetHead(Q,s);
        }   
        if (!(s->firstchild)) { 
            s->firstchild = p;
            r = p;
        }// 链接第一个孩子结点
        else { 
            r->nextsibling = p;  
            r = p; 
        }// 链接其它孩子结点 

        }// 非根结点的情况
   } // for
} // CreateTree	

猜你喜欢

转载自blog.csdn.net/liuxiang15/article/details/82347124