數(shù)據(jù)結(jié)構(gòu)(七)數(shù)組和廣義表

數(shù)組

從本質(zhì)上講,數(shù)組與順序表、鏈表、棧和隊(duì)列一樣,都用來存儲具有 "一對一" 邏輯關(guān)系數(shù)據(jù)的線性存儲結(jié)構(gòu)。只因各編程語言都默認(rèn)將數(shù)組作為基本數(shù)據(jù)類型,使初學(xué)者對數(shù)組有了 "只是基本數(shù)據(jù)類型,不是存儲結(jié)構(gòu)" 的誤解。

數(shù)組結(jié)構(gòu)的實(shí)現(xiàn)使用的是順序存儲結(jié)構(gòu)。

根據(jù)數(shù)組中存儲數(shù)據(jù)之間邏輯結(jié)構(gòu)的不同,數(shù)組可細(xì)分為一維數(shù)組、二維數(shù)組、...、n 維數(shù)組:

  • 一維數(shù)組,指的是存儲不可再分?jǐn)?shù)據(jù)元素的數(shù)組,如圖 1 所示:
圖1:一維數(shù)組存儲結(jié)構(gòu)示意圖
  • 二維數(shù)組,指的存儲一維數(shù)組的一維數(shù)組,如圖 2 所示:


    圖2:二維數(shù)組示意圖
  • n維數(shù)組,指的是存儲n-1維數(shù)組的一維數(shù)組

注意:無論數(shù)組的維數(shù)是多少,數(shù)組中的數(shù)據(jù)類型都必須一致。


矩陣(稀疏矩陣)壓縮存儲(3種方式)

數(shù)據(jù)結(jié)構(gòu)中提供針對某些特殊矩陣的壓縮存儲結(jié)構(gòu),這里所說的特殊矩陣,主要分為以下兩類:

  • 1.含有大量相同元素的矩陣,比如對稱矩陣
  • 2.含有大量0元素的矩陣,比如稀疏矩陣、上(下)三角矩陣

針對以上兩類矩陣,數(shù)據(jù)結(jié)構(gòu)的壓縮存儲思想是:矩陣中的相同數(shù)據(jù)元素(包括元素 0)只存儲一個(gè)。

對稱矩陣

數(shù)據(jù)元素沿主對角線對應(yīng)相等,這類矩陣稱為對稱矩陣。

圖3:對稱矩陣示意圖

矩陣中有兩條對角線,其中圖 1 中的對角線稱為主對角線,另一條從左下角到右上角的對角線為副對角線。對稱矩陣指的是各數(shù)據(jù)元素沿主對角線對稱的矩陣。

我們可以使用一維數(shù)組存儲對稱矩陣。由于矩陣中沿對角線兩側(cè)的數(shù)據(jù)相等,因此數(shù)組中只需存儲對角線一側(cè)(包含對角線)的數(shù)據(jù)即可。

對稱矩陣的實(shí)現(xiàn)過程是,若存儲下三角中的元素,只需將各元素所在的行標(biāo) i 和列標(biāo) j 代入下面的公式:


圖4:下三角矩陣存儲位置計(jì)算

存儲上三角的元素要將各元素的行標(biāo) i 和列標(biāo) j 代入另一個(gè)公式:


圖5:上三角矩陣存儲位置計(jì)算

最終求得的 k 值即為該元素存儲到數(shù)組中的位置(矩陣中元素的行標(biāo)和列標(biāo)都從 1 開始)。

例如,在數(shù)組 skr[6] 中存儲圖 1 中的對稱矩陣,則矩陣的壓縮存儲狀態(tài)如圖 6 所示(存儲上三角和下三角的結(jié)果相同):


圖6 對稱矩陣壓縮示意圖

注意,以上兩個(gè)公式既是用來存儲矩陣中元素的,也用來從數(shù)組中提取矩陣相應(yīng)位置的元素。例如,如果想從圖 6 中的數(shù)組提取矩陣中位于 (3,1) 處的元素,由于該元素位于下三角,需用下三角公式獲取元素在數(shù)組中的位置,即:

圖7:元素對應(yīng)位置計(jì)算

結(jié)合圖 6,數(shù)組下標(biāo)為 3 的位置存儲的是元素 3,與圖 3 對應(yīng)。

上(下)三角矩陣

圖8:上下三角矩陣

主對角線下的數(shù)據(jù)元素全部為0的矩陣為上三角矩陣(圖 4a)),主對角線上元素全部為0的矩陣為下三角矩陣(圖 4b))。上(下)三角矩陣存儲元素和提取元素的過程和對稱矩陣相同。

稀疏矩陣

圖9:稀疏矩陣示意圖

壓縮存儲稀疏矩陣的方法是:只存儲矩陣中的非 0 元素,與前面的存儲方法不同,稀疏矩陣非 0 元素的存儲需同時(shí)存儲該元素所在矩陣中的行標(biāo)和列標(biāo)。

例如,存儲圖 9 中的稀疏矩陣,需存儲以下信息:

  • (1,1,1):數(shù)據(jù)元素為 1,在矩陣中的位置為 (1,1);
  • (3,3,1):數(shù)據(jù)元素為 3,在矩陣中的位置為 (3,1);
  • (5,2,3):數(shù)據(jù)元素為 5,在矩陣中的位置為 (2,3);
  • 除此之外,還要存儲矩陣的行數(shù) 3 和列數(shù) 3;

由此,可以成功存儲一個(gè)稀疏矩陣。


矩陣壓縮存儲的3種方式

對于以上 3 種特殊的矩陣,對稱矩陣和上下三角矩陣的實(shí)現(xiàn)方法是相同的,且實(shí)現(xiàn)過程比較容易,僅需套用上面給出的公式即可。

稀疏矩陣的壓縮存儲,數(shù)據(jù)結(jié)構(gòu)提供有3種具體實(shí)現(xiàn)方式:

  • 1.三元組順序表
  • 2.行邏輯鏈接的順序表
  • 3.十字鏈表

三元組順序表

圖 9 是一個(gè)稀疏矩陣,若對其進(jìn)行壓縮存儲,矩陣中各非 0 元素的存儲狀態(tài)如圖 10 所示:


圖10 稀疏矩陣壓縮存儲示意圖

圖10存儲的是三元組(即由 3 部分?jǐn)?shù)據(jù)組成的集合),組中數(shù)據(jù)分別表示(行標(biāo),列標(biāo),元素值)。

public class Triple {
    int i; //行標(biāo)i
    int j; //列標(biāo)j
    int data;   //元素值
}

public class TSMatrix{
    int n; // 矩陣行數(shù)
    int m; // 矩陣列數(shù)
    int num; // 矩陣有效數(shù)據(jù)數(shù)量
    Triple[] triple = new Triple[num];//矩陣3元組元素
}

行邏輯鏈接順序表

三元組順序表每次提取指定元素都需要遍歷整個(gè)數(shù)組,運(yùn)行效率很低。
行邏輯鏈接的順序表。它可以看作是三元組順序表的升級版,即在三元組順序表的基礎(chǔ)上改善了提取數(shù)據(jù)的效率。

圖11:稀疏矩陣示意圖

圖 11 是一個(gè)稀疏矩陣,當(dāng)使用行邏輯鏈接的順序表對其進(jìn)行壓縮存儲時(shí),需要做以下兩個(gè)工作:

  • 將矩陣中的非 0 元素采用三元組的形式存儲到一維數(shù)組 data 中,如圖 2 所示(和三元組順序表一樣):


    圖12:三元組存儲稀疏矩陣

使用數(shù)組 rpos 記錄矩陣中每行第一個(gè)非 0 元素在一維數(shù)組中的存儲位置。如圖 13 所示:


圖13:存儲各行首個(gè)非0元素在[圖11]數(shù)組中的位置

