樹的基本操作


一、關於樹:
 
 數的定義是遞歸的:
 定義樹是滿足以下條件的,包含至少一個結點的有限集合:
 
(1)樹中有一個特別指定的結點,稱為根,或樹根。
(2)其它結點划分成n>=0個不相交的集合T1…Tn ,每個集合又還是一棵樹,但稱為根的子樹。
     樹的主要操作包括:求樹的深度、求給定節點的子節點、兄弟節點、遍歷樹、插入子樹、刪除子樹等等。
     因為樹的定義本身就是遞歸的,所以在實際的程序中,很多操作也是通過遞歸來完成的。樹是如何表示的
     呢?有一種常用的表示方法,成為孩子、兄弟表示法,對於每個節點,通過孩子指針指向自己的子節點,
     通過兄弟指針指向自己右邊的兄弟。
 
二、樹的存儲方法:
 
雙親表示法(順序存儲)
孩子表示法(順序存儲與鏈式存儲結合)
孩子兄弟表示法/二叉樹表示法/二叉鏈表表示法(順序存儲與鏈式存儲結合)(左鏈域為該節點的第一個孩子,右鏈域為該節點的下一個兄弟)
 
三、基本操作:
 
//節點
typedef struct CSNode{
      char data;
      struct SCNode *firstchild,*nextsibling;
}TNode,*Tree;
 
 
構造樹與刪除樹,插入子樹與刪除子樹
 
1.構造樹
 
Tree InitTree(){
  Tree T=NULL;
  int ch;
  ch=getchar();
  if(ch!='#'){
       T=(Tree)malloc(sizeof(TNode));
       T->firstchild=NULL;
       T->nextsibling=NULL;
       T->data=ch;
  }
  return T;
}
 
 
 
2.插入子樹
 
Tree pos=NULL;     //標記子樹的父節點的位置
bool insertSubTree(Tree T,ElemType e,Tree Tadd)
{
    locateElem(T,e);     //查找到其父節點位置
    if(pos!= NULL)
    {
        Tadd->nextSibling=pos->firstChild;  //將新子樹根節點作為該節點的最左孩子
        pos->firstChild=Tadd;
        return true;
    }
    else
        return false;
}
 
3.刪除樹(調用刪除函數逐個刪除節點)
 
void deleteTree(Tree T){
    if(!T)
        return OK;
    else{
        deleteTree(T->firstchild);
        deleteTree(T->nextsibling);
        free(T);
        T=NULL;
    }
}
 
4.刪除子樹
 
Tree pos=NULL;//標記其父節點的位置
bool deleteSubTree(Tree T,ElemType e)
{
    locateElem(T,e);
 
    //先判斷pos是否有孩子節點
    if(pos->firstChild!=NULL)
    {
        deleteTree(pos->firstChild);   //調用刪除樹函數,刪除以該節點最左孩子為根節點的子樹
        return true;
    }
    else
        return false;
}
 
----------------------------------------------------------------------------------------
 
 遍歷樹
//先序遍歷
void TraverseTree(Tree T){
    if(T){
        visit(T->data);
        TreaverseTree(T->firstchild);
        TreaverseTree(T->nextsibling);
    }
    return 0;
}
//或者
void TraverseTree(Tree T){
    Tree p;
    if(T){
        visit(T->data);
        p=T->firstchild;
        while(!p){
            TreaverseTree(p);
            p=p->nextsiling;
        }
    }
    return 0;
}
------------------------------------------------------------------------------------------
查找某個節點x,查找左孩子,右兄弟
 
Tree p;   //用全局變量標記查找到的節點
Tree searchnode(Tree  &T,char ch){
    p=T;
    if(T){
        if(p->data==ch)
            return p;
        else{
            p=T->firstchild;
            while(p){
            searchnode(p->firstchild,ch);
            p=p->nextsibling;
            }
        }
   return Null;
}
 
1.查找某個節點的左孩子
 
Tree findChild(Tree T,ElemType e)
{
    searchnode(T,e);
    //如果沒有找到或者該節點是葉子節點,返回空
    if( p==NULL&&NULL==p->firstChild)
        return NULL;
    else
        return p->firstChild;
}
 
2.查找某個節點的右兄弟
 
Tree findSibling(Tree T,ElemType e)
{
    searchnode(T,e);
    //如果沒有找到或者該節點沒有右兄弟,返回空
    if(p==NULL&&p->nextSibling==NULL)
        return NULL;
    else
        return p->nextSibling;
}
 
------------------------------------------------------------------------------------------
求樹的高度
 
void TreeDepth(Tree T){
    int height=0,hmax=0;
    if(T){
      Tree p=T->firstchild;
      while(p){
         height=TreeDrpth(p);
         p=p->nextsibling;
         if(hmax
            hmax=height;
      }
   }
   return hmax+1;
}
--------------------------------------------------------------------------------------
 
 
 總結:對於樹的核心操作,毫無疑問是如何遞歸的遍歷一棵樹。我們的作法是這樣的:
對於一個節點,先訪問它的數據域,然后通過孩子指針來訪問它的孩子,一直到
沿着這條分支的葉子節點,此時,訪問這個節點的兄弟,直到所有的兄弟都訪問
過了,然后回退到上一節點,訪問它的兄弟,依次類推。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM