1. 程式人生 > >廣義表C/C++實現詳解

廣義表C/C++實現詳解

所謂的廣義表就是單鏈表的擴充套件,就是節點可以是一個元素也可以是一個連結串列。官方的說法是,原子節點和子表節點。廣義表用遞迴的方法來建立是最簡單易懂的,也符合廣義表的思想。

C程式碼實現下載
C++程式碼實現下載
(備用下載地址 )

1.廣義表的各種形態

(1)、A = (); 空表
(2)、B = (()); 長度為1,深度為2,原子個數為0,這個實質上就是廣義表中有一個元素,它是子表,該子表為空。
(3)、C = (a); 長度為1,深度為0,原子個數為1
(4)、D = (a,A,b);長度為3,深度為2,原子個數為2,其中A是一個空表。
(5)、E = (A,B,C,D);長度為4,深度為3,原子個數為3,其中ABCD都是表。
(6)、F = (a,F); 無限遞迴下去。

2.廣義表C語言實現思路

先來看結構體定義

enum NodeType { ATOM, LIST };

typedef struct _GList
{
    NodeType nodeType;   //節點型別
    union
    {
        char c;          //原子 
        _GList* subList; //子表
    };
    _GList* next;       //指向後繼節點
}GList, *PGList;

(1)建立表
給定一個串,該串必須遵守相關規則,例如,層次分隔符用‘()’,元素分隔符用‘,’。

虛擬碼描述如下:

Create(PGList* gl,char* s)
{
    如果s="()",則(*gl)=NULL
    如果s='(',則遞迴建立子表,Create(&(*gl)->subList,s);
    否則建立原子節點

    如果s=',',則遞迴建立後繼節點(該節點可能是ATOMLISTCreate(&(*gl)->next,s);
    如果s=')',則置(*gl)->next為NULL,表示該子表已經結束
    如果s='\0',則置(*gl)->next為NULL,表示該廣義表已經建立完成
}

重點!!! :為什麼這裡要傳進去二級指標?剛開始我傳進一級指標的時候,我發現建立完成後,gl = NULL,為什麼?因為沒有一個變數記錄gl第一個節點的地址啊,所以最後找不到它了。這時候就需要一個二級指標,指向該頭節點的地址。如圖:

(2)計算廣義表長度
這個就比較簡單了,就和單鏈表一樣,依次遍歷第一層節點即可。
需要注意的是,因為建立廣義表的時候,一開始就建立了一個子表節點,所以該節點才是廣義表的頭節點。

(3)計算廣義表深度
遞迴遍歷子表,取子表深度最大值。例如:(A,(B,C),(D,E,(F,G)),H)
此時最大深度在(F,G)這個子表處得到。

(4)新增原子到廣義表前面或後面
這個操作和單鏈表的操作是一樣的,廣義表如果要實現更深層次的插入和新增會比較麻煩。

(5)列印廣義表
一樣的遞迴遍歷,若是原子節點,則直接輸出,所示子表節點,則遞迴進去。

2.廣義表C++實現思路

廣義表的節點類如下:

enum NodeType { ATOM, LIST };   //節點型別
private:
    class Node   //廣義表結點類
    {
    public:
        Node(NodeType nodeType, T atom)
            :nodeType(nodeType), atom(atom) {}
    private:
        NodeType nodeType;      //節點型別
        union
        {
            T atom;             //原子
            Node* subList;      //子表
        };
        Node* next;             //指向下一個元素
        friend class GList;
    };

和C語言類似。

只不過C++我用模板實現,這樣就能儲存字元、整形、浮點型了。
基本思路和C語言類似,所以,我一般都是用C語言實現了簡單的功能,然後用C++封裝成一個完善的類。這裡省略對C++的描述,具體看程式碼,裡面有註釋。