數據結構 第五章 數組與廣義表_第1頁
數據結構 第五章 數組與廣義表_第2頁
數據結構 第五章 數組與廣義表_第3頁
數據結構 第五章 數組與廣義表_第4頁
數據結構 第五章 數組與廣義表_第5頁
已閱讀5頁,還剩41頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第五章數組和廣義表5.1數組的定義5.2數組的順序表示和實現5.3矩陣的壓縮存儲

5.3.1特殊矩陣

5.3.2稀疏矩陣5.4廣義表的定義5.5廣義表的存儲結構數組和廣義表可看成是一種特殊的線性表,其特殊在于,表中的所有元素本身也是一種線性表。數組是我們最熟悉的數據類型,在早期的高級語言中,數組是唯一可供使用的數據類型。由于數組中各元素具有統一的類型,并且數組元素的下標一般具有固定的上界和下界,因此,數組的處理比其它復雜的結構更為簡單。多維數組是向量的推廣。例如,二維數組:5.1數組的定義二維數組可以看成是由行向量組成的向量,也可以看成是列向量組成的向量。同樣,可把三維數組看成是一個線性表,表中每一個數組元素為一個二維數組。依次類推,可把n維數組看成是一個線性表,表中每一個數據元素是一個n-1維數組。數組的運算:數組一旦被定義,它的維數和維界就不再改變。因此,除了結構的初始化和銷毀之外,數組只有存取元素和修改元素值的操作。即給定一組下標,存取或修改相應的數組元素。5.1數組的定義1、順序存儲結構5.2數組的順序表示和實現順序存儲結構:用一組地址連續的存儲單元依次存放數據元素,稱為數組的順序存儲結構。由于計算機的內存結構是一維的,因此用一維內存來表示多維數組,就必須按某種次序將數組元素排成一列序列,然后將這個線性序列存放在存儲器中。由于對數組一般不做插入和刪除操作,也就是說,數組一旦建立,結構中的元素個數和元素間的關系就不再發生變化。因此,一般都是采用順序存儲的方法來表示數組。

通常有兩種順序存儲方式:2、順序存儲方式⑴行優先順序——將數組元素按行排列,第i+1個行向量緊接在第i個行向量后面。以二維數組為例,按行優先順序存儲的線性序列為:a11,a12,…,a1n,a21,a22,…a2n,……,am1,am2,…,amn

在PASCAL、C語言中,數組就是按行優先順序存儲的。⑵列優先順序——將數組元素按列向量排列,第j+1個列向量緊接在第j個列向量之后,A的m*n個元素按列優先順序存儲的線性序列為:a11,a21,…,am1,a12,a22,…am2,……,a1n,a2n,…,amn在FORTRAN語言中,數組就是按列優先順序存儲的。

a11a12……..a1n

a21a22……..a2n

am1am2……..amn

….Loc(aij)=Loc(a11)+[(i-1)n+(j-1)]*l

按行序為主序存放

amn

……..

am2am1……….a2n

……..

a22a21a1n

…….a12

a1101n-1m*n-1n

按列序為主序存放01m-1m*n-1m

amn

……..

a2n

a1n……….

am2

……..

a22

a12

am1

…….

a21

a11

a11

a12

……..

a1n

a21

a22……..

a2n

am1

am2

……..

amn

….Loc(aij)=Loc(a11)+[(j-1)m+(i-1)]*l

以上規則推廣到多維數組的情況:行優先順序可規定為先排最右的下標,從右到左,最后排最左下標;3、n維數組按上述兩種方式順序存儲的數組,只要知道開始結點的存放地址(即基地址)、維數和每維的上、下界,以及每個數組元素所占用的單元數,就可以將數組元素的存放地址表示為其下標的線性函數。因此,數組中的任一元素可以在相同的時間內存取,即順序存儲的數組是一個隨機存取結構。列優先順序與此相反,先排最左下標,從左向右,最后排最右下標。例如,二維數組Amn按“行優先順序”存儲在內存中,假設每個元素占用d個存儲單元。4、地址公式元素aij的存儲地址應是數組的基地址加上排在aij前面的元素所占用的單元數。因為aij位于第i行、第j列,前面i-1行一共有(i-1)×n個元素,第i行上aij前面又有j-1個元素,故它前面一共有(i-1)×n+j-1個元素,因此,aij的地址計算函數為:LOC(aij)=LOC(a11)+[(i-1)*n+j-1]*d同樣,三維數組Aijk按“行優先順序”存儲,其地址計算函數為:

