數(shù)據(jù)結(jié)構(gòu)(樹和二叉樹)

1.樹和二叉樹的定義

(1) 樹的定義

樹是n (n≥0) 個結(jié)點的有限集。 n=0 時稱為空樹。在任意一棵非空樹中:

  • 有且僅有一個特定的稱為根(Root) 的結(jié)點;
  • 當(dāng)n>1 時,除了根結(jié)點以外其余結(jié)點可分為m(m>0) 個互不相交的有限集T1、 T2、 ……、 Tm, 其中每一個集合本身又是一棵樹,并且稱為根的子樹(SubTree)。

(2) 樹的基本術(shù)語

結(jié)點:樹中的一個獨立單元。
結(jié)點的度:結(jié)點擁有的子樹數(shù)稱為結(jié)點的度。
樹的度:樹的度是樹內(nèi)各結(jié)點度的最大值。
葉子:度為0的結(jié)點稱為葉子或者終端結(jié)點。
非終端結(jié)點:度不為0的結(jié)點稱為非終端結(jié)點或者分支結(jié)點。除根結(jié)點以外,非終端結(jié)點也稱為內(nèi)部結(jié)點。
雙親和孩子:結(jié)點的子數(shù)的根稱為該結(jié)點的孩子,相應(yīng)地,該結(jié)點稱為孩子地雙親。
兄弟:同一個雙親地孩子之間互稱為兄弟。
祖先:從根到該結(jié)點所經(jīng)分支上所有結(jié)點。
子孫:以某結(jié)點為根地子數(shù)中任一結(jié)點都稱為該結(jié)點地子孫。
層次:結(jié)點地層次從根開始定義起,根稱為第一層,根地孩子為第二層。樹中任一結(jié)點層次等于其雙親結(jié)點地層次加1。
堂兄弟:雙親在同一層次地結(jié)點互為堂兄弟。
樹地深度:樹中結(jié)點地最大層次稱為樹地深度或高度。
有序樹和無序樹:如果將樹中結(jié)點地各個子樹看成從左至右是有次序地,不能互換,則稱為有序樹,否則稱為無序樹。在有序樹中最左邊地子樹的根稱為第一個孩子,最右邊的稱為最后一個孩子。
森林:森林(Forest) 是m(m≥0) 棵互不相交的樹的集合。對樹中每個結(jié)點而言,其子樹的集合即為森林。
二叉樹:是n(n≥0)個結(jié)點的有限集合,該集合或者為空集(稱為空二叉樹),或者由一個根結(jié)點和兩棵互不相交的、分別稱為根結(jié)點的左子樹和右子樹的二叉樹組成。


(3) 二叉樹的定義

二叉樹是n個結(jié)點所構(gòu)成的集合,它或為空樹(n=0),或為非空樹,對于非空樹T:

  • 有且只有一個稱為根的結(jié)點。
  • 除根結(jié)點以外的其余結(jié)點分為兩個互不相交的子集T1和T2,分別稱為T的左子樹和右子樹,且T1和T2本身又是二叉樹。

二叉樹和樹的區(qū)別:
* 二叉樹每個結(jié)點至多只有兩顆子樹。
* 二叉樹的子樹有左右之分,其次序不能任意顛倒。

2. 二叉樹的性質(zhì)和存儲結(jié)構(gòu)

(1) 二叉樹的性質(zhì)

性質(zhì)1: 在二叉樹上的第i層至多有2^(i-1)個結(jié)點。(i>=1)
性質(zhì)2: 深度為k 的二叉樹至多有2^k -1個結(jié)點(k>=1)。
性質(zhì)3:對于任何一棵二叉樹T,如果其終端結(jié)點數(shù)為n0,度為2的結(jié)點數(shù)為n2,則n0=n2+1。
證明:
二叉樹結(jié)點總數(shù):n = n0+n1+n2;
除了根結(jié)點外,其余結(jié)點都有一個分支進入,設(shè)B為分支總數(shù),則n = B + 1;由于這些分支是由度為1或2的結(jié)點射出,所以B=n1+2*n2
于是:n = n1+2*n2+1 => n0 = n2+1

滿二叉樹:深度為k且含有2^k - 1個結(jié)點的二叉樹。
滿二叉樹的特點:每一層上的結(jié)點數(shù)都是最大結(jié)點數(shù),即每一層i的結(jié)點數(shù)都具有最大值2^(i-1)。
對滿二叉樹結(jié)點進行編號,約定編號從根結(jié)點起,自上而下,自左至右。

完全二叉樹:深度為k對,由n個結(jié)點的二叉樹,當(dāng)且僅當(dāng)每一個結(jié)點都與深度為k的滿二叉樹中編號1至n的結(jié)點一一對應(yīng),稱之為完全二叉樹。
完全二叉樹的特點:
* 葉子結(jié)點只能在層次最大的兩層上出現(xiàn)。
* 對任一結(jié)點,若其右分支下的子孫的最大層次為l,則其左分支下的子孫的最大層次必為l或l+1。


(2) 二叉樹的存儲結(jié)構(gòu)

1.順序存儲結(jié)構(gòu):使用一組地址連續(xù)的存儲單元來存儲數(shù)據(jù)元素,將二叉樹的結(jié)點依照自上而下,自左至右存儲結(jié)點元素。

#define MAXSIZE 100;
typedef TElemType SqBiTree[MAXSIZE];//0號單元存儲根結(jié)點
SqBiTree bt;

2.鏈?zhǔn)酱鎯Y(jié)構(gòu):結(jié)點包含3個域:數(shù)據(jù)域,左右指針。

typedef struct BiTNode {
    TElemType data;
    Struct BiTree *lchild,*rchild;
}BiTNode,*BiTree;

3. 遍歷二叉樹和線索二叉樹

(1) 遍歷二叉樹

遍歷二叉樹是指按某條搜索路徑巡訪樹中每個結(jié)點,使的每個結(jié)點均被訪問一次,而且僅被訪問一次。遍歷的實質(zhì)是對二叉樹進行線性化的過程。

  1. 前序遍歷:規(guī)則是若二叉樹為空,則空操作返回,否則先訪問根結(jié)點,然后前序遍歷左子樹, 再前序遍歷右子樹。如下最左圖,遍歷的順序為:ABDGHCEIF。
void PreOrderTraverse(BiTree T){    
    if(T)
    {   
        printf("%c",T->data);/* 顯示結(jié)點數(shù)據(jù),可以更改為其它對結(jié)點操作 */  
        PreOrderTraverse(T->lchild); /* 再先序遍歷左子樹 */    
        PreOrderTraverse(T->rchild); /* 最后先序遍歷右子樹 */
    }
}
  1. 中序遍歷:規(guī)則是若樹為空,則空操作返回,否則從根結(jié)點開始(注意并不是先訪問根結(jié)點),中序遍歷根結(jié)點的左子樹,然后是訪問根結(jié)點,最后中序遍歷右子樹。 如下中左圖,遍歷的順序為: GDHBAEICF。
void InOrderTraverse(BiTree T){     
    if(T)
    {   
        InOrderTraverse(T->lchild); /* 中序遍歷左子樹 */
        printf("%c",T->data);/* 訪問根結(jié)點 */    
               
        InOrderTraverse(T->rchild); /* 中序遍歷右子樹 */
    }
}
  1. 后序遍歷:規(guī)則是若樹為空,則空操作返回,否則從左到右先葉子后結(jié)點的方式遍歷訪問左右子樹,最后是訪問根結(jié)點。 如下中右圖,遍歷的順序為: GHDBIEFCA。
void PostOrderTraverse(BiTree T){   
    if(T)
    {   
        InOrderTraverse(T->lchild); /* 后序遍歷左子樹 */          
        InOrderTraverse(T->rchild); /* 后序遍歷右子樹 */
        printf("%c",T->data);/* 訪問根結(jié)點 */    
    }
}
  1. 層序遍歷:規(guī)則是若樹為空, 則空操作返回,否則從樹的第一層,也就是根結(jié)點開始訪問,從上而下逐層遍歷,在同一層中, 按從左到右的頗用才結(jié)點逐個訪問。如下最右圖所示,遍歷的順序為:ABCDEFGHI。

1. 根據(jù)遍歷順序確定二叉樹

己知前序遍歷序列和中序遍歷序列,可以唯一確定一棵二叉樹;已知后序遍歷序列和中序遍歷序列,可以唯一確定一棵二叉樹;但已知前序和后序遍歷,是不能確定一棵二叉樹的。



2. 先序遍歷的順序建立二叉樹