通過以上兩步操作,即實(shí)現(xiàn)了使用行邏輯鏈接的順序表存儲稀疏矩陣。
此時(shí),如果想從行邏輯鏈接的順序表中提取元素,則可以借助 rpos 數(shù)組提高遍歷數(shù)組的效率。

例如,提取圖 11 稀疏矩陣中的元素 2 的過程如下:

  • 由 rpos 數(shù)組可知,第一行首個(gè)非 0 元素位于data[1],因此在遍歷此行時(shí),可以直接從第 data[1] 的位置開始,一直遍歷到下一行首個(gè)非 0 元素所在的位置(data[3])之前

十字鏈表法

對于壓縮存儲稀疏矩陣,無論是使用三元組順序表還是使用行邏輯鏈接的順序表,歸根結(jié)底是使用數(shù)組存儲稀疏矩陣。介于數(shù)組 "不利于插入和刪除數(shù)據(jù)" 的特點(diǎn),以上兩種壓縮存儲方式都不適合解決類似 "向矩陣中添加或刪除非 0 元素" 的問題。

十字鏈表法存儲稀疏矩陣,該存儲方式采用的是 "鏈表+數(shù)組" 結(jié)構(gòu),如圖14所示:


圖14:十字鏈表示意圖

可以看到,使用十字鏈表壓縮存儲稀疏矩陣時(shí),矩陣中的各行各列都各用一各鏈表存儲,與此同時(shí),所有行鏈表的表頭存儲到一個(gè)數(shù)組(rhead),所有列鏈表的表頭存儲到另一個(gè)數(shù)組(chead)中。

因此,各個(gè)鏈表中節(jié)點(diǎn)的結(jié)構(gòu)應(yīng)如圖15 所示:


圖15:十字鏈表節(jié)點(diǎn)結(jié)構(gòu)

兩個(gè)指針域分別用于鏈接所在行的下一個(gè)元素以及所在列的下一個(gè)元素。


矩陣(稀疏矩陣)的轉(zhuǎn)置算法

矩陣的轉(zhuǎn)置,即互換矩陣中所有元素的行標(biāo)和列標(biāo),如圖16所示:


圖16:矩陣轉(zhuǎn)置示意圖

但如果想通過程序?qū)崿F(xiàn)矩陣的轉(zhuǎn)置,互換行標(biāo)和列標(biāo)只是第一步。因?yàn)閷?shí)現(xiàn)矩陣轉(zhuǎn)置的前提是將矩陣存儲起來,數(shù)據(jù)結(jié)構(gòu)中提供了 3 種存儲矩陣的結(jié)構(gòu),分別是三元組順序表、行邏輯鏈接的順序表十字鏈表。如果采用前兩種結(jié)構(gòu),矩陣的轉(zhuǎn)置過程會涉及三元組表也跟著改變的問題,如圖 2 所示:

圖17:三元組表的變化

圖 2a) 表示的是圖 1 中轉(zhuǎn)置之前矩陣的三元組表,2b) 表示的是圖 1 中矩陣轉(zhuǎn)置后對應(yīng)的三元組表。由此發(fā)現(xiàn),三元組順序表中數(shù)組的位置發(fā)生了變化。
不僅如此,如果矩陣的行數(shù)和列數(shù)不等,也需要將它們互換。

因此通過以上分析,矩陣轉(zhuǎn)置的實(shí)現(xiàn)過程需完成以下 3 步:

  • 1.將矩陣的行數(shù)和列數(shù)互換
  • 2.將三元組表(存儲矩陣)中的 i 列和 j 列互換,實(shí)現(xiàn)矩陣的轉(zhuǎn)置
  • 3.以 j 為序列,重新排列三元組表中存儲各三元組的先后順序

此 3 步中,前兩步比較簡單,關(guān)鍵在于最后一步的實(shí)現(xiàn)。

矩陣轉(zhuǎn)置的實(shí)現(xiàn)思路是:不斷遍歷存儲矩陣的三元組表,每次都取出表中 j 列最小的那一個(gè)三元組,互換行標(biāo)和列標(biāo)的值,并按次序存儲到一個(gè)新三元組表中。

