數據結構複習筆記(二)

第二章 線性表

線性結構是一個數據元素的有序(次序)集

線性結構的基本特徵:

1.集合中必存在唯一的一個“第一元素”;

2.集合中必存在唯一的一個“最後元素”;

3.除最後元素之外,均有唯一的後繼;

4.除第一元素之外,均有唯一前驅。

2.1線性表的類型定義

抽象數據類型線性表的定義如下:

ADT List{

數據對象:

D = {ai | ai∈ElemSeti=1,2,.....nn0}

{n爲線性表的表長;

n=0時的線性表爲空表。}

數據關係:

R1 = {<ai-1,ai>|ai-1,ai∈Di=2,.......n}

{設線性表爲(a1,a2,.....ai,.....an),

iai在線性表中的位序。} 

基本操作:

{結構初始化}


InitList&L

操作結果:構造一個空的線性表L


{銷燬結構}


DestroyList&L

初始條件:線性表L已存在。

操作結果:銷燬線性表L


{引用型操作}


ListEmptyL

初始條件:線性表L已存在。

操作結果:若L爲空表,則返回TRUE,否則FALSE

 

ListLengthL

初始條件:線性表L已存在。

操作結果:返回線性表L中元素的個數。

 

PriorElemLcur_e&pre_e

初始條件:線性表L已存在。

操作結果:若cur_eL的元素,但不是第一個,則用pre_e返回它的前驅,否則操作失敗,pre_e無定義。

 

NextElemLcur_e&next_e

初始條件:線性表L已存在。

操作結果:若cur_eL的元素,但不是最後一個,則用next_e返回它的後繼,否則操作失敗,next_e無定義。

  

GetElemLi&e

初始條件:線性表L已存在,1≦i≦LengthListL)。

操作結果:用e返回L中的第i個元素的值。

 

LocateElemLecompare())

初始條件:線性表L已存在,compare()是元素判定函數。

操作結果:返回L中第一個與e滿足關係compare()的元素的位序,若這樣的元素不存在,則返回值爲0

 

ListTraverseLvisit()

初始條件:線性表L已存在。

操作結果:依次對L的每個元素調用函數visit()。一旦visit()失敗,則操作失敗。

 

{加工型操作}

ClearList&L

初始條件:線性表L已存在。

操作結果:將L重置爲空表。

 

PutElemLi&e

初始條件:線性表L已存在,1≦i≦LengthListL)。

操作結果:L中第i個元素賦值同e的值。

 

ListInsert&Lie

初始條件:線性表L已存在,1≦i≦LengthListL+1

操作結果:在L的第i個元素之前插入新的元素eL的長度增1

  

ListDelete&Lie

初始條件:線性表L已存在且非空,1≦i≦LengthListL)。

操作結果:刪除L的第i個元素,並用e返回其值,L的長度減1


}ADT List

 

2.2線性表類型的實現——順序映象

用一組地址連續的存儲單元依次存放線性表中的數據元素

a1

a2

....

ai-1

ai

....

an

 

 

以“存儲位置相鄰”表示有序對<ai-1,ai>

即:LOC(ai)=LOC(ai-1)+C

一個數據元素所佔存儲量↑

所有數據元素的存儲位置均取決於第一個數據元素的存儲位置

LOCai)=LOCa1+i-1*C

             ↑基地址

順序映象的C語言描述

#define LIST_INIT_SIZE 80

//線性表存儲空間的初始分配量

#define LISTINCREMENT 10

//線性表存儲空間的分配增量

Typedef struct{

ElemType * elem;//存儲空間基址

int length;//當前長度

int listsize;//當前分配的存儲容量

//(以sizeofElemType)爲單位)

}SqList;//俗稱順序表

線性表的初始化操作

Status InitList_Sq(Sqlist &L){

//構造一個空的線性表

L.elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));

if(!L.elem)exit(OVERFLOW);

L.length = 0;