(1) 掃描字符序列,讀入字符ch。
(2) 如果ch是一個“#”字符,則表明該二叉樹為空樹,即T為NULL,否則執(zhí)行以下操作:

  • 申請一個結(jié)點空間T。
  • 將ch賦給T->data。
  • 遞歸創(chuàng)建T的左子樹。
  • 遞歸創(chuàng)建T的右子樹。
void CreateBiTree(BiTree &T)
{//先按次序輸入二叉樹中結(jié)點的值(一個字符),創(chuàng)建二叉鏈表示的二叉樹T
    cin>>ch;
    if(ch=='#')  T=NULL;    //  遞歸結(jié)束,建空樹
    else    //遞歸創(chuàng)建二叉樹
    {       
        T = new BiTNode; /* 生成根結(jié)點 */    
        T->data=ch; /* 根結(jié)點數(shù)據(jù)域為ch */     
        CreateBiTree(T->lchild); /* 遞歸創(chuàng)建左子樹 */
        CreateBiTree(T->rchild); /* 遞歸創(chuàng)建右子樹 */  
      } 
}
 

3. 復(fù)制二叉樹

如果是空樹,遞歸結(jié)束,否則執(zhí)行以下操作:

  • 申請一個新的結(jié)點空間,復(fù)制根結(jié)點。
  • 遞歸復(fù)制左子樹。
  • 遞歸復(fù)制右子樹。
 void Copy(BiTree T,BiTree &NewT)
{//復(fù)制一棵和T完全相同的二叉樹
    if(T == NULL)
    {
          NewT = NULL;
          return;
    }
    else
    {
          NewT = new BiTNode; 
          New->data = T->data; //復(fù)制根結(jié)點
          Copy(T->lchild,NewT->lchild);//遞歸復(fù)制左子樹
          copy(T->rchild,NewT->rchild);//遞歸復(fù)制右子樹
    }
}

4. 計算二叉樹的深度

如果是空樹,遞歸結(jié)束,深度為0,否則執(zhí)行以下操作:

  • 遞歸計算左子樹的深度計為m。
  • 遞歸計算右子樹的深度為n。
  • 如果m大于n,二叉樹的深度為m+1,否則為n+1;

int Depth(BiTree T)
{
    if(T == NULL) return 0;
    else
    {
          m = Depth(T->lchild);
          n  = Depyh(T->rchild);
          if(m>n) return(m+1);
          else  return (n+1);
     }
}
5. 統(tǒng)計二叉樹中結(jié)點的個數(shù)
int NodeCount(BiTree T)
{
      if(T == NULL) return 0;
      else return NodeCount(T->lchild)+NodeCount(T->rchild)+1;
}

(2) 線索二叉樹

1. 線索二叉樹的基本概念

對于一個有n 個結(jié)點的二叉鏈表,每個結(jié)點有指向左右孩子的兩個指針域,所以一共是2n個指針域。而n個結(jié)點的二叉樹一共有n-1 條分支線數(shù),也就是說,其實是存在2n-(n-1)=n+1個空指針域。可以考慮利用那些空地址,存放指向結(jié)點在某種遍歷次序下的前驅(qū)和后繼結(jié)點的地址。這種指向前驅(qū)和后繼的指針稱為線索,加上線索的二叉鏈表稱為線索鏈表,相應(yīng)的二叉樹就稱為線索二叉樹。線索二叉樹等于是把一棵二叉樹轉(zhuǎn)變成一個雙向鏈表。這樣對我們插入刪除結(jié)點、查找某個結(jié)點帶來了方便。所以我們對二叉樹以某種次序遍歷使其變?yōu)榫€索二叉樹的過程稱作是線索化。

若結(jié)點有左子樹,則其lchild域指示其左孩子,否則令lchild指示其前驅(qū),若結(jié)點有右子樹,則其rchild域指示其右孩子,否則令rchild域指示其后繼。為了避免混淆,需要改變結(jié)點結(jié)構(gòu),增加兩個標(biāo)志域,LTag、RTag。
LTag:
0->lchild域指示結(jié)點的左孩子
1-> lchild域指示結(jié)點的前驅(qū)

RTag:
0->Rchild域指示結(jié)點的右孩子
1-> Rchild域指示結(jié)點的后繼

//二叉樹的二叉線索存儲結(jié)構(gòu)
typedef struct BithrNode
{
    TElemType data;
    struct BiThrNode *lchid,*rchild;//左右孩子指針
    int LTag,RTag//左右標(biāo)志
}BiThrNode,*BiThrTree;

