数据结构编程实验——chapter9-应用二叉树的基本概念编程

  二叉树是树结构中的重要概念,一些特殊的二叉树如满二叉树和彻底二叉树因为节点序号的特殊关系,在一些算法中十分常见。ios

  这篇文章将从三个方面介绍有关二叉树的知识点:算法

(1)   普通有序树转化为二叉树。编程

(2)   计算二叉树路径。函数

(3)   经过两种遍历肯定二叉树结构。spa

 

一.普通有序树转化为二叉树设计

其实不只限于有序树,森林转化成二叉树也是利用了这里给出的方法。code

左子女-右兄弟法:blog

1)     T中节点与T’中一一对应,即T中每个节点的序号的值在T’中保持不变。递归

2)     T中某节点v的第一个儿子节点为v1,则在T’中v1为对应节点v的左儿子。ci

3)     T中节点v的儿子序列(即v1节点的兄弟序列),在T’中依次连接成一条开始与v1的右链。

 

Ex1(poj3437):

用du字符串的形式(d是down的缩写,u是up的缩写,该字符串描述了先序遍历有序树的方向变化,间接描述的树结构)表征,如今要求咱们求解有序树的高度及其转化成二叉树后的高度。

 

首先咱们明确一个知识点,根据普通有序树转化成二叉树的方法,咱们能够获得这样一个公式:对于节点x及其在有序树中的父节点y,咱们设level(i)表明节点i在二叉树中的层次(根节点是第0层),那么有level(x) = level(y) + son_th.其中son_th表示x是y的第几个儿子。所以咱们在算法设计中,首先递归设计算法统计有序树的层数,中间设置变量tempson来记录当前节点是其有序树中的父节点中的第几个儿子,顺便就能够求出二叉树的层次。

 

代码以下:

#include<cstdio>

#include<string>

#include<iostream>

#include<algorithm>

using namespace std;

string s;

int i , n = 0 , height1 , height2;

 

void work(int level1 , int level2){//递归计算树高,每次函数调用表示咱们在两种树种遍历到同一节点,这一节点在有序树和二叉树中的层次分别是level1 , level2

   int tempson = 0;//该节点的儿子序列计数器置零

   while(s[i] == 'd'){//若是当前方向向下,说明有儿子

      i++;

      tempson++;

      work(level1 + 1 , level2 + tempson);//基于儿子节点递归调用函数

   }

    //完成了该节点全部子节点的递归函数调用,维护层数最大值

   height1 = max(height1 , level1);

   height2 = max(height2 , level2);

   i++;

}

 

int main(){

      while(cin >> s && s != "#"){

         i = height1 = height2 = 0;

         work(0 , 0);

         cout << "Tree "<<++n<<":"<<height1 <<" => "<<height2<<endl;

      }

}

 

 

二.计算二叉树的路径

在一些题目中每每要求咱们在二叉树中的某条路径上行遍以得到一些信息。彻底二叉树就是一种很是利于咱们行遍路径的结构。设咱们有n节点的彻底二叉树,且姐弟拿笔拿好是从上而下从左而右递增分布的,则任意分支节点i的父节点是floor((i-1)/2);若节点i有左儿子则左儿子的节点序号是2i+1,若节点i有右儿子,则节点序号为2i+2.

 

Ex1:

假设咱们有一个二叉树,根节点标识为(1,1),其左儿子被标识为(2 , 1),右节点被标识为(1,2)。抽象得说,若一个节点的标识为(a , b),则其左儿子的标识为(a + b , b),右儿子标识为(a , a+b).那么如今给出一个节点的标识(a , b),编程计算这个这个节点相对于根节点(1 ,1)向左移动了多少步,向右移动了多少步。

 

这里实际上就是给出了一种二叉树路径的一种生成机制。咱们从已知标识的(a,b)开始分析。若是a>b,则显然必定是以前的某些节点向左移动了若干步,朴素来说,咱们基于(a,b),其父节点是(a – b , b),若是依然知足a-b > n,那么在走到其父节点(a – b – b ,b)。这一迭代扩成能够归纳为:

If(a > b){

up = floor((a – 1 )/b).某个节点连续往左儿子走up步走到(a,b)

left += up;//更新

a -= up*b. //此时a必定是b的剩余系。可是a不会等于0,这也是为何用(a-1)/b而不用a/b的缘由。

}

对称的,b>a的情形也是同样,通过屡次迭代运算,知道a = b = 1,说明路径已经行遍到了根节点。

参考代码以下:

#include<cstdio>

#include<string>

#include<iostream>

#include<algorithm>

using namespace std;

string s;

int i , n = 0 , height1 , height2;

 

void work(int level1 , int level2){//递归计算树高,每次函数调用表示咱们在两种树种遍历到同一节点,这一节点在有序树和二叉树中的层次分别是level1 , level2

   int tempson = 0;//该节点的儿子序列计数器置零

   while(s[i] == 'd'){//若是当前方向向下,说明有儿子

      i++;

      tempson++;

      work(level1 + 1 , level2 + tempson);//基于儿子节点递归调用函数

   }

    //完成了该节点全部子节点的递归函数调用,维护层数最大值

   height1 = max(height1 , level1);

   height2 = max(height2 , level2);

   i++;

}

 

int main(){

      while(cin >> s && s != "#"){

         i = height1 = height2 = 0;

         work(0 , 0);

         cout << "Tree "<<++n<<":"<<height1 <<" => "<<height2<<endl;

      }

}
相关文章
相关标签/搜索