L.listsize = LIST_INIT_SIZE;

return OK;

}//InitList_Sq 

 

線性表操作

LocateElem(L,e,compare())的實現:

int LocateElem_Sq(SqList L,ElemType e,Status(*compare)(ElemType,ElemType)){

i = 1;//i的初值爲第一元素的位序

p = L.elem;//p的初值爲第一元素的存儲位置

while(i<=L.length && !(*compare)(*p++,e))

++i;

if(i <= L.length) return i;

else return 0;

}//LocateElem_Sq;

此算法的時間複雜度爲O(ListLength(L))

 

線性表操作

ListInsert(&L,i,e)的實現:

Status ListInsert_Sq(SqList &L,int pos,ElemType e){

if(pos < 1|| pos > L.length + 1)return ERROR;//插入位置不合法

if(L.length >= L.listsize){//當前存儲空間已滿,增加分配

newbase = (ElemType *)realloc(L.elem,(L.listsize + LISTINCREMENT) * sizeof(ElemType));

if(!newbase)exit(OVERFLOW);//存儲分配失敗

L.elem = newbase;//新基址

L.listsize += LISTINCREMENT;//增加存儲容量

}

q = &(L.elem[pos-1]);//q指示插入位置

for(p = &(L.elem[L.length-1]);p >=q;-- p)

*(p+1) = *p;//插入位置及之後的元素右移

*q = e;//插入e

++L.length;//表長增1

return OK;

}//ListInsert_Sq;

此算法時間複雜度爲O(ListLength(L))

 

 

線性表操作

ListDelete(&L,i,&e)的實現:

Status ListDelete_Sq(SqList &L, int pos, ElemType &e){

if((pos < 1)||(pos > L.length)) return ERROR;//刪除位置不合法

p = &(L.elem[pos-1]);//p爲被刪除元素的位置

e = *p;//被刪除元素的值賦給e

q = L.elem + L.length - 1;//表尾元素的位置

for(++p;p <= q;++p)

*(p-1) = *p;//被刪除元素之後的元素左移

--L.length;//表長減1

return OK;

}//ListDelete_Sq;

此算法的時間複雜度爲:O(ListLength(L))

 

2.3線性表類型的實現——鏈式映象

一、單鏈表

用一組地址任意的存儲單元存放線性表中的數據元素

以元素(數據元素的映象)+指針(指示後繼元素存儲位置的)=結點(表示數據元素)

以“結點的序列”表示線性表——稱作鏈表

以線性表中第一個數據元素的存儲地址作爲線性表的地址,稱作線性表的頭指針

二、結點和單鏈表的C語言描述

Typedef struct LNode{

ElemType data;//數據域

Struct Lnode *next;//指針域

}LNode, *LinkList;

三、單鏈表操作的實現

線性表的操作GetElem(L,i,&e)

在鏈表中的實現:

基本操作位:使指針p始終指向線性表中第j個數據元素

Status GetElem L(LinkList L,int pos,ElemType &e){

p = L->next; j = 1;//初始化,p指向第一個結點,j爲計數器

while(p && j<pos){p = p->next; ++j; }//p指針向後查找,直到p指向第pos個元素或p爲空

if(!p || j>pos)

return ERROR;//pos個元素不存在

E = p->data;//取第pos個元素

return OK

}//GetElem_L

此算法的時間複雜度爲:O(ListLength(L))

 

線性表的操作ListInsert(&L,i,e)在鏈表中的實現:

基本操作爲:找到線性表中第i-1個結點,修改其指向後繼的指針

