廣義表 (五)

5.1廣義表—廣義表的定義和基本運算html

 

顧名思義,廣義表是線性表的推廣。也有人稱其爲列表(Lists,用複數形式以示與統稱的表List 的區別)。

⒈廣義表的定義和性質


咱們知道,線性表是由n 個數據元素組成的有限序列。其中每一個組成元素被限定爲單元素,有時這種限制須要拓寬。例如,中國舉辦的某體育項目國際邀請賽,參賽隊清單可採用以下的表示形式:
(俄羅斯,巴西,(國家,河北,四川),古巴,美國,(),日本)

在這個拓寬了的線性表中,韓國隊應排在美國隊的後面,但因爲某種緣由未參加,成爲空表。國家隊、河北隊、四川隊均做爲東道主的參賽隊參加,構成一個小的線性表,成爲原線性表的一個數據項。這種拓寬了的線性表就是廣義表。

廣義表(Generalized Lists)是n(n≥0)個數據元素a1,a2,…,ai,…,an 的有序序列,通常記做:
ls=(a1,a2,…,ai,…,an)

其中:ls 是廣義表的名稱,n 是它的長度。每一個ai(1≤i≤n)是ls 的成員,它能夠是單個元素,也能夠是一個廣義表,分別稱爲廣義表ls 的單元素和子表。當廣義表ls 非空時,稱第一個元素a1 爲ls 的表頭(head),稱其他元素組成的表(a2,…,ai,…,an)爲ls 的表尾(tail)。顯然,廣義表的定義是遞歸的。

爲書寫清楚起見,一般用大寫字母表示廣義表,用小寫字母表示單個數據元素,廣義表用括號括起來,括號內的數據元素用逗號分隔開。下面是一些廣義表的例子:
A =()
B =(e)
C =(a,(b,c,d))
D =(A,B,C)
E =(a,E)
F =(())

⒉廣義表的性質


從上述廣義表的定義和例子能夠獲得廣義表的下列重要性質:

⑴廣義表是一種多層次的數據結構。廣義表的元素能夠是單元素,也能夠是子表,而子表的元素還能夠是子表,…。

⑵廣義表能夠是遞歸的表。廣義表的定義並無限制元素的遞歸,即廣義表也能夠是其自身的子表。例如表E 就是一個遞歸的表。

⑶廣義表能夠爲其餘表所共享。例如,表A、表B、表C 是表D 的共享子表。在D中能夠沒必要列出子表的值,而用子表的名稱來引用。


廣義表的上述特性對於它的使用價值和應用效果起到了很大的做用。

廣義表能夠當作是線性表的推廣,線性表是廣義表的特例。廣義表的結構至關靈活,在某種前提下,它能夠兼容線性表、數組、樹和有向圖等各類經常使用的數據結構。當二維數組的每行(或每列)做爲子表處理時,二維數組即爲一個廣義表。另外,樹和有向圖也能夠用廣義表來表示。因爲廣義表不只集中了線性表、數組、樹和有向圖等常見數據結構的特色,並且可有效地利用存儲空間,所以在計算機的許多應用領域都有成功使用廣義表的實例。

⒊廣義表基本運算


廣義表有兩個重要的基本操做,即取頭操做(Head)和取尾操做(Tail)。根據廣義表的表頭、表尾的定義可知,對於任意一個非空的列表,其表頭多是單元素也多是列表,而表尾必爲列表。例如:
Head(B)= e Tail(B)=()
Head(C)= a Tail(C)=((b,c,d))
Head(D)= A Tail(D)=(B,C)
Head(E)= a Tail(E)=(E)
Head(F)=() Tail(F)=()

此外,在廣義表上能夠定義與線性表相似的一些操做,如創建、插入、刪除、拆開、鏈接、複製、遍歷等。
CreateLists(ls):根據廣義表的書寫形式建立一個廣義表ls。
IsEmpty(ls):若廣義表ls 空,則返回True;不然返回False。
Length(ls):求廣義表ls 的長度。
Depth(ls):求廣義表ls 的深度。
Locate(ls,x):在廣義表ls 中查找數據元素x。
Merge(ls1,ls2):以ls1 爲頭、ls2 爲尾創建廣義表。
CopyGList(ls1,ls2):複製廣義表,即按ls1 創建廣義表ls2。
Head(ls):返回廣義表ls 的頭部。
Tail(ls):返回廣義表的尾部。
……