LOC(aijk)=LOC(a111)+[(i-1)*n*p+(j-1)*p+(k-1)]*d上述討論均是假設數組各維的下界是1,更一般的二維數組是A[c1..d1,c2..d2],這里c1,c2不一定是1。aij前一共有i-c1行,二維數組一共有d2-c2+1列,故這i-c1行共有(i-c1)*(d2-c2+1)個元素,第i行上aij前一共有j-c2個元素,因此,aij的地址計算函數為:

4、地址公式LOC(aij)=LOC(ac1c2)+[(i-c1)*(d2-c2+1)+j-c2)]*d例如,在C語言中,數組各維下標的下界是0,因此在C語言中,二維數組的地址計算公式為:LOC(aij)=LOC(a00)+(i*(d2+1)+j)*d在科學與工程計算問題中,矩陣是一種常用的數學對象,在高級語言編制程序時,簡單而又自然的方法,就是將一個矩陣描述為一個二維數組。但是在矩陣中非零元素呈某種規律分布或者矩陣中出現大量的零元素的情況下,看起來存儲密度仍為1,但實際上占用了許多單元去存儲重復的非零元素或零元素,這對高階矩陣會造成極大的浪費,為了節省存儲空間,我們可以對這類矩陣進行壓縮存儲。5.3矩陣的壓縮存儲壓縮存儲:為多個相同的非零元素只分配一個存儲空間;對零元素不分配空間。假若值相同的元素或零元素在矩陣中的分布有一定規律,則我們稱此類矩陣為特殊矩陣;反之,稱為稀疏矩陣。1、對稱矩陣5.3.1特殊矩陣在一個n階方陣A中,若元素滿足下述性質:aij=aji0≦i,j≦n-1則稱A為對稱矩陣。如圖5.1便是一個5階對稱矩陣。對稱矩陣中的元素關于主對角線對稱,故只要存儲矩陣中上三角或下三角中的元素,讓每兩個對稱的元素共享一個存儲空間,這樣,能節約近一半的存儲空間。不失一般性,我們按“行優先順序”存儲主對角線(包括對角線)以下的元素,其存儲形式如圖所示:

a00a01

….

……..a0n-1

a10

a11

……..…….a1n-1

an-10

an-11

……..an-1n-1

….a00a10a11a20a21a23………………..an-10an-11an-12…an-1n-1

a00a01

….

……..a0n-1

a10

a11

……..…….a1n-1

an-10

an-11

……..an-1n-1

….在這個下三角矩陣中,第i行恰有i+1個元素,元素總數為:(i+1)=n(n+1)/2。這樣可將n2個壓縮到n(n+1)/2個元的空間中。因此,我們可以按圖中箭頭所指的次序將這些元素存放在一個向量sa[0..n(n+1)/2-1]中。為了便于訪問對稱矩陣A中的元素,我們必須在aij和sa[k]之間找一個對應關系。1、對稱矩陣i≧j,則aij在下三角形中。aij之前的i行(從第0行到第i-1行)一共有1+2+…+i=i(i+1)/2個元素,在第i行上,aij之前恰有j個元素(即ai0,ai1,ai2,…,aij-1),因此有:1、對稱矩陣k=i*(i+1)/2+j0≦k<n(n+1)/2若i<j,則aij是在上三角矩陣中。因為aij=aji,所以只要交換上述對應關系式中的i和j即可得到:k=j*(j+1)/2+i0≦k<n(n+1)/2令I=max(i,j),J=min(i,j),則k和i,j的對應關系可統一為:

k=I*(I+1)/2+J0≦k<n(n+1)/2aij的地址可用下列式計算:

LOC(aij)=LOC(sa[k])=LOC(sa[0])+k*d=LOC(sa[0]+[I*(I+1)/2+J]*d)a00a10a11a20……an-10……an-1,n-1根據下標交換關系,對于任意給定一組下標(i,j),均可在sa[k]中找到矩陣元素aij,反之,對所有的k=0,1,2,…n(n-1)/2-1,都能確定sa[k]中的元素在矩陣中的位置(i,j)。由此,稱sa[n(n+1)/2]為階對稱矩陣A的壓縮存儲,見下圖:k=0123n(n-1)/2n(n-1)/2-1例如a21和a12均存儲在sa[4]中

k=I*(I+1)/2+J=2*(2+1)/2+1=4以主對角線劃分,三角矩陣有上三角和下三角兩種。2、三角矩陣a00a01…a0n-1ca11…a1n-1……………..cc…an-1n-1(a)上三角矩陣a00c…ca10a11…c……………..an-10an-11…an-1

n-1

(b)下三角矩陣上三角矩陣如圖所示,它的下三角(不包括主對角線)中的元素均為常數。下三角矩陣正好相反,它的主對角線上方均為常數,如圖所示。在大多數情況下,三角矩陣常數為零。帶狀矩陣:在帶狀矩陣中,所有的非零元素集中在以主對角線為中心的帶狀區域中,即除了主對角線和主對角線相鄰兩側的若干條對角線上的元素之外,其余元素皆為零。這個帶狀區域若包含主對角線下面及上面各d條對角線上的元素,那么,方陣稱為半帶寬為d的帶狀矩陣。設n階方陣A是半帶寬為d的帶狀矩陣,則當|i-j|>d時,aij=0,2d+1稱為帶狀矩陣的帶寬。3、帶狀矩陣

a11a120

…………….

0

a21

a22a23

0

……………0

0

0

…an-1,n-2an-1,n-1

an-1,n

0

0

……an,n-1

ann.

0

a32

a33a34

0

………0

……………非零元素僅出現在主對角上,緊鄰主對角線上面的d條對角線上和緊鄰主對角線下面的d條對角線上。顯然,當∣i-j∣>d時,元素aij=0。對帶狀矩陣可按行優先順序或對角線的順序,將其壓縮存儲到一個向量中,并且也能找到每個非零元素和向量下標的對應關系。對于n階半帶寬為d的帶狀矩陣,只需存放帶狀區域之內的n(2d+1)-d(d+1)個非零元素。為了計算非零元素存放位置方便,除第1行和第n行外,每行都當做有

2d+1個元素,若少于2d+1個,則添零補足。將帶狀矩陣存儲在[(2d+1)n-2d)]s個存儲單元中,元素aij的地址公式為:LOC[i,j]=Loc[1,1]+[(i-1)(2d+1)+(j-i)]s(1in,1jn,|i-j|d)上述的各種特殊矩陣,其非零元素的分布都是有規律的,因此總能找到一種方法將它們壓縮存儲到一個向量中,并且一般都能找到矩陣中的元素與該向量的對應關系,通過這個關系,仍能對矩陣的元素進行隨機存取。5.3.2稀疏矩陣什么是稀疏矩陣?精確點,設在的矩陣A中,有s個非零元素。令e=s/(m*n),稱e為矩陣的稀疏因子。通常認為e≦0.05時稱之為稀疏矩陣。簡單說,設矩陣A中有s個非零元素,若s遠遠小于矩陣元素的總數(即s≦m×n),則稱A為稀疏矩陣。在存儲稀疏矩陣時,為了節省存儲單元,很自然地想到使用壓縮存儲方法。但由于非零元素的分布一般是沒有規律的,因此在存儲非零元素的同時,還必須同時記下它所在的行和列的位置(i,

j)。1、三元順序表

反之,一個三元組(i,j,aij)唯一確定了矩陣A的一個非零元。因此,稀疏矩陣可由表示非零元的三元組及其行列數唯一確定。例如,下列三元組表((1,2,12)(1,3,9),(3,1,-3),(3,6,14),(4,3,24),(5,2,18),(6,1,15),(6,4,-7))加上(6,7)這一對行、列值便可作為下列矩陣M的另一種描述。而由上述三元組表的不同表示方法可引出稀疏矩陣不同的壓縮存儲方法。1、三元順序表#defineM20typedef

structnode{inti,j;

intv;}JD;JDma[M];三元組表所需存儲單元個數為3(t+1)其中t為非零元個數678