Status ListInsert(LinkList &L, int pos, ElemType e){

p = L;j = 0;

while(p && j < pos-1)

{ p=p->next;++jl}//尋找第pos-1個結點

if(!p||j > pos - 1

return ERROR;//pos小於1或者大於表長

s = (LinkList)malloc(sizeof(LNode));//生成新結點

s->data = e;s->next = p->next;//插入L

p->next = s;

return OK;

}//ListInsert_L

此算法的時間複雜度爲O(ListLength(L))

 

線性表的操作ListDelete(&L,i,&e)在鏈表中的實現:

基本操作爲:找到線性表中第i-1個結點,修改其指向後繼的指針

Status ListDelete(LinkList &L, int pos, ElemType &e){

p = L;j = 0;

while(p->next && j<pos-1)

{p = p->next;++j;}//尋找第pos個結點,並令p指向其前驅

if(!(p->next)||j > pos-1)

return ERROR;//刪除位置不合理

q = p->next;p->next = q->next;//刪除並釋放結點

e = q->data; free(q);

return OK;

}//ListDelete_L;

此算法的時間複雜度爲O(ListLength(L))

 

初始化鏈表:

void CreateList_L(LinkList &L,int n){

L = (LinkList)malloc(sizeof(LNode));

L->next = NULL;//先建立一個帶頭結點的單鏈表

for(i=n; i>0; --i){

p = (LinkList)malloc(sizeof(LNode));

scanf(&p->data);//輸入元素值。

p->next = L->next;L->next = p;//插入到表頭。

}

}//CreateList_L

此算法的時間複雜度爲:O(ListLength(L))

 

求兩個集合的並:

Void union(List &La,List Lb){

La _len = ListLength(La);

Lb_len = ListLength(Lb);

for(i = 1;i <= Lb_len;i ++){

GetElem(Lb,i,e);

if(!LocateElem(La,e,equal()))

ListInsert(La,++La_len,e)

}

}//union

上述算法的時間複雜度:

控制結構:for循環

基本操作:LocateElem(La,e,equal())

當以順序映象實現抽象數據類型線性表時間複雜度爲:O(La_len*Lb_len);

當以鏈式映象實現抽象數據類型線性表時間複雜度爲:O(La_len*Lb_len);

 

有序合併:

void purge(List &La,List Lb){

InitList(LA);

La_len = ListLength(La);

Lb_len = ListLength(Lb);

for(i = 1;i <= Lb_len;i ++){

GetElem(Lb,i,e);

if(!equal(en,e)){

ListInsert(La,++La_len,e);

en = e;

}

}

}//purge

上述算法的時間複雜度:

控制結構:for循環

基本操作:GetElem(Lb,i,e);

當以順序映象實現抽象數據類型線性表時間複雜度爲:O(Lb_len);

當以鏈式映象實現抽象數據類型線性表時間複雜度爲:O(La_len*Lb_len);

 

 

歸併兩個線性表:

Void MergeList(List La,List Lb,List &Lc){

InitList(Lc);

i = j = 1;k = 0;

La_len = ListLength(La);

Lb_len = ListLength(Lb);

while((i <= La_len)&&(j <= Lb_len)){

GetElem(La,i,ai);GetElem(Lb,j,bj);

if(ai <= bj){

ListInsert(Lc,++k,ai);

++i;

}

else{

ListInsert(Lc,++k,bj);

++j;

}

}

Whilei <= La_len{

GetElem(La,i++,ai);ListInsert(Lc,++k,ai);

}

Whilej <= Lb_len{

GetElem(Lb,j++,bj);ListInsert(Lc,++k,bj);

}

}

上述算法的時間複雜度爲:

控制結構:三個並列的while循環

基本操作:ListInsert(Lc,++k,e)

當以順序映象實現抽象數據類型線性表時間複雜度爲:O(La_len+Lb_len);

當以鏈式映象實現抽象數據類型線性表時間複雜度爲:O(La_len+Lb_len)*(La_len+Lb_len);

 

用上述定義的單鏈表實現線性表的操作時,

存在的問題:

1.單鏈表的表長是一個隱含的值;

2.在單鏈表的最後一個元素最後插入元素時,需遍歷整個鏈表;

3.在鏈表中,元素的“位序”概念淡化,結點的“位置”概念強化。

改進鏈表的設置:

1.增加“表長”、“表尾指針”和“當前位置的指針”三個數據域;

2.將基本操作由“位序”改變爲“指針”

 

 

四、一個帶頭結點的線性表類型

Typedef struct LNode{//結點類型

ElemType data;

struct LNode *next;

}*Link,*Position;

 

Status MakeNode(Link &p,ElemType e);

//分配由p指向的值爲e的結點,並返回OK

//若分配失敗,則返回ERROR

void FreeNode(Link &p);

//釋放p所指結點

 

Typedef struct{

Link head,tail;//指向頭結點和最後一個結點

int len;//指示鏈表長度

Link current;

//指向當前訪問的結點的指針

//初始位置指向頭結點

}LinkList;

 

鏈表的基本操作:

{結構初始化和銷燬結構}

Status InitList(LinkList &L);

//構造一個空的線性鏈表L

//頭指針、尾指針和當前指針均指向頭結點,表長爲零

 

Status DestroyList(LinkList &L);

//銷燬線性鏈表LL不再存在

 

{引用型操作}

Status ListEmpty(LinkList L);//判表空

Int ListLength(LinkList L);//求表長

Status Prior(LinkList L);//改變當前指針指向其前驅

Status Next(LinkList L);//改變當前指針指向其後繼

ElemType GetCurElem(LinkList L);//返回當前指針所指數據元素

Status LocatePos(LinkList L,int i);//改變當前指針指向第i個結點

Status LocateElem(LinkList L,ElemType e,Status(*compare)(ElemType,ElemType));

//若存在與e滿足函數compare()判定後關係的元素,則移動當前指針

//指向第1個滿足條件的元素,並返回OK;否則返回ERROR

Status ListTraverse(LinkList L,Status(*visit()));

//依次對L的每個元素調用函數visit()

 

{加工型操作}

Status ClearList(LinkList &L);//重置爲空表

Status SetCurElem(LinkList &L,ElemType e);//更新當前指針所指數據元素

Status Append(LinkList &L,Link s);//一串結點鏈接在最後一個結點之後

Status InsAfter(LinkList &L,ElemType e);//將元素e插入到當前指針之後

Status DelAfter(LinkList &L,ElemType *e);//刪除當前指針之後的結點

 

Status InsAfter(LinkList &L,ElemType e){

//當前指針在鏈表中,則將數據元素e插入在線性鏈表L

//當前指針所指結點之後,並返回OK;否則返回ERROR

if(!L.current)return ERROR;

if(!MakeNode(s,e))return ERROR;

S->next = L.current->next;

L.current->next = s;

return OK;

}//InsAfter

 

Status DelAfter(LinkList & L,ElemType &e){

//當前指針及其後繼在鏈表中,則刪除線性鏈表L中當前指針所指結點之後的結點

//並返回OK,否則返回ERROR

if(!(L.current&&L.current->next))return ERROR;

q = L.current->next;

L.current->next = q->next;

e = q->data;

FreeNode(q);

return OK;

}//DelAfter

 

{利用上述定義的線性鏈表可以完成線性表的其他操作}

 

例一:

Status ListInsert_L(LinkList L,int i ,ElemType e){

//在帶頭結點的單鏈線性表L的第i個元素之前插入元素e

if(!LocatePos(L,i-1))return ERROR;//i使不合法

if(InsAfter(L,e))return OK;//插入第i-1個結點之後

else return ERROR;

}//ListInsert_L

 

例二:

Void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc,int(*compare)(ElemType,ElemType)){

if(!InitList(Lc))return ERROR;//存儲空間分配失敗

LocatePos(La,0);LocatePos(Lb,0);//當前指針指向頭結點

if(DelAfter(La,e)) a = e;

else a = MAXC;//MAXC爲常量最大值

if(DelAfter(Lb,e)) b = e;

else b = MAXC;//ab爲兩表中當前比較元素

while(!(a = MAXC && b = MAXC)){//LaLb非空

.......

}

DestroyList(La);DestroyList(Lb);//銷燬鏈表LaLb

return OK;

}//MergeList_L

 

