抽象数据类型 (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。函数
程序设计细节
为了更方便的实现链表中的操做,咱们一般会增长一个头结点,并将它指向第一个元素。
源码设计
//链表的结构 struct Node; typedef struct Node *ptrToNode ; typedef ptrToNode List ; typedef ptrToNode Position; struct Node{ ElementType Element; Position Next; }; //判断表是否为空 int IsEmpty(List L){ return L->Next == NULL; } //判断当前是否为链表的末尾 int IsLast(Position P,List L){ return P->Next == Null; } //查找函数 Position Find(Element X,List L){ Position P; P = L->Next; while(P != NULL && P->Element != X){ P = P->Next; } return P; } //删除元素 void Delet(ElementType X,List L){ Position P, TempNode; P = FindPrevious(X, L); if(!IsLast(P,L)){ TempNode = P->Next; P->Next = TempNode->Next; free(TmpNode); } } //查找某元素的前一个元素 Position FindPrevious(ElementType X,List L){ Position P; P = L; while(P->Next != NULL && P->Next->Element != X){ P = P->Next; } return P; } //插入元素 void Insert(ElementType X,List L,Position P){ Position TempNode ; TempNode = malloc(sizeof(struct Node)); if(TempNode == NULL){ printf("malloc error"); return ; } TempNode->Element = x; TempNode->Next = P->Next; p->Next = TempNode; } //删除链表 void DeleteList(List L){ Position P,Tmp; p = L->Next; L->Next = NULL;\ while(p != NULL){ Tmp = P->Next; free(p); p = Tmp; } }
双链表
当涉及到倒序扫描链表时,双链表就很是方便了。双链表和单链表的区别就是:双链表中存在两个指针域,一个指向当前元素的前驱,另外一个指向当前元素的后继。有了双向链表,能够不用在访问当前元素的前一个元素了,不过,双链表方便的同时,增长了空间的开销。指针
循环链表
让最后的单元指向第一个单元构成循环,这样的链表被称为循环链表。它既能够有表头,也能够没有表头(如有表头,则最后一个元素指针指向表头)。code
案例实战
一元多项式
咱们能够用表来定义模拟一元多项式的抽象数据类型。对于大多数系数非零的多项式,咱们能够采用一个简单的数组来进行存储,数组的下标表示多项式的次幂,下标的值表示多项式的系数。可是对于系数相差较大,大部分的系数为0的多项式,采用数组将会浪费极大的空间。下面咱们就采用数组的方法来定义多项式的抽象数据类型。源码
typddef struct{ int CoeffArray[ MaxDegree + 1 ]; int HighPower; }* Polynomial; //多项式初始化为0 void ZeroPolynomial(Polynomial Poly){ int i; for( i=0; i <= MakDegree; i++){ Poly->CoeffArray[i] = 0; } Poly->HighPower = 0; } //两个多项式相加 void AddPolynomial(const Polynomial poly1, const Polynomial poly2, Polynomial polysum){ int i; ZeroPolynomial(polysum); polysum->HighPower = Max(poly1->HighPower,poly2->HighPower); for( i = polysum->HighPower; i>=0; i--){ polysum->CoeffArray[i] = poly1->CoeffArray[i] + poly2->CoeffArray[i]; } } //两个多项式的乘法 void MultPolynomial(const Polynomial poly1, const Polynomial poly2, Polynomial polymult){ int i,j; ZeroPolynomial(polymult); polymult->HighPower = poly1->HighPower + poly2->HighPower; if(polymult->HighPower > MaxDegree){ printf("MaxDegree ERROR"); }else{ for( i=0; i <= poly1->HighPower; i++ ){ for( j=0; poly2->HighPower; j++){ polysum->CoeffArray[i+j] = poly1->CoeffArray[i] * poly2->CoeffArray[i]; } } } }