數據結構編程實驗——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;

      }

}
相關文章
相關標籤/搜索