if((*compare)(a,b) <= 0){//a <=b

InsAfter(Lc,a);

if(DelAfter(La,e1)) a = e1;

else a = MAXC;

}

else{//a > b

InsAfter(Lc,s);

if(DelAfter(Lb,e)) b = e1;

else b = MAXC;

}

 

五、其它形式的鏈表

1.雙向鏈表

//-----線性表的雙向鏈表存儲結構----

Typedef sttuct DuLNode{

ElemType data;//數據域

struct DuLNode *prior;//指向前驅的指針域

struct DuLNode *next;//指向後繼的指針域

}DuLNode,*DuLinkList;

 

2.循環鏈表

最後一個結點的指針域的指針又指回第一個結點的鏈表。

 

2.4一元多項式的表示

一元多項式

pn(x) = p0 + p1x + p2x2 +...+pnxn

在計算機中,可以用一個線性表來表示:

P = (p0,p1,.....,pn)

一般情況下的一元多項式可寫成

Pn(x) = p1xe1 + p2xe2 +....+ pmxem

其中:pi是指數爲ei的項的非零係數,

0 <= e1 < e2 <....< em = n

((p1,e1),(p2,e2),...(pm,em))

 

抽象數據類型一元多項式的定義如下:

 

ADT Polynomial{

數據對象:D = {ai | ai∈TeemSet, i = 1,2,3....,m, m≥0

TermSet中的每一個元素包含一個表示係數的實數和表示指數的整數}

數據關係:R1 = {<ai-1,ai> | ai-1,ai∈D,ai-1中的指數值<ai中的指數值,i = 2,....,n}

基本操作:

CreatPolyn(&P,m)

操作結果:輸入m項的係數和指數,建立一個一元多項式P

DestroyPolyn(&P)

初始條件:一元多項式P已存在。

操作結果:銷燬一元多項式P

PrintPolyn(P)

初始條件:一元多項式P已存在。

操作結果:打印輸出一元多項式P

PolynLength(P)

初始條件:一元多項式P已存在。

操作結果:返回一元多項式P中的項數。

AddPolyn(&Pa&Pb)

初始條件:一元多項式PaPb已存在。

操作結果:完成多項式相加運算,即:Pa = Pa + Pb,並銷燬一元多項式Pb

SubtractPolyn(&Pa&Pb)

初始條件:一元多項式PaPb已存在。

操作結果:完成多項式相減運算,即:Pa = Pa - Pb,並銷燬一元多項式Pb

MultiplyPolyn(&Pa&Pb)

初始條件:一元多項式PaPb已存在。

操作結果:完成多項式相乘運算,即:Pa = Pa × Pb,並銷燬一元多項式Pb

}ADT Polynomial

 

抽象數據類型Polynomial的實現

 

Typedef struct{//項的表示,多項式的項作爲LinkList的數據元素

float coef;//係數

int expn;//指數

}term,ElemType;//兩個類型名:term用於本ADTElemTypeLinkList的數據對象名

 

Typedef LinkList polynomial;//用帶表頭結點的有序鏈表表示多項式

 

int cmp(term a,term b);

//a的指數值<(=)(>)b的指數值,分別返回-10+1

 

Void CreatPolyn(polynomial &P,int m){

//輸入m項的係數和指數,建立表示一元多項式的有序鏈表P

initList(P);

e.coef = 0.0; e.expn = -1;

setCurElem(P,e);//置頭結點的數據元素

for(i = 1;i <= m; ++i){

//依次輸入m個非零項

scanf(e.coef,e.expn);

if(!LocateElem(P,e,(*cmp)()))

//當前鏈表中不存在該指數項

InsAfter(P,e)

}

}//CreatPolyn

 

 

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章