2. 構(gòu)造線索二叉樹

由于線索二叉樹構(gòu)造的實質(zhì)是將二叉鏈表中的空指針指向前驅(qū)或后繼的線索,而前驅(qū)或后繼的信息只有在遍歷時才能得到,因此線索化的過程即為在遍歷過程中修改空指針的過程。

為了紀下遍歷過程中訪問結(jié)點的先后關(guān)系,附設(shè)一個指針pre始終指向剛剛訪問過的結(jié)點,而指針p指向當(dāng)前訪問的結(jié)點,由此紀錄遍歷過程中訪問結(jié)點的先后關(guān)系。

以p結(jié)點為根的子樹中序線索化

  1. 如果p非空,左子樹遞歸線索化。
  2. 如果p的左孩子為空,則p加上左線索,將其LTag置為1,讓p的左孩子指針指向pre(前驅(qū)),否則將p的LTag置為0。
  3. 如果pre的右孩子為空,則pre加上右線索,將其RTag置為1,讓pre的右孩子指向p(后繼),否則將pre的RTag置為0。
  4. 將pre指向剛訪問過的結(jié)點p,即pre = p 。
  5. 右子樹遞歸線索化。
void InThreading(BiThrTree p)
{//pre是全局變量,初始化時其右孩子指針為空,便于在樹的左點開始建線索。
    InThreading(p->lchild); // 左子樹遞歸線索化
    if(!p->lchild)//p的左孩子為空
    {
        p->LTag = 1;//給p加上左線索
        p->lchild = pre;//p的左孩子指針指向pre(前驅(qū))
    }
    else p->LTag = 0;
    if(!pre->rchild) //pre的右孩子為空
    {
          pre->RTag =1;//給pre加上右線索
          pre->rchild = p;//pre的右孩子指針指向p(后繼)
    }
    else pre->RTag = 0;
    pre = p;//保持pre指向p的前驅(qū)
    InThreading(p->rchild);//右子樹遞歸線索化
}

帶頭結(jié)點的二叉樹中序線索化

void InOrderThreading(BiThrTree &Thrt, BiThrTree T)
{    //中序遍歷二叉樹T,并將其中序線索化,Thrt指向頭結(jié)點
    Thrt =  new BiThrNode; //建頭結(jié)點
    Thrt->LTag = 0; //頭結(jié)點有左孩子,若樹非空,則其左孩子為樹根
    Thrt->RTag = 1; //頭結(jié)點的右孩子指針為右線索
    Thrt->rchild = Thrt;    //初始化時右指針指向自己
    if (!T)     Thrt->lchild = Thrt;    //若樹非空,左指針也指向自己
    else    
    {       
          Thrt->lchild = T;     pre = Thrt;//頭結(jié)點的左孩子指向根,pre初始值指向頭結(jié)點
          InThreading(T);//以T為根的二叉樹進行中序線索化      
          pre->rchild = Thrt;   //結(jié)束后,pre為最右結(jié)點,pre的右線索指向頭結(jié)點 
          pre->RTag = 1;        
          Thrt->rchild = pre;   //頭結(jié)點的右線索指向pre
      } 
 }

 

3. 遍歷線索二叉樹




遍歷中序線索二叉樹

  1. 指針p指向根結(jié)點
  2. p為非空樹或遍歷未結(jié)束,循環(huán)執(zhí)行以下操作:
  • 沿左孩子向下,到達最左下結(jié)點*p,它是中序的第一個結(jié)點。
  • 訪問*p。
  • 沿右線索反復(fù)查找當(dāng)前結(jié)點*p的后繼結(jié)點并訪問后繼結(jié)點,直至右線索為0或者遍歷結(jié)束。
  • 轉(zhuǎn)向p的右子樹。
void InOrderTraverse_Thr(BiThrTree T)
{//T指向頭結(jié)點,頭結(jié)點的左鏈lchild指向根結(jié)點。
//中序遍歷二叉線索樹T的非遞歸算法,對每個數(shù)據(jù)元素直接輸出。
    BiThrTree p;    
    p = T->lchild;   //p指向根結(jié)點
    while (p != T)  //空樹或遍歷結(jié)束,p == T
    {       
         while (p->LTag == 0)  p = p->lchild;   //沿左孩子向下    
          cout<<p->data; //訪問其左子樹為空的結(jié)點      
          while (p->RTag == 1 && p->rchild != T)        
          {         
              p = p->rchild;cout<<p->data;//沿右線索訪問后繼結(jié)點  
           }        
            p = p->rchild;  //轉(zhuǎn)向右子樹
        }   
}