例如,將圖 2a) 三元組表存儲的矩陣進(jìn)行轉(zhuǎn)置的過程為:

  • 1.新建一個(gè)三元組表(用于存儲轉(zhuǎn)置矩陣),并將原矩陣的行數(shù)和列數(shù)互換賦值給新三元組;

  • 2.遍歷三元組表,找到表中 j 列最小值 1 所在的三元組 (3,1,6),然后將其行標(biāo)和列標(biāo)互換后添加到一個(gè)新的三元組表中,如圖 18 所示:


    圖18:矩陣轉(zhuǎn)置的第一個(gè)過程
  • 3.繼續(xù)遍歷三元組表,找到表中 j 列次小值為 2 的三元組,分別為 (1,2,1)、(2,2,3) 和 (3,2,5),根據(jù)找到它們的先后次序?qū)⒏髯缘男袠?biāo)和列標(biāo)互換后添加到新三元組表中,如圖 19 所示:


    圖19:矩陣轉(zhuǎn)置的第二個(gè)過程

對比圖 19 和圖 2b) 可以看到,矩陣被成功地轉(zhuǎn)置。
由于此算法中需要嵌套使用了兩個(gè) for 循環(huán),時(shí)間復(fù)雜度為 O(n2)。


稀疏矩陣的快速轉(zhuǎn)置算法

稀疏矩陣快速轉(zhuǎn)置算法和普通算法的區(qū)別僅在于第 3 步,快速轉(zhuǎn)置能夠做到遍歷一次三元組表即可完成第 3 步的工作。
稀疏矩陣的快速轉(zhuǎn)置是這樣的,在普通算法的基礎(chǔ)上增設(shè)兩個(gè)數(shù)組(假
設(shè)分別為 array 和 copt):

  • array 數(shù)組負(fù)責(zé)記錄原矩陣每一列非 0 元素的個(gè)數(shù)。以圖 1 為例,則對應(yīng)的 array 數(shù)組如圖 20 所示:
    圖20:每一列非0元素的個(gè)數(shù)

    圖 2 中 array 數(shù)組表示,原稀疏矩陣中第一列有 1 個(gè)非 0 元素,第二列有 2 個(gè)非 0 元素。
  • copt 數(shù)組用于計(jì)算稀疏矩陣中每列第一個(gè)非 0 元素在新三元組表中存放的位置。
    我們通常默認(rèn)第一列首個(gè)非 0 元素存放到新三元組表中的位置為 1,然后通過 cpot[col] = cpot[col-1] + array[col-1] 公式可計(jì)算出后續(xù)各列首個(gè)非 0 元素存放到新三元組表的位置。拿圖 1 中的稀疏矩陣來說,它對應(yīng)的 copt 數(shù)組如圖 21 所示:


    圖21:copt數(shù)組示意圖

    圖 21 中的 copt 數(shù)組表示,原稀疏矩陣中第 2 列首個(gè)非 0 元素存放到新三元組表的位置為 2。

注意,cpot[col] = cpot[col-1] + array[col-1] 的意思是,后一列首個(gè)非 0 元素存放的位置等于前一列首個(gè)非 0 元素的存放位置,加上該列非 0 元素的個(gè)數(shù)。由此可以看出,copt 數(shù)組才是最終想要的,而 array 數(shù)組的設(shè)立只是為了幫助我們得到 copt 數(shù)組。

//具體代碼省略

稀疏矩陣快速轉(zhuǎn)置算法的時(shí)間復(fù)雜度為 O(n)。即使在最壞的情況下(矩陣中全部都是非 0 元素),該算法的時(shí)間復(fù)雜度也才為 O(n2)。


矩陣乘法

矩陣相乘的前提條件是:乘號前的矩陣的數(shù)要和乘號后的矩陣的數(shù)相等。且矩陣的乘法運(yùn)算沒有交換律,即 AB 和 BA 是不一樣的。假設(shè)下面是矩陣A:

3 0 0 5
0 -1 0 0
2 0 0 0

下面是矩陣B:

0 2
1 0
-2 4
0 0

由于矩陣 A 的列數(shù)和矩陣 B 的行數(shù)相等,可以進(jìn)行 AB 運(yùn)算(不能進(jìn)行 BA 運(yùn)算)。計(jì)算方法是:用矩陣 A 的第 i 行和矩陣 B 中的每一列 j 對應(yīng)的數(shù)值做乘法運(yùn)算,乘積一一相加,所得結(jié)果即為矩陣 C 中第 i 行第 j 列的值。

例如:C12 = 6 是因?yàn)椋篈11B12 + A12B22 + A13B32 + A14B42,即 32 + 00 + 04 + 50 = 6 ,因?yàn)檫@是 A 的第 1 行和 B的第 2 列的乘積和,所以結(jié)果放在 C 的第 1 行第 2 列的位置。

結(jié)果矩陣C為:

0 6
-1 0
0 4

例如,A 是 m1n1 矩陣,B 是 m2n2 矩陣(前提必須是 n1 == m2 ):
普通算法的時(shí)間復(fù)雜度為 O(m1*n2*n1)

基于行邏輯鏈接的順序表的矩陣乘法

具體過程不描述,請自行百度,這里只說結(jié)論。

當(dāng)稀疏矩陣 Amn 和稀疏矩陣 Bnp 采用行邏輯鏈接的順序表做乘法運(yùn)算時(shí),在矩陣 A 的列數(shù)(矩陣 B 的行數(shù)) n 不是很大的情況下,算法的時(shí)間復(fù)雜度相當(dāng)于 O(m*p),比普通算法要快很多


矩陣加法

矩陣之間能夠進(jìn)行加法運(yùn)算的前提條件是:各矩陣的行數(shù)和列數(shù)必須相等。

在行數(shù)和列數(shù)都相等的情況下,矩陣相加的結(jié)果就是矩陣中對應(yīng)位置的值相加所組成的矩陣,例如:


圖22:矩陣相加

十字鏈表法
過程有點(diǎn)復(fù)雜,具體請自行百度,這里只說結(jié)論
使用十字鏈表法解決稀疏矩陣的壓縮存儲的同時(shí),在解決矩陣相加的問題中,對于某個(gè)單獨(dú)的結(jié)點(diǎn)來說,算法的時(shí)間復(fù)雜度為一個(gè)常數(shù)(全部為選擇結(jié)構(gòu)),算法的整體的時(shí)間復(fù)雜度取決于兩矩陣中非 0 元素的個(gè)數(shù)。


廣義表

數(shù)組即可以存儲不可再分的數(shù)據(jù)元素(如數(shù)字 5、字符 'a'),也可以繼續(xù)存儲數(shù)組(即 n 維數(shù)組)。

但需要注意的是,以上兩種數(shù)據(jù)存儲形式絕不會出現(xiàn)在同一個(gè)數(shù)組中。例如,我們可以創(chuàng)建一個(gè)整形數(shù)組去存儲 {1,2,3},我們也可以創(chuàng)建一個(gè)二維整形數(shù)組去存儲 {{1,2,3},{4,5,6}},但數(shù)組不適合用來存儲類似 {1,{1,2,3}} 這樣的數(shù)據(jù)。

有人可能會說,創(chuàng)建一個(gè)二維數(shù)組來存儲{1,{1,2,3}}。在存儲上確實(shí)可以實(shí)現(xiàn),但無疑會造成存儲空間的浪費(fèi)。

對于存儲 {1,{1,2,3}} 這樣的數(shù)據(jù),更適合用廣義表結(jié)構(gòu)來存儲。
廣義表,又稱列表,也是一種線性存儲結(jié)構(gòu)。

同數(shù)組類似,廣義表中既可以存儲不可再分的元素,也可以存儲廣義表,記作:

LS = (a1,a2,…,an)

