數據結構之表(C語言實現)


抽象數據類型 (abstract data type,ADT)

抽象數據類型是一些操作的集合。抽象數據類型是數學中的定義,在ADT中,我們不關心操作是如何被實現的。因此,這可以看做是模塊化的擴充。
例如表,樹,圖和它們的操作一起可以看做是抽象數據類型,就想整數,實數和布爾變量是數據類型一樣。整數,實數和布爾變量有它們的操作,抽象數據類型也有它們自己的操作。

表 ADT

我們將形如A1,A2,A3,...,An的一列數稱為表。
表的大小:表中的元素的個數稱為表的大小,大小為0的表稱為空表。
對於除空表外,我們稱Ai+1是Ai的后繼,Ai-1是Ai的前驅,其中表的第一個元素A1不定義前驅,最后一個元素An不定義后繼。

表的數組實現

對於表的所有操作都可以通過數組來實現,數組使得PrintList和Find以線性的時間執行,而FindIndex則花費常數的執行時間。然而,插入和刪除的代價是昂貴的,例如在第一個元素位置插入,需要將后面的所有元素往后移一個位置出來,同理刪除也是如此。因此這兩種操作的最壞情況是O(N)。平均來看,這兩種運算都要移動表的一半的元素,仍然需要線性時間。
因為插入和刪除的運行時間是如此的慢,而且表的大小還需要事先知道,所以簡單數組一般不用來實現表的結構。

鏈表

為了避免插入和刪除的線性開銷,我們需要運行表可以不連續存儲,否則表的部分或全部需要整體移動,而如圖表達了鏈表的一般想法。
在鏈表中,每個結構均包含有表元素和指向包含包含該元素后繼元素的結構的指針,我們稱之為next指針,最后一個元素的next指針指向null,ANSI C規定NULL為0。

程序設計細節

為了更方便的實現鏈表中的操作,我們通常會增加一個頭結點,並將它指向第一個元素。

 1 //鏈表的結構
 2 struct Node;
 3 typedef struct Node *ptrToNode ;
 4 typedef ptrToNode List ;
 5 typedef ptrToNode Position;
 6 
 7 struct Node{
 8     ElementType Element;
 9     Position Next;
10 };
11 
12 //判斷表是否為空
13 int IsEmpty(List L){
14     return L->Next == NULL;
15 }
16 
17 //判斷當前是否為鏈表的末尾
18 int IsLast(Position P,List L){
19     return P->Next == Null;
20 }
21 
22 //查找函數
23 Position Find(Element X,List L){
24     Position P;
25     P = L->Next;
26     while(P != NULL && P->Element != X){
27         P = P->Next;
28     }
29     return P;
30 }
31 
32 //刪除元素
33 void Delet(ElementType X,List L){
34     Position P, TempNode;
35      P = FindPrevious(X, L);
36      if(!IsLast(P,L)){
37          TempNode = P->Next;
38          P->Next = TempNode->Next;
39          free(TmpNode);
40      }
41 }
42 
43 //查找某元素的前一個元素
44 Position FindPrevious(ElementType X,List L){
45     Position P;
46     P = L;
47     while(P->Next != NULL && P->Next->Element != X){
48         P = P->Next;
49     }
50     return P;
51 }
52 
53 //插入元素
54 void Insert(ElementType X,List L,Position P){
55     Position TempNode ;
56     TempNode = malloc(sizeof(struct Node));
57     if(TempNode == NULL){
58         printf("malloc error");
59         return ;
60     }
61     TempNode->Element = x;
62     TempNode->Next = P->Next;
63     p->Next = TempNode;
64 }
65 
66 //刪除鏈表
67 void DeleteList(List L){
68     Position P,Tmp;
69     p = L->Next;
70     L->Next = NULL;\
71     while(p != NULL){
72         Tmp = P->Next;
73         free(p);
74         p = Tmp;
75     }
76 }

雙鏈表

當涉及到倒序掃描鏈表時,雙鏈表就非常方便了。雙鏈表和單鏈表的區別就是:雙鏈表中存在兩個指針域,一個指向當前元素的前驅,另一個指向當前元素的后繼。有了雙向鏈表,可以不用在訪問當前元素的前一個元素了,不過,雙鏈表方便的同時,增加了空間的開銷。

循環鏈表

讓最后的單元指向第一個單元構成循環,這樣的鏈表被稱為循環鏈表。它既可以有表頭,也可以沒有表頭(若有表頭,則最后一個元素指針指向表頭)。

案例實戰

一元多項式
我們可以用表來定義模擬一元多項式的抽象數據類型。對於大多數系數非零的多項式,我們可以采用一個簡單的數組來進行存儲,數組的下標表示多項式的次冪,下標的值表示多項式的系數。但是對於系數相差較大,大部分的系數為0的多項式,采用數組將會浪費極大的空間。下面我們就采用數組的方法來定義多項式的抽象數據類型。

 1 typddef struct{
 2     int CoeffArray[ MaxDegree + 1 ];
 3     int HighPower;
 4 }* Polynomial;
 5 
 6 //多項式初始化為0
 7 void ZeroPolynomial(Polynomial Poly){
 8     int i;
 9     for( i=0; i <= MakDegree; i++){
10         Poly->CoeffArray[i] = 0;
11     }
12     Poly->HighPower = 0;
13 }
14 
15 //兩個多項式相加
16 void AddPolynomial(const Polynomial poly1, const Polynomial poly2, Polynomial polysum){
17     int i;
18     ZeroPolynomial(polysum);
19     polysum->HighPower = Max(poly1->HighPower,poly2->HighPower);
20     for( i = polysum->HighPower; i>=0; i--){
21         polysum->CoeffArray[i] = poly1->CoeffArray[i] + poly2->CoeffArray[i];
22     }
23 }
24 
25 //兩個多項式的乘法
26 void MultPolynomial(const Polynomial poly1, const Polynomial poly2, Polynomial polymult){
27     int i,j;
28     ZeroPolynomial(polymult);
29     polymult->HighPower = poly1->HighPower + poly2->HighPower;
30     if(polymult->HighPower > MaxDegree){
31         printf("MaxDegree ERROR");
32     }else{
33         for( i=0; i <= poly1->HighPower; i++ ){
34             for( j=0; poly2->HighPower; j++){
35                 polysum->CoeffArray[i+j] = poly1->CoeffArray[i] * poly2->CoeffArray[i];
36             }
37         }
38     }
39 }

 

 


免責聲明!

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



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