121213931-3361443245218611564-7maijv012345678ma[0].i,ma[0].j,ma[0].v分別存放矩陣行列維數和非零元個數行列下標非零元值2、稀疏矩陣的壓縮存儲方法3、求轉置矩陣問題描述:已知一個稀疏矩陣的三元組表,求該矩陣轉置矩陣的三元組表。解決思路:(1)將矩陣行、列維數互換(2)將每個三元組中的i和j相互調換(3)重排三元組次序,使mb中元素以T的行(M的列)為主序67

8

121213931-3361443245218611564-7ijv012345678maijv76

8

13-3161521122518319342446-76314012345678mb?一個m×n的矩陣A,它的轉置B是一個n×m的矩陣,且a[i][j]=b[j][i],0≦i≦m,0≦j≦n,即A的行是B的列,A的列是B的行。方法一將A轉置為B,就是將A的三元組表a.data置換為表B的三元組表b.data,如果只是簡單地交換a.data中i和j的內容,那么得到的b.data將是一個按列優先順序存儲的稀疏矩陣B。要得到按行優先順序存儲的b.data,就必須重新排列三元組的順序。

由于A的列是B的行,因此,按a.data的列序轉置,所得到的轉置矩陣B的三元組表b.data必定是按行優先存放的。按這種方法設計的算法,其基本思想是:對A中的每一列col(0≦col≦n-1),通過從頭至尾掃描三元表a.data,找出所有列號等于col的那些三元組,將它們的行號和列號互換后依次放入b.data中,即可得到B的按行優先的壓縮存儲表示。方法一StatusTransmatrix(TSMatrixM,TSMatrix&T){T.mu=M.nu;T.nu=M.mu;T.tu=M.tu;if(T.tu){q=1;for(col=1;col<=M.nu;col++)

for(p=1;p<=M.tu;p++)

if(M.data[p].j==col){

T.data[q].i=M.data[p].j;

T.data[q].j=M.data[p].i;

T.data[q].e=M.data[p].e;q++;}returnOK;}//TransposeSMatrix6

7

8

121213931-3361443245218611564-7ijv012345678ma7

6

8

13-3161521122518319342446-76314ijv012345678mbkppppppppkkkkppppppppcol=1col=2方法一分析這個算法,主要的工作是在p和col的兩個循環中完成的,故算法的時間復雜度為O(n*t),即矩陣的列數和非零元的個數的乘積成正比。而一般傳統矩陣的轉置算法為:

for(col=1;col<=nu;++col)

for(row=1;row<=mu;++row)

t[col][row]=m[row][col];時間復雜度為O(n*m)。當非零元素的個數t和m*n同數量級時,算法transmatrix的時間復雜度為O(m*n2)。三元組順序表雖然節省了存儲空間,但時間復雜度比一般矩陣轉置的算法還要復雜,同時還有可能增加算法的難度。因此,此算法僅適用于t<=m*n的情況。方法一按照a.data中三元組的次序進行轉置,并將轉置后的三元組置入b中的恰當位置。方法2:快速轉置算法如果能預先確定矩陣M中每一列(即T中每一行)的第一個非零元素在b.data中應有的位置,那么在對a.data中的三元組一次作轉置時,便可直接放到b.data中恰當位置上去。為了確定這些位置,在轉置前,應先求得M的每一列中非零元的個數,進而求得每一列的第一個非零元在b.data中應有的位置。快速轉置算法的思想:對A掃描一次,按A第二列提供的列號一次確定裝入B的一個三元組的位置。具體實施如下:一遍掃描先確定三元組的位置關系,二次掃描由位置關系裝入三元組。可見,位置關系是此種算法的關鍵。

實現:需要附設num和cpot兩個數組。num[col]:表示矩陣M中第col列中非零元個數;cpot[col]:指示M中第col列第一個非零元在mb中位置顯然有:cpot[1]=1;cpot[col]=cpot[col-1]+num[col-1];(2cola.nu)1357889colnum[col]cpot[col]12223241506170方法2:快速轉置算法快速轉置算法StatusFastTransmatrix(TSMatrixM,TSMatrix&T){T.mu=M.nu;T.nu=M.mu;T.tu=M.tu;if(T.tu){for(col=1;col<=M.nu;++col)num[col]=0;for(t=1;t<=M.tu;++t)++num[M.data[t].j];//求M中每一列含非零元個數cpot[1]=1;//求第col列中第1個非零元素在b.data中的序號。快速轉置算法for(col=2;col<=M.nu;++col)cpot[col]=cpot[col-1]+num[col-1];for(p=1;p<=M.tu;p++){col=M.data[p].j;q=cpot[col];}//ifreturnOK;}//FastTransposeSMatrix

T.data[q].i=M.data[p].j;T.data[q].j=M.data[p].i;

T.data[q].e=M.data[p].e;++cpot[col];}//for這個算法僅比前一個算法多用了兩個輔助數組。快速轉置算法分析從時間上看,算法中有四個并列的單循環,循環次數分別為nu和tu,因而總的時間復雜度為O(nu+tu)。在M的非零元素個數tu和mu×nu等數量級時,其時間復雜度為O(mu×nu),和經典算法的時間復雜度相同。67

8

121213931-3361443245218611564-7ijv012345678maijv012345678mbcolnum[col]cpot[col]1122323524715806817907

6

8

13-3161521122518319342446-76314pppppppp4629753tpedef

struct

OLNode{inti,j;ElemTypee;struct

OLNode*down,*right;}OLNode;*OLink;ijedownright在鏈表中,每個非零元素可用一個含5個域的結點表示,right域用以鏈接同一行中下一個非零元素,down域用以鏈接同一列中下一個非零元素。4、十字鏈表同一行的非零元素通過right域鏈接成一個線性表,同一列的非零元素通過down域鏈接成一個線性表,每個非零元素既是某行鏈表中的一個結點,又是某個列鏈表中的一個結點,整個矩陣構成了一個十字交叉的鏈表,故稱這樣的存儲結構為十字鏈表,可用兩個分別存儲行鏈表的頭指針和列鏈表的頭指針的一維數組表示。113418225234^^^^^^^4、十字鏈表例題:兩個矩陣相加假設兩個矩陣相加后的結果為A’,則和矩陣A’中的非零元aij’只可能有三種情況:aij+bij

當將B加到A上去時,A矩陣的十字鏈表:改變接點的e值(aij+bij0)aij(bij=0)bij(aij=0)不變(bij=0)插入一個新結點(aij=0)另一種情況:和A矩陣中的某個非零元相對應,和矩陣A’中是零元,即對A的操作是刪除一個接點(aij+bij=0)。整個運算過程可從矩陣的第一行起逐行進行。對每一行都從表頭出發分別找到A和B在該行中的第一個非零元結點后,開始比較,然后按上述四種不同情況分別處理。例題:兩個矩陣相加廣義表(Lists,又稱列表)是線性表的推廣。在第2章中,我們把線性表定義為n0個元素a1,a2,a3,…,an的有限序列。線性表的元素僅限于原子項,原子是作為結構上不可分割的成分,它可以是一個數或一個結構,若放松對表元素的這種限制,容許它們具有其自身結構,這樣就產生了廣義表的概念。5.4廣義表的定義廣義表是n(n0)個元素a1,a2,a3,…,an的有限序列,其中ai或者是原子項,或者是一個廣義表。通常記作LS=(a1,a2,a3,…,an)。LS是廣義表的名字,n為它的長度。若ai是廣義表,則稱它為LS的子表。通常用圓括號將廣義表括起來,用逗號分隔其中的元素。為了區別原子和廣義表,書寫時用大寫字母表示廣義表,用小寫字母表示原子。若廣義表LS(n>=1)非空,則a1是LS的表頭,其余元素組成的表(a1,a2,…an)稱為LS的表尾。5.4廣義表的定義顯然廣義表是遞歸定義的,這是因為在定義廣義表時又用到了廣義表的概念。廣義表的例子如下:(1)A=()——A是一個空表,其長度為零。(2)B=(e)——表B只有一個原子e,B的長度為1。(3)C=(a,(b,c,d))——表C的長度為2,兩個元素分別為原子a和子表(b,c,d)。(4)D=(A,B,C)——表D的長度為

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論