5.2廣義表—廣義表的存儲 數組

因爲廣義表中的數據元素能夠具備不一樣的結構,所以難以用順序的存儲結構來表示。而鏈式的存儲結構分配較爲靈活,易於解決廣義表的共享與遞歸問題,因此一般都採用鏈式的存儲結構來存儲廣義表。在這種表示方式下,每一個數據元素可用一個結點表示。

按結點形式的不一樣,廣義表的鏈式存儲結構又能夠分爲不一樣的兩種存儲方式。一種稱爲頭尾表示法,另外一種稱爲孩子兄弟表示法。

⒈頭尾表示法


若廣義表不空,則可分解成表頭和表尾;反之,一對肯定的表頭和表尾可唯一地肯定一個廣義表。頭尾表示法就是根據這一性質設計而成的一種存儲方法。

因爲廣義表中的數據元素既多是列表也多是單元素,相應地在頭尾表示法中結點的結構形式有兩種:一種是表結點,用以表示列表;另外一種是元素結點,用以表示單元素。

在表結點中應該包括一個指向表頭的指針和指向表尾的指針;而在元素結點中應該包括所表示單元素的元素值。爲了區分這兩類結點,在結點中還要設置一個標誌域,若是標誌爲1,則表示該結點爲表結點;若是標誌爲0,則表示該結點爲元素結點。其形式定義說明以下:
typedef enum {ATOM, LIST} Elemtag; /*ATOM=0:單元素;LIST=1:子表*/
typedef struct GLNode {
Elemtag tag; /*標誌域,用於區分元素結點和表結點*/
union { /*元素結點和表結點的聯合部分*/
datatype data; /*data 是元素結點的值域*/
struct {
struct GLNode *hp, *tp
}ptr; /*ptr 是表結點的指針域,ptr.hp 和ptr.tp 分別*/
/*指向表頭和表尾*/
};
}*GList; /*廣義表類型*/

頭尾表示法的結點形式如圖5.21 所示。

對於5.5.1 所列舉的廣義表A、B、C、D、E、F,若採用頭尾表示法的存儲方式,其存儲結構如圖5.22 所示。

從上述存儲結構示例中能夠看出,採用頭尾表示法容易分清列表中單元素或子表所在的層次。例如,在廣義表D 中,單元素a 和e 在同一層次上,而單元素b、c、d 在同一層次上且比a 和e 低一層,子表B 和C 在同一層次上。另外,最高層的表結點的個數即爲廣義表的長度。例如,在廣義表D 的最高層有三個表結點,其廣義表的長度爲3。

⒉孩子兄弟表示法


廣義表的另外一種表示法稱爲孩子兄弟表示法。在孩子兄弟表示法中,也有兩種結點形式:一種是有孩子結點,用以表示列表;另外一種是無孩子結點,用以表示單元素。在有孩子結點中包括一個指向第一個孩子(長子)的指針和一個指向兄弟的指針;而在無孩子結點中包括一個指向兄弟的指針和該元素的元素值。爲了能區分這兩類結點,在結點中還要設置一個標誌域。若是標誌爲1,則表示該結點爲有孩子結點;若是標誌爲0,則表示該結點爲無孩子結點。其形式定義說明以下:
typedef enum {ATOM, LIST} Elemtag; /*ATOM=0:單元素;LIST=1:子表*/
typedef struct GLENode {
Elemtag tag; /*標誌域,用於區分元素結點和表結點*/
union { /*元素結點和表結點的聯合部分*/
datatype data; /*元素結點的值域*/
struct GLENode *hp; /*表結點的表頭指針*/
};
struct GLENode *tp; /*指向下一個結點*/
}*EGList; /*廣義表類型*/
孩子兄弟表示法的結點形式如圖5.23 所示。

對於5.5.1 節中所列舉的廣義表A、B、C、D、E、F,若採用孩子兄弟表示法的存儲方式,其存儲結構如圖5.24 所示。

從圖5.24 的存儲結構示例中能夠看出,採用孩子兄弟表示法時,表達式中的左括號「(」對應存儲表示中的tag=1 的結點,且最高層結點的tp 域必爲NULL。

5.3 廣義表—廣義表基本操做的實現 數據結構

相關文章
相關標籤/搜索