程序員面試100題之二叉樹(一)

二叉樹對我們來說已經不陌生了,這是一個非常常用的數據結構,常見的二叉樹的應用:二叉排序樹、二叉平衡樹、紅黑樹、二叉堆等等,這些都是關於二叉樹的一些數據結構;好了我們廢話少說,下面我們一起來了解一些二叉樹。


二叉樹的一些基本術語和特性

二叉樹是每個節點最多有兩個子樹樹結構。通常子樹被稱作“左子樹”(left subtree)和“右子樹”(right subtree)。

二叉樹的每個結點至多隻有二棵子樹(不存在度大於2的結點),二叉樹的子樹有左右之分,次序不能顛倒。二叉樹的第i層至多有2^{i-1}個結點;深度爲k的二叉樹至多有2^k-1個結點;對任何一棵二叉樹T,如果其終端結點數爲n_0,度爲2的結點數爲n_2,則n_0=n_2+1

滿二叉樹:一棵深度爲k,且有(2的k次方)-1個節點成爲滿二叉樹。

完全二叉樹:深度爲k,有n個節點的二叉樹,當且僅當其每一個節點都與深度爲k的滿二叉樹中序號爲1至n的節點對應時,稱之爲完全二叉樹。



二叉樹的存儲結構:

順序存儲表示

一個存儲在數組中的完全二叉樹

二叉樹可以用數組或線性表來存儲,而且如果這是完全二叉樹,這種方法不會浪費空間。用這種緊湊排列,如果一個結點的索引爲i,它的子結點能在索引2i+1和2i+2找到,並且它的父節點(如果有)能在索引floor((i-1)/2)找到(假設根節點的索引爲0)。這種方法更有利於緊湊存儲和更好的訪問的局部性,特別是在前序遍歷中。然而,它需要連續的存儲空間,這樣在存儲高度爲hn個結點組成的一般普通樹時將會浪費很多空間。一種最極壞的情況下如果深度爲h的二叉樹每個節點只有右孩子需要佔用2的h次冪減1,而實際卻只有h個結點,空間的浪費太大,這是順序存儲結構的一大缺點。

二叉鏈表存儲表示

基於鏈表的二叉樹邏輯結構示意

在使用記錄內存地址指針的編程語言中,二叉樹通常用樹結點結構來存儲。有時也包含指向唯一的父節點的指針。如果一個結點的子結點個數小於2,一些子結點指針可能爲空值,或者爲特殊的哨兵結點。 使用鏈表能避免順序儲存浪費空間的問題,算法和結構相對簡單,但使用二叉鏈表,由於缺乏父鏈的指引,在找回父節點時需要重新掃描樹得知父節點的節點地址。

 typedef struct BiTNode
 {
   TElemType data;
   struct BiTNode *lchild,*rchild; /* 左右孩子指針 */
 }BiTNode,*BiTree;

二叉樹的基本操作

/* 按先序次序輸入二叉樹節點的值(可爲字符型或整型,在主程中定義),*/
   /* 構造二叉鏈表表示的二叉樹T。變量Nil表示空(子)樹。 */
 
void CreateBiTree(BiTree &T)
 { 
   TElemType ch;
   scanf(form, ch);
   if(ch == Nil) /* 空 */
     T = NULL;
   else
   {
     T = new BiTNode; /* 生成根結點*/
     if(NULL == T)
       exit(OVERFLOW);
     T->data=ch;
     CreateBiTree(T->lchild); /* 構造左子樹*/
     CreateBiTree(T->rchild); /* 構造右子樹*/
   }
 }


/*二叉樹的先、中、後序遍歷*/

void preOrder(BiTree root)
{
    if( root != NULL)
    {
        cout << root->data << ' ';
        preOrder(root->lchild);
        preOrder(root->rchild);
    }
}

void inOrder(BiTree root)
{
    if( root != NULL)
    {
        preOrder(root->lchild);
        cout << root->data << ' ';
        preOrder(root->rchild);
    }
}

void postOrder(BiTree root)
{
    if( root != NULL)
    {
        preOrder(root->lchild);
        preOrder(root->rchild);
        cout << root->data << ' ';
    }
}



/*求二叉樹的深度*/

int getDepth(BiTree root)
{
    int deplef = 0;
    int deprig = 0;
    int deptal = 0;

    if(root == NULL) return 0;

    deplef = getDepth(root->lchild) + 1;
    deprig = getDepth(root->rchild) + 1;
    deptal = deplef > deprig ? deplef:deprig;

    return deptal;
}

/*求二叉樹的葉子結點個數*/

int CountTreeLeaf(BiTree root)
{
    if(root == NULL)
        return 0;

    else if(root->lchild == NULL && root->rchild == NULL)
        return 1;
    else
        return CountTreeLeaf(root->lchild)+CountTreeLeaf(root->rchild);
}

待續。。。。。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章