4. 樹和森林

(1) 樹的存儲結(jié)構(gòu)

1. 雙親表示法

假設(shè)以一組連續(xù)空間存儲樹的結(jié)點,同時在每個結(jié)點中,附設(shè)一個指示器指示其雙親結(jié)點到鏈表中的位置。也就是說,每個結(jié)點除了知道自己是誰以外,還知道它的雙親在哪里。結(jié)點結(jié)構(gòu)為表所示:



其中data是數(shù)據(jù)域,存儲結(jié)點的數(shù)據(jù)信息。而parent是指針域,存儲該結(jié)點的雙親在數(shù)組中的下標(biāo)。

#define MAX_TREE_SIZE 100 
typedef int TElemType;  /*樹結(jié)點的數(shù)據(jù)類型,目前暫定為整型*/
typedef struct PTNode   /*結(jié)點結(jié)構(gòu)*/
{   
    TElemType data;     /*結(jié)點數(shù)據(jù)*/    
    int parent;         /*雙親位置*/
}PTNode;
typedef struct{ 
    PTNode nodes[MAX_TREE_SIZE];    /*結(jié)點數(shù)組*/    
    int r,n;                        /*根的位置和結(jié)點數(shù)*/
}PTree

根結(jié)點因為沒有雙親,我們約定根結(jié)點的位置域設(shè)置為-1,則每個結(jié)點都存有其雙親的位置。


這樣的結(jié)構(gòu)容易根據(jù)結(jié)點的parent指針找到它的雙親結(jié)點,時間復(fù)雜度為O(1),直到parent為-1時,表示找到了樹結(jié)點的根。但不易找到結(jié)點的孩子結(jié)點,除非遍歷整個結(jié)構(gòu),如上圖,要找到E的孩子J,必須遍歷結(jié)點,找到parent為E的下標(biāo)4,才能找到E的孩子J。

2. 孩子表示法

由于樹中每個結(jié)點可能有多棵子樹,可以考慮用多重鏈表,即每個結(jié)點有多個指針域,其中每個指針指向一棵子樹的根結(jié)點,這種方法叫多重鏈表表示法。不過,樹的每個結(jié)點的度,也就是它的孩子個數(shù)是不同的。 所以可以設(shè)計兩種方案來解決。

方案一:
一種是指針域的個數(shù)就等于樹的度,復(fù)習(xí)一下,樹的度是樹各個結(jié)點度的最大值。其結(jié)構(gòu)如圖:



其中data是數(shù)據(jù)域。child1到childd是指針域,用來指向該結(jié)點的孩子結(jié)點。上述度為3的樹若用此法表示,指針域的個數(shù)為3,如圖。



這種方法對于樹中各結(jié)點的度相差很大時,容易浪費空間,因為有很多的結(jié)點,它的指針域都是空的。不過如果樹的各結(jié)點度相差很小時,意味著開辟的空間被充分利用了,這時存儲結(jié)構(gòu)的缺點反而變成了優(yōu)點。

方案二:
第二種方案每個結(jié)點指針域的個數(shù)等于該結(jié)點的度,我們專門取一個位置來存儲結(jié)點指針域的個數(shù),其結(jié)構(gòu)如下圖:



其中data為數(shù)據(jù)域,degree 為度域,也就是存儲該結(jié)點的孩子結(jié)點的個數(shù),child1到childd為指針域,指向該結(jié)點的各個孩子的結(jié)點。方案一的表示可更改如下。



這種方法克服了浪費空間的缺點,對空間利用率是很高了,但是由于各個結(jié)點的鏈表是不相同的結(jié)構(gòu),加上要維護結(jié)點的度的數(shù)值,在運算上就會帶來時間上的損耗。

能否有更好的方法,既可以減少空指針的浪費又能使結(jié)點結(jié)構(gòu)相同。可以用孩子表示法。具體辦法是,把每個結(jié)點的孩子結(jié)點排列起來,以單鏈表作存儲結(jié)構(gòu),則n個結(jié)點有n個孩子鏈表,如果是葉子結(jié)點則此單鏈表為空。然后n個頭指針又組成一個線性表,采用順序存儲結(jié)構(gòu),存放進一個一維數(shù)組中,如圖:


孩子鏈表

為此,設(shè)計兩種結(jié)點結(jié)構(gòu),一個是孩子鏈表的孩子結(jié)點,其中child是數(shù)據(jù)域,用來存儲某個結(jié)點在表頭數(shù)組中的下標(biāo)。next是指針域,用來存儲指向某結(jié)點的下一個孩子結(jié)點的指針。另一個是表頭數(shù)組的表頭結(jié)點,其中也data是數(shù)據(jù)域,存儲某結(jié)點的數(shù)據(jù)信息。firstchild是頭指針域, 存儲該結(jié)點的孩子鏈表的頭指針。

/*樹的孩子表示法結(jié)構(gòu)定義*/
#define MAX_TREE_SIZE 100
typedef struct CTNode/*孩子結(jié)點*/
{   
    int child;  
    struct CTNode *next;
}*ChildPtr; 
typedef struct/*表頭結(jié)構(gòu)*/
{   
    TElemType data; 
    ChildPtr firstchild;
}CTBox;
 typedef struct/*樹結(jié)構(gòu)*/
{   
    CTBox nodes[MAX_TREE_SIZE];     /*結(jié)點數(shù)組*/    
    int r, n;           /*根的位置和結(jié)點數(shù)*/
}CTree;

此結(jié)構(gòu)便于查找某結(jié)點的孩子、兄弟,只需查找這個結(jié)點的孩子單鏈表即可。遍歷整棵樹也比較方便,對頭結(jié)點的數(shù)組循環(huán)即可。問題是,不易知道某個結(jié)點的雙親,為此可以改進成雙親孩子表示法。結(jié)構(gòu)如下圖:


帶雙親的孩子鏈表

3. 孩子兄弟法

對樹觀察發(fā)現(xiàn),任意一棵樹, 它的結(jié)點的第一個孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。 因此,我們設(shè)置兩個指針, 分別指向該結(jié)點的第一個孩子和此結(jié)點的右兄弟。結(jié)構(gòu)如下圖



其中data是數(shù)據(jù)域,firstchild為指針域,存儲該結(jié)點的第一個孩子結(jié)點的存儲地址, rightsib是指針域,存儲該結(jié)點的右兄弟結(jié)點的存儲地址。結(jié)構(gòu)定義代碼如下。

/*樹的孩子兄弟表示法結(jié)構(gòu)定義*/
typedef struct CSNode
{
    TElemType data;
    struct CSNode *firstchild, *rightsib;
}CSNode,*CSTree;

此法方便找某個結(jié)點的孩子,只需要通過fistchild 找到此結(jié)點的長子,然后再通過長子結(jié)點的rightsib 找到它的二弟,接著一直下去,直到找到具體的孩子。如果想找到某個結(jié)點的雙親,這個表示法就有缺陷了,可以考慮加個parent指針域來解決。其實此法最大的好處就是,把一棵復(fù)雜的樹變成了二叉樹。上圖可以變形如下:


(2) 森林與二叉樹的轉(zhuǎn)換

1. 樹轉(zhuǎn)換成二叉樹

轉(zhuǎn)化方法:
1.把所有兄弟結(jié)點連接起來
2.刪掉除了結(jié)點第一個左孩子外的連線


2. 森林轉(zhuǎn)換成二叉樹

將森林轉(zhuǎn)換成二叉樹的規(guī)則與樹類似。先將森林中的每一棵樹轉(zhuǎn)換成二叉樹,再將第一棵樹的根作為轉(zhuǎn)換后的二叉樹的根,第一棵樹的左子樹作為轉(zhuǎn)換后二叉樹根的左子樹,第二棵樹作為轉(zhuǎn)換后二叉樹根的右子樹,第三棵樹作為轉(zhuǎn)換后二叉樹根的右子樹的右子樹,以此類推。


3. 二叉樹轉(zhuǎn)換成森林

若二叉樹非空,則二叉樹根及其左子樹為第一棵樹的二叉樹形式,二叉樹根的右子樹可以看作是一個由除第一棵樹外的森林轉(zhuǎn)換后的二叉樹,應(yīng)用同樣的方法,直到最后產(chǎn)生一顆沒有右子樹的二叉樹為止,這樣就得到了原森林。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。