其中,LS 代表廣義表的名稱,an 表示廣義表存儲的數(shù)據(jù)。廣義表中每個(gè) ai 既可以代表單個(gè)元素,也可以代表另一個(gè)廣義表。

原子和子表

通常,廣義表中存儲的單個(gè)元素稱為 "原子",而存儲的廣義表稱為 "子表"。

以下是廣義表存儲數(shù)據(jù)的一些常用形式:

  • A = ():A 表示一個(gè)廣義表,只不過表是空的。
  • B = (e):廣義表 B 中只有一個(gè)原子 e。
  • C = (a,(b,c,d)) :廣義表 C 中有兩個(gè)元素,原子 a 和子表 (b,c,d)。
  • D = (A,B,C):廣義表 D 中存有 3 個(gè)子表,分別是A、B和C。這種表示方式等同于 D = ((),(e),(b,c,d)) 。
  • E = (a,E):廣義表 E 中有兩個(gè)元素,原子 a 和它本身。這是一個(gè)遞歸廣義表,等同于:E = (a,(a,(a,…)))。

注意,A = () 和 A = (()) 是不一樣的。前者是空表,而后者是包含一個(gè)子表的廣義表,只不過這個(gè)子表是空表。

廣義表的表頭和表尾

當(dāng)廣義表不是空表時(shí),稱第一個(gè)數(shù)據(jù)(原子或子表)為"表頭",剩下的數(shù)據(jù)構(gòu)成的新廣義表為"表尾"。

強(qiáng)調(diào)一下,除非廣義表為空表,否則廣義表一定具有表頭和表尾,且廣義表的表尾一定是一個(gè)廣義表。

例如在廣義表中 LS={1,{1,2,3},5} 中,表頭為原子 1,表尾為子表 {1,2,3} 和原子 5 構(gòu)成的廣義表,即 {{1,2,3},5}。

再比如,在廣義表 LS = {1} 中,表頭為原子 1 ,但由于廣義表中無表尾元素,因此該表的表尾是一個(gè)空表,用 {} 表示。

廣義表的存儲結(jié)構(gòu)

由于廣義表中既可存儲原子(不可再分的數(shù)據(jù)元素),也可以存儲子表,因此很難使用順序存儲結(jié)構(gòu)表示,通常情況下廣義表結(jié)構(gòu)采用鏈表實(shí)現(xiàn)。

使用鏈表存儲廣義表,首先需要確定鏈表中節(jié)點(diǎn)的結(jié)構(gòu)。由于廣義表中可同時(shí)存儲原子和子表兩種形式的數(shù)據(jù),因此鏈表節(jié)點(diǎn)的結(jié)構(gòu)也有兩種,如圖23 所示:


圖23:廣義表節(jié)點(diǎn)的兩種類型

如圖 23所示,表示原子的節(jié)點(diǎn)由兩部分構(gòu)成,分別是 tag 標(biāo)記位和原子的值,表示子表的節(jié)點(diǎn)由三部分構(gòu)成,分別是 tag 標(biāo)記位、hp 指針和 tp 指針。

tag 標(biāo)記位用于區(qū)分此節(jié)點(diǎn)是原子還是子表,通常原子的 tag 值為 0,子表的 tag 值為 1。子表節(jié)點(diǎn)中的 hp 指針用于連接本子表中存儲的原子或子表,tp 指針用于連接廣義表中下一個(gè)原子或子表。

例如,廣義表 {a,{b,c,d}} 是由一個(gè)原子 a 和子表 {b,c,d} 構(gòu)成,而子表 {b,c,d} 又是由原子 b、c 和 d 構(gòu)成,用鏈表存儲該廣義表如圖 24 所示:


圖24:廣義表{a,{b,c,d}}的結(jié)構(gòu)示意圖

另一種廣義表存儲結(jié)構(gòu)

如果你覺得圖 24 這種存儲廣義表的方式不合理,可以使用另一套表示廣義表中原子和子表結(jié)構(gòu)的節(jié)點(diǎn),如圖 25 所示:

圖25:廣義表的另一套節(jié)點(diǎn)結(jié)構(gòu)

