樹的存儲結構


存儲結構表示方式:雙親表示法,孩子表示法,孩子兄弟表示法。

一、雙親表示法:

以雙親作為索引的關鍵詞的一種存儲方式

除根結點外,每個結點只有一個雙親,所以選擇順序存儲占主要
以一組連續空間存儲樹的結點,同時在每個結點中,附設一個指示其雙親結點位置的指針域

1、結點結構:

 2、結點結構定義:

 

/*樹的雙親表示法結點結構定義*/
#define MAX_TREE_SIZE 100

typedef int TElemType;

typedef struct PTNode //結點結構
{
    TElemType data;   //結點數據
    int parent;       //雙親位置
}PTNode;

typedef struct        //樹結構
{
    PTNode nodes[MAX_TREE_SIZE];   //結點數組
    int r, n;                      //r是根位置,n是結點數
}PTree;

優點:parent指針域指向數組下標,所以找雙親結點的時間復雜度為O(1),向上一直找到根節點也快

缺點:由上向下找就十分慢,若要找結點的孩子或者兄弟,要遍歷整個樹

 3、改進一:方便獲取孩子結點

在雙親結點基礎上加入孩子結點位置,由於可能一個結點有多個子樹,所以我們要根據樹的度來設置添加幾個孩子結點的元素

樹的度為3,所以我們在結點結構設置上添加3個指針域,指向孩子結點,若是孩子為空則位置為-1。

#define MAX_TREE_SIZE 100

typedef int TElemType;

typedef struct PTNode   //結點結構
{
    TElemType data;     //結點數據
    int parent;         //雙親位置
    int child1;         //孩子1
    int child2;         //孩子2 
    int child3;         //孩子3
}PTNode;

typedef struct  //樹結構
{
    PTNode nodes[MAX_TREE_SIZE];   //結點數組
    int r, n;                      //r是根位置,n是結點數
}PTree;

 

 

 缺點:這樣消耗了大量的空間,是不必要的,我們盡可能使用較小的空間,所以我們一般只添加一個長子域,可以獲取到有0個或1個孩子結點,注意:長子域是最左邊孩子的域。

#define MAX_TREE_SIZE 100

typedef int TElemType;

typedef struct PTNode   //結點結構
{
    TElemType data;     //結點數據
    int parent;         //雙親位置
    int firstchild;     //長子域
}PTNode;

typedef struct  //樹結構
{
    PTNode nodes[MAX_TREE_SIZE];   //結點數組
    int r, n;                      //r是根位置,n是結點數
}PTree;

 

4.改進二:方便獲取各兄弟之間的關系

我們只需要增加一個有兄弟域,即可依次獲取所有的兄弟結點

#define MAX_TREE_SIZE 100

typedef int TElemType;

typedef struct PTNode   //結點結構
{
    TElemType data;     //結點數據
    int parent;         //雙親位置
    int rightsib;       //右兄弟結點
}PTNode;

typedef struct  //樹結構
{
    PTNode nodes[MAX_TREE_SIZE];   //結點數組
    int r, n;                      //r是根位置,n是結點數
}PTree;

 

存儲結構的設計是一個十分靈活的過程。一個存儲結構設計是否合理,取決於基於該存儲結構的運算是否合適,方便,時間復雜度好不好等。

例如若是我們既關注孩子又關注兄弟,而且對時間遍歷要求高,那么我們可以擴展上面結構含有雙親域,長子域,右兄弟域

二、孩子表示法

由於每個結點可有多個子樹(無法確定子樹個數),可以考慮使用多重鏈表來實現。

根據樹的度來設置孩子域的個數,例如本例中度為3,設置3個孩子域

#define MAX_TREE_SIZE 100

typedef int TElemType;

typedef struct PTNode   //結點結構
{
    TElemType data;     //結點數據
    int child1;         //孩子1
    int child2;         //孩子2 
    int child3;         //孩子3
}PTNode;

typedef struct  //樹結構
{
    PTNode nodes[MAX_TREE_SIZE];   //結點數組
    int r, n;                      //r是根位置,n是結點數
}PTree;

 

 

與雙親表示法中的改進1->表示法非常相似,只是孩子表示法注重結點的孩子。 

缺點:占用了大量不必要的孩子域空指針。以其為標准:需要3n個指針域,實際上有用n-1個(除了根節點,其他n-1個都向上需要一條邊),則有2n+1個無用,浪費

改進一:為每個結點添加一個結點度域,方便控制指針域的個數

 

 缺點:維護困難,不易實現。

改進二:結合順序結構和鏈式結構

 

#define MAX_TREE_SIZE 100

typedef int TElemType;

typedef struct CTNode   //孩子結點
{
    TElemType child;     
    struct CTNode* next;
}*ChildPtr;

typedef struct          //表頭結構 
{
    TElemType data;
    ChildPtr firstchild; //頭指針,指向第一個孩子結點
}CTBox;

typedef struct  
{
    CTBox nodes[MAX_TREE_SIZE];   //結點數組
    int r, n;                      //r是根位置,n是結點數
}CTree;

 

改進三:添加雙親域,方便查找雙親結點(雙親孩子表示法)

 

#define MAX_TREE_SIZE 100

typedef int TElemType;

typedef struct CTNode   //孩子結點
{
    TElemType child;     
    struct CTNode* next;
}*ChildPtr;

typedef struct          //表頭結構 
{
    TElemType data;
    int parent;
    ChildPtr firstchild; //頭指針,指向第一個孩子結點
}CTBox;

typedef struct  
{
    CTBox nodes[MAX_TREE_SIZE];   //結點數組
    int r, n;                      //r是根位置,n是結點數
}CTree;

 

三、孩子兄弟表示法

上面從雙親,孩子角度研究樹的結構,下面我們從樹的結點的兄弟角度來研究。任意一棵樹,他的結點的第一個孩子如果存在就是唯一結點,他的右兄弟如果存在,也是唯一的,因此,我們設置兩個指針,分別指向該結點的第一個孩子和該結點的右兄弟。

n個結點,有2n個指針域,有n-1條邊,空n+1個指針域 

typedef int TElemType;

typedef struct CSNode
{
    TElemType data;
    struct CSNode* firstchild, rightsib;
}CSNode,*CSTree;

若有需要,可以再加入一個雙親域。

 

 


免責聲明!

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



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