采用圖 25 中的節(jié)點(diǎn)結(jié)構(gòu)存儲廣義表 {a,{b,c,d}} 的示意圖如圖 26 所示:


圖26:廣義表{a,{b,c,d}}的結(jié)構(gòu)示意圖

廣義表的深度和長度

廣義表的長度

由于廣義表中可以同時(shí)存儲原子和子表兩種類型的數(shù)據(jù),因此在計(jì)算廣義表的長度時(shí)規(guī)定,廣義表中存儲的每個(gè)原子算作一個(gè)數(shù)據(jù),同樣每個(gè)子表也只算作是一個(gè)數(shù)據(jù)。

前面我們用 LS={a1,a2,...,an} 來表示一個(gè)廣義表,其中每個(gè) ai 都可用來表示一個(gè)原子或子表,其實(shí)它還可以表示廣義表 LS 的長度為 n。

廣義表規(guī)定,空表 {} 的長度為 0

廣義表的存儲使用的是鏈表結(jié)構(gòu),且有以下兩種方式(如圖 1 所示):

圖27:廣義表存儲{a,{b,c,d}}的兩種方式

對于圖 a) 來說,只需計(jì)算最頂層(紅色標(biāo)注)含有的節(jié)點(diǎn)數(shù)量,即可求的廣義表的長度。

對于圖 b) 來說,由于其最頂層(藍(lán)色標(biāo)注)表示的此廣義表,而第二層(紅色標(biāo)注)表示的才是該廣義表中包含的數(shù)據(jù)元素,因此可以通過計(jì)算第二層中包含的節(jié)點(diǎn)數(shù)量,即可求得廣義表的長度。


廣義表的深度

廣義表的深度,可以通過觀察該表中所包含括號的層數(shù)間接得到。


圖28:廣義表示意圖

從圖 28 中可以看到,此廣義表從左往右數(shù)有兩層左括號(從右往左數(shù)也是如此),因此該廣義表的深度為 2。

編寫程序計(jì)算廣義表的深度時(shí),可以采用遞歸的方式:

  • 1.依次遍歷廣義表 C 的每個(gè)節(jié)點(diǎn),若當(dāng)前節(jié)點(diǎn)為原子(tag 值為 0),則返回 0;若為空表,則返回 1;反之,則繼續(xù)遍歷該子表中的數(shù)據(jù)元素。

  • 2.設(shè)置一個(gè)初始值為 0 的整形變量 max,每次遞歸過程返回時(shí),令 max 與返回值進(jìn)行比較,并取較大值。這樣,當(dāng)整個(gè)廣義表遞歸結(jié)束時(shí),max+1 就是廣義表的深度。


廣義表的復(fù)制

對于任意一個(gè)非空廣義表來說,都是由兩部分組成:表頭和表尾。反之,只要確定的一個(gè)廣義表的表頭和表尾,那么這個(gè)廣義表就可以唯一確定下來。

復(fù)制一個(gè)廣義表,也是不斷的復(fù)制表頭和表尾的過程。如果表頭或者表尾同樣是一個(gè)廣義表,依舊復(fù)制其表頭和表尾。

所以,復(fù)制廣義表的過程,其實(shí)就是不斷的遞歸,復(fù)制廣義表中表頭和表尾的過程。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 避免失敗的關(guān)鍵在于要用系統(tǒng),而不要用分量;要以整體,而不要以局部的方式進(jìn)行思維。 我們的思維模式中有一些傾向,如一...
    白鯨閱讀 1,071評論 0 1
  • 何為人? 亼。 可否具體? 忈。 可否再具體? 囚。
    李大摳腳閱讀 123評論 0 0
  • “要你姐姐拿個(gè)大桶過來我們家接水回去吃!”媽媽一臉認(rèn)真地跟我說。我讓她別開玩笑,自家的水吃了那么長時(shí)間,也沒覺得有...
    麥子飛呀飛閱讀 244評論 0 0

友情鏈接更多精彩內(nèi)容