數據結構 C語言版|第2版-複習

轉載於:https://blog.csdn.net/qq_43874613/article/details/106446193(Villin尼,本校大佬)

第1章 緒論

1.2基本概念和術語

1.2.1數據、數據元素、數據項和數據對象

數據是客觀事物的符號表示,是所有能輸入到計算機中並被計算機程序處理的符號的總稱。

數據元素是數據的基本單位。數據元素通常用於完整地描述一個對象。例如一名學生記錄。

數據項是組成數據元素的、有獨立含義的、不可分割的最小單位。例如學生基本信息表中的學號、姓名、性別等。

數據對象是性質相同的數據元素的集合,是數據的一個子集。

1.2.2數據結構

數據結構是相互之間存在一種或多種特定關係(“結構”)的數據元素的集合。

數據結構包括邏輯結構和存儲結構兩個層次。

1.邏輯結構

(1) 集合結構

(2) 線性結構

(3) 樹結構

(4) 圖結構或網狀結構

其中集合結構、樹結構和圖結構都屬於非線性結構。

線性結構包括線性表、棧和隊列、字符串、數組、廣義表。

非線性結構包括樹和二叉樹、有向圖和無向圖。

2.存儲結構

(1) 順序存儲結構

(2) 鏈式存儲結構

1.4.1算法的定義及特性

算法是爲了解決某類問題而規定的一個有限長的操作序列。

一個算法必須滿足一下五個重要特性:

(1) 有窮性。一個算法必須總是在執行有窮步後結束,且每一步都必須在有窮時間內完成。

(2) 確定性。對於每種情況下所應執行的操作,在算法中都有確切的規定,不會產生二義性,使算法的執行者或閱讀者都能明確其含義及如何執行。

(3) 可行性。算法中的所有操作都可以通過已經實現的基本操作運算執行有限次來實現。

(4) 輸入。一個算法有零個或多個輸入。

(5) 輸出。一個算法有一個或多個輸出。

1.4.3算法的時間複雜度

算法的時間複雜度取決於問題的規模和待處理數據的初態。

一般情況下,算法中基本語句重複執行的次數是時間規模n的某個函數f(n),算法的時間量度記作T(n)=O(f(n)),它表示隨問題規模n的增大,算法執行時間的增長率和f(n)的增長率相同,稱做算法的漸進時間複雜度,簡稱時間複雜度。

若f(n)=amnm+am-1nm-1+…+a1n+a0是一個m次多項式,則T(n)=O(nm)。

1.4.4算法的空間複雜度

關於算法的存儲空間需求,類似於算法的時間複雜度,我們採用漸進空間複雜度作爲算法所需存儲空間的量度,簡稱空間複雜度,它也是問題規模n的函數,記作:S(n)=O(f(n))。

若算法執行時所需要的輔助空間相對於輸入數據量而言是個常數,則稱這個算法爲原地工作,輔助空間爲O(1)。

第2章 線性表

線性表特徵:線性結構的基本特點是除第一個元素無直接前驅,最後一個元素無直接後繼外,其他每個數據元素都有一個前驅和後繼。

2.1線性表的定義和特點

由n(n>=0)個數據特性相同的元素構成的有限序列稱爲線性表(同一性、有窮性、有序性)。

線性表中元素的個數 n(n>=0)定義爲線性表的長度,n=0時稱爲空表。

2.4線性表的順序表示和實現

2.4.1線性表的順序存儲表示

線性表的順序表示指的是用一組地址連續的存儲單元依次存儲線性表的數據元素,這種表示也稱作線性表的順序存儲結構。

假設線性表的每個元素需佔用l個存儲單元,並以所佔的第一個單元的存儲地址(基地址)作爲數據元素的存儲起始位置。

線性表的第i個數據元素ai的存儲位置爲:LOC(ai)=LOC(a1)+(i-1)*l

第i+1個數據元素的存儲位置和第i個數據元素的存儲位置滿足:LOC(ai+1)=LOC(ai)+l。

只要確定了存儲線性表的起始位置,線性表中任一數據元素都可隨機存取,所以線性表的順序存儲結構是一種隨機存取的存儲結構。

2.4.2順序表中基本操作的實現

1.初始化

Status InitList(SqList &L)
{
    L.elem=new ElemType[MAXSIZE];  //爲順序表分配一個大小爲MAXSIZE的數組空間
    if(!L.elem) exit(OVERFLOW);
    L.length=0;  //當前長度爲0,爲空表
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.取值

elem[i-1]單元存儲第i個數據元素。

Status GetElem(SqList L,int I,ElemType &e)
{
    if(i<1||i>L.length) return ERROR;
    e=L.elem[i-1];
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

取值算法的時間複雜度爲O(l)。

3.查找

int LocateElem(SqList L,ElemType e)
{
    for(i=0;i<L.length;i++)
       if(L.elem[i]==e) return i+1;  //查找成功,返回序號i+1
    return 0;  //查找失敗,返回0
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

平均查找長度ASL=(n+1)/2,平均時間複雜度爲O(n)。

4.插入

Status ListInsert(SqList &L,int i,ElemType e)
{
    if((i<1)||(i>L.length+1)) return ERROR;  //i不合法
    if(L.length==MAXSZIE) return ERROR;  //存儲空間已滿
    for(j=L.length-1;j>=i-1;j--)
       L.elem[j+1]=L.elem[j];  //插入位置後的元素後移
    L.elem[i-1]=e;  //新元素e放入第i個位置
    ++L.length;  //表長加1
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

所需移動元素次數的期望值Eins=n/2,插入算法的平均時間複雜度爲O(n)。

5.刪除

Status ListDelete(SqList &L,int i)
{
    if((i<1)||(i>L.length)) return ERROR;  //i不合法
    for(j=i;j<L.length-1;j++)
       L.elem[j-1]=L.elem[j];  //被刪除元素之後的元素前移
    --L.length;  //表長減1
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

所移動元素的期望值Edel=(n-1)/2,刪除算法的平均時間複雜度O(n)。

2.5線性表的鏈式表示和實現

線性錶鏈式存儲結構的特點是:用一組任意的存儲單元存儲線性表的數據元素(這組存儲單元可以是連續的,也可以是不連續的)。元素本身的信息和指示其直接後繼的信息組成數據元素ai的存儲映像,稱爲結點。它包括兩個域:其中存儲數據元素信息的域稱爲數據域;存儲直接後繼存儲位置的域稱爲指針域。由於此鏈表的每個結點中只包含一個指針域,故又稱線性鏈表或單鏈表。

鏈表增加頭節點的作用:(1)便於首元結點的處理(2)便於空表和非空表的統一處理。

2.5.2單鏈表基本操作的實現

操作特點:順鏈操作,指針保留

1.初始化

Status InitList(LinkList &L)
{
    L=new LNode;
    L->next=NULL;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2.取值

Status GetElem(LinkList L,int i,ElemType &e)  //取序號爲i的元素的值
{
    p=L->next;
    j=1;
    while(p&&j<i)  //p爲空或p指向第i個元素跳出循環 
    {
       p=p->next;
       ++j;
    }
    if(!p||j>i) return ERROR;  //i>n或i<=0,不合法
    e=p->data;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

平均查找長度ASL=(n-1)/2,平均時間複雜度爲O(n)。

3.查找

分爲按序號查找和按值查找,從鏈表的首元結點出發(只能順鏈查找)。

按值查找:

LNode *LocateElem(LinkList L,ElemType e)
{
    p=L->next;
    while(p&&p->data!=e)  //p爲空或p結點的數據域等於e跳出循環
       p=p->next;
    return p;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

平均時間複雜度爲O(n)。

4.插入

Status ListInsert(LinkList &L,int i,ElemType e)
{
    p=L;
    j=0;
    while(p&&(j<i-1))
        {p=p->next;++j;}
    if(!p||j>i-1) return ERROR;
    s=new LNode;
    s->data=e;
    s->next=p->next;
    p->next=s;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

平均時間複雜度爲O(n)。

5.刪除

Status ListDelete(LinkList &L,int i)
{
    p=L;
    j=0;
    while((p->next)&&(j<i-1))  //查找第i-1個結點
	{p=p->next;++j;}
    if(!(p->next)||(j>i-1))  return ERROR; //i>n或i<1刪除位置不合法
    q=p->next;
    p->next=q->next;  // p->next=p->next->next
    delete q;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

平均時間複雜度爲O(n)。

6.創建單鏈表

(1)前插法/頭插法

void CreateList_H(LinkList &L,int n)
{
    L=new LNode;
    L->next=NULL;
    for(i=0;i<n;++i)
    {
	p=new LNode;
	cin>>p->data;
	p->next=L->next;
	L->next=p;  //p插入到頭結點之後
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

時間複雜度爲O(n)。

(2)後插法/尾插法

Void CreateList_R(LinkList &L,int n)
{
    L=new LNode;
    L->next=NULL;
    r=L;  //尾指針r指向頭結點
    for(i=0;i<n;++i)
    {
	p=new LNode;
	cin>>p->data;
	p->next=NULL;
	r->next=p;  //新節點p插入尾結點r之後
	r=p;  //r指向新的尾結點p
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

時間複雜度爲O(n)。

2.5.3循環鏈表

其特點是表中最後一個結點的指針域指向頭結點(首尾相接)。

判別當前指針p是否指向表尾結點的終止條件爲p!=L或p->next!=L。

2.5.4雙向鏈表

在雙向鏈表的結點中有兩個指針域,一個指向直接後繼,另一個指向直接前驅。

插入:

Status ListInsert_Dul(DuLinkList &L,int i,ElemType e)
{  //在第i個位置之前插入元素e
    if(!(p=GetElem_Dul(L,i))) return ERROR;  //第i個元素不存在
    s=new DulNode;
    s->data=e;
    s->prior=p->prior;
    p->prior->next=s;
    s->next=p;
    p->prior=s;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

刪除:

Status ListDelete_Dul(DuLinkList &L,int i)
{  //刪除第i個元素
    if(!(p=GetElem_Dul(L,i))) return ERROR;  //第i個元素不存在
    p->prior->next=p->next;
    p->next->prior=p->prior;
    delete p;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.6順序表和鏈表的比較

2.6.1空間性能的比較

(1)存儲空間的分配

當線性表的長度變化較大,難以預估存儲規模時,宜採用鏈表作爲存儲結構。

(2)存儲密度的大小

存儲密度是指數據元素本身所佔用的存儲量和整個結點結構所佔用的存儲量之比。存儲密度越大,存儲空間的利用率就越高。順序表的存儲密度爲1,而鏈表的存儲密度小於1。

當線性表的長度變化不大,易於事先確定其大小時,爲了節約存儲空間,宜採用順序表爲存儲結構。

2.6.2時間性能比較

(1)存取元素的效率

若線性表的主要操作是和元素位置緊密相關的這類取值操作,很少做插入或刪除時,宜採用順序表作爲存儲結構。

(2)插入和刪除操作的效率

對於頻繁進行插入或刪除操作的線性表,宜採用鏈表作爲存儲結構。

第3章 棧和隊列

運算的位置限定在表的端點。數據元素可是任意類型,但必須屬於同一個數據對象,數據之間是線性關係。

3.1.1棧的定義和特點

棧是限定僅在表尾進行插入或刪除操作的線性表。表尾端稱爲棧頂,表頭端稱爲棧底。不含元素的空表稱爲空棧。棧又稱爲後進先出的線性表。

3.1.2隊列的定義和特點

隊列是一種先進先出的線性表。只允許在表的一端進行插入,而在另一端刪除元素。在隊列中,允許插入的一端稱爲隊尾,允許刪除的一端稱爲隊頭。

3.3棧的表示和操作的實現

3.3.2順序棧的表示和實現

順序棧,即利用一組地址連續的存儲單元依次存放自棧底到棧頂的數據元素。指針top指示棧頂元素(top=0/-1表示空棧),指針base指示棧底元素。當top和base的值相等時,表示空棧。

棧空時,top和base的值相等;棧非空時,top始終指向棧頂元素的上一個位置。

1.初始化

Status InitStack(SqStack &S)
{
    S.base=new SElemType[MAXSIZE];
    if(!S.base) exit(OVERFLOW);
    S.top=S.base;
    S.stacksize=MAXSIZE;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.入棧

Status Push(SqStack &S,SElemType e)
{
    if(S.top-S.base==S.stacksize) return ERROR;  //棧滿
    *S.top++=e;  //*S.top=e; S.top++; e壓入棧頂,棧頂指針加1
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3.出棧

Status Pop(SqStack &S,SElemType &e)
{
    if(S.top==S.base) return ERROR;  //棧空
    e=*--S.top;  //S.top--;e=*S.top; 棧頂指針減1,棧頂元素賦給e
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4.取棧頂元素

SElmType GetTop(SqStack &S)
{
    if(S.top!=S.base)  //棧非空
    return *(S.top-1);  //返回棧頂元素的值,棧頂指針不變
}
  • 1
  • 2
  • 3
  • 4
  • 5

3.3.3鏈棧的表示和實現

以鏈表的頭部作爲棧頂,無需附加頭結點。

  1. 鏈棧的初始化
Status InitStack(LinkStack &S)
{
    S=NULL;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  1. 鏈棧的入棧
Status Push(LinkStack &S,SElemType e)
{
    p=new StackNode;
    p->data=e;
    p->next=S;  //新節點插入棧頂
    S=p;  //棧頂指針指向p
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  1. 鏈棧的出棧
Status Pop(LinkStack &S,SElemType &e)
{
    if(S==NULL) return ERROR;  //棧空
    e=S->data;  //棧頂元素賦給e
    p=S;
    S=S->next;  //修改棧頂指針
    delete p;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4.取鏈棧的棧頂元素

SElmType GetTop(LinkStack S)
{
    if(S!=NULL)
    return S->data;  //返回棧頂元素的值,棧頂指針不變
}
  • 1
  • 2
  • 3
  • 4
  • 5

兩棧共享技術:兩棧共享棧空間。

3.4棧與遞歸

3.4.1採用遞歸算法解決的問題

若在一個函數、過程或者數據結構定義的內部又直接(或間接)出現定義本身的應用,則稱它們是遞歸的。

一個遞歸算法必須包括終止條件和遞歸部分。

3.5隊列的表示和操作的實現

3.5.2循環隊列——隊列的順序表示和實現

附設兩個整型變量front和rear分別指示隊列頭元素及隊列尾元素的位置。

約定:初始化創建空隊列時,令front=rear=0,每當插入新的隊列尾元素時,尾指針rear增1;每當刪除隊列頭元素時,頭指針front增1。因此,在非空隊列中,頭指針始終指向隊列頭元素,而尾指針始終指向隊列尾元素的下一個位置。

爲解決上述約定的“假溢出”問題,將順序隊列變爲一個環狀的空間,稱之爲循環隊列。頭、尾指針 “依環狀增1”的操作可用“模”運算來實現。

循環隊列不能以頭、尾指針的值是否相同來判斷隊列空間是“滿”還是“空”,如何區分隊滿還是隊空,通常有以下兩種處理方法:

(1)少用一個元素空間,即隊列空間大小爲m時,有m-1個元素就認爲是隊滿;當頭、尾指針的值相同時,則認爲隊空。

隊空的條件:Q.front==Q.rear

隊滿的條件:(Q.rear+1)%MAXSIZE==Q.front

(2)另設一個標誌位以區別隊列是“空”還是“滿”。

1.循環隊列的初始化

Status InitQueue(SqQueue &Q)
{
    Q.base=new QElemType[MAXSIZE];
    if(!Q.base) exit(OVERFLOW);
    Q.front=Q.rear=0;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.求循環隊列的長度

int QueueLength(SqQueue Q)
{
    return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
  • 1
  • 2
  • 3
  • 4

3.循環隊列的入隊

Status EnQueue(SqQueue &Q,QElemType e)
{
    if((Q.rear+1)%MAXSIZE==Q.front)  //隊滿
    return ERROR;
    Q.base[Q.rear]=e;  //e入隊尾
    Q.rear=(Q.rear+1)%MAXSIZE;  //隊尾指針加1
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

4.循環隊列的出隊

Status DeQueue(SqQueue &Q,QElemType &e)
{
    if(Q.front==Q.rear) return ERROR;  //隊空
    e=Q.base[Q.front];  //取隊頭元素
    Q.front=(Q.front+1)%MAXSIZE;  //隊頭指針加1
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

5.取循環隊列的隊頭元素

SElemType GetHead(SqQueue Q)
{
    if(Q.front!=Q.rear)  //隊非空
    return Q.base[Q.front];  //取隊頭元素的值,隊頭指針不變
}
  • 1
  • 2
  • 3
  • 4
  • 5

3.5.3鏈隊——隊列的鏈式表示和實現

一個鏈隊需要兩個分別指向隊頭和隊尾的指針才能唯一確定,給鏈隊天驕一個頭結點,並令頭指針始終指向頭結點。

1.鏈隊的初始化

Status InitQueue(LinkQueue &Q)
{
    Q.front=Q.rear=new QNode;  //隊頭和隊尾的指針指向頭結點
    Q.front->next=NULL;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2.鏈隊的入隊

Status EnQueue(LinkQueue &Q,QElemType e)
{
    p=new QNode;
    p->data=e;
    p->next=NULL;
    Q.rear->next=p;  //新節點插到隊尾
    Q.rear=p;  //修改隊尾指針
    return OK:
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3.鏈隊的出隊

Status DeQueue(LinkQueue &Q,QElemType &e)
{
    if(Q.front==Q.rear) return ERROR;  //隊空
    p=Q.front->next;
    e=p->data;  //取隊頭元素
    Q.front->next=p->next;  //修改頭結點的指針域
    if(Q.rear==p) Q.rear=Q.front;  //最後一個元素被刪,隊尾指針指向頭結點
    delete p;
    return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4.取鏈隊的隊頭元素

SElemType GetHead(LinkQueue Q)
{
    if(Q.front!=Q.rear)  //隊非空
    return Q.front->next->data;  //返回隊頭元素,隊頭指針不變
}
  • 1
  • 2
  • 3
  • 4
  • 5

第4章 串、數組和廣義表

4.1串的定義

串(或字符串)是由零個或多個字符組成的有限序列。一般記爲

s=“a1a2…an” (n>=0)

其中,s是串的名,用雙引號括起來的字符序列是串的值;ai(1<=i<=n)(單字符)可以是字母、數字或其他字符;串中字符的數目n稱爲串的長度。零個字符的串稱爲空串,其長度爲零。

串中任意個連續的字符組成的子序列稱爲該串的子串。包含子串的串相應地稱爲主串。子串在主串中的位置以子串的第一個字符在主串中的位置來表示。

稱兩個串是相等的,當且僅當這兩個串的值相等。只有當兩個串的長度相等,並且各個對應位置的字符都相等時才相等。

4.3串的類型定義、存儲結構及其運算

4.3.2串的存儲結構(順序串,堆串,塊鏈串)

1.串的順序存儲

#define MAXLEN 255  //串的最大長度
typedef struct{
char ch[MAXLEN+1];  //存儲串的一維數組
int length;  //串的當前長度
}SString;
  • 1
  • 2
  • 3
  • 4
  • 5

2.串的堆式順序存儲

typedef struct{
char *ch;  //若是非空串,則按串長分配存儲區,否則ch爲NULL
int length;  //串的當前長度
}HString;
  • 1
  • 2
  • 3
  • 4

3.串的鏈式存儲

#define CHUNKSIZE 80  //可由用戶定義的塊大小
typedef struct Chunk{
char ch[CHUNKSIZE];
struct Chunk *next;
}Chunk;
typedef struct{
Chunk *head,*tail;  //串的頭和尾指針
int length;  //串的當前長度
}LString;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

存儲密度小,運算處理方便,然而存儲佔用量大。

4.3.3串的模式匹配算法

子串的定位運算通常稱爲串的模式匹配或串匹配。

1.BF算法

int Index_BF(SString S,SString T,int pos)
{  //返回子串T在主串S中從第pos個字符開始第一次出現的位置
    i=pos;
    j=1;
    while(i<=S.length&&j<=T.length)
    {
	if(S.ch[i]==T.ch[j]) {++i;++j;}
	else {i=i-j+2;j=1;}
    }
    if(j>T.length) return i-T.length;
    else return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

設主串長度爲n,子串的長度爲m,最好的情況下匹配成功的平均比較次數爲(n+m)/2,時間複雜度爲O(n+m);最壞的情況下匹配成功的平均比較次數爲m*(n-m+2)/2,時間複雜度爲O(n*m)。

2.KMP算法

int Index_KMP(SString S,SString T,int pos)
{  //利用模式串T的next函數求T在主串S中從第pos個字符之後的位置
    i=pos;
    j=1;
    while(i<=S.length&&j<=T.length)
    {
	if(j==0&&S.ch[i]==T.ch[j]) {++i;++j;}
	else {j=next[j]};
    }
    if(j>T.length) return i-T.length;
    else return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

計算next函數值:

void get_next(SString T,int next[])
{
    i=1;
    next[1]=0;
    j=0;
    while(i<T.length)
    {
	if(j==0||T.ch[i]==T.ch[j]) {++i;++j;next[i]=j;}
	else j=next[j];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

計算next函數修正值:

void get_nextval(SString T,int nextval[])
{
    i=1;
    nextval[1]=0;
    j=0;
    while(i<T.length)
    {
	if(j==0||T.ch[i]==T.ch[j])
	{
	    ++i;
	    ++j;
	    if(T.ch[i]!=T.ch[j]) nextval[i]=j;
	    else nextval[i]=nextval[j];
	}
	else j=nextval[j];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

next數組計算:

next[1]=-1:next[i]爲模式串第i-1個字符前與前綴匹配的字符串長度。

Next[1]=0:Next[i]=next[i]+1。

nextval數組計算:

nextval[1]=-1/0。

當T.ch[i]==T.ch[next[i]]時,nextval[i]=nextval[next[i]];

當T.ch[i]!=T.ch[next[i]]時,nextval[i]= next[i]。

4.4數組

數組時由類型相同的數據元素構成的有序集合。數組是線性表的原因:ai是單元素或者ai是帶有結構信息的元素。

4.4.2數組的順序存儲

採用順序存儲結構表示數組比較合適。

對二維數組可有兩種存儲方式:一種是以列序爲主序的存儲方式;一種是以行序爲主序的存儲方式。

以行序爲主序的存儲結構:每個數據元素佔L個存儲單元,二維數組A[0…m-1,0…n-1]中任一元素aij的存儲位置LOC(i,j)=LOC(0,0)+(n*i+j)L。

n維數組A[0…b1-1,0…b2-1,…,0…bn-1]的數據元素存儲位置的計算公式:LOC(j1,j2,…,jn)=LOC(0,0,…,0)+(b2*…bnj1+b3*…bnj2+…+bn*jn-1+jn)L。

4.4.3特殊矩陣的壓縮存儲

1.對稱矩陣(aij=aji)

以一維數組sa[n(n+1)/2]作爲n階對稱矩陣A的存儲結構,則sa[k]和矩陣元aij之間存在一一對應的關係:

在這裏插入圖片描述

2.三角矩陣

(1)上三角矩陣

sa[k]和矩陣元aij之間的對應關係爲:

在這裏插入圖片描述

(2)下三角矩陣

sa[k]和矩陣元aij之間的對應關係爲:

在這裏插入圖片描述

3.對稱矩陣(帶狀矩陣)

按某個原則(或以行爲主,或以對角線的順序)將其壓縮存儲到一維數組上。

4.稀疏矩陣

其非零元較零元少,且分佈沒有一定規律,稱之爲稀疏矩陣。(三元組表示法或十字鏈表)

4.5廣義表

4.5.1廣義表的定義

廣義表是線性表的推廣,也成爲列表。一般記作LS=(a1,a2,…,an).

其中,LS是廣義表的名稱,n是其長度。線性表中ai只限於是單個元素。而在廣義表的定義中,ai可以是單個元素,也可以是廣義表,分別稱爲廣義表LS的原子和子表。用大寫字母表示廣義表的名稱,用小寫字母表示原子。

廣義表的定義是一個遞歸的定義。

A=()——A是一個空表,其長度爲零
B=(e)——B只有一個原子e,其長度爲1
C=(a,(b,c,d))——C的長度爲2,兩個元素分別爲原子a和子表(b,c,d)
D=(A,B,C)——D的長度爲3,3個元素都是廣義表,D=((),(e), (a,(b,c,d)))
E=(a,E)——這是一個遞歸的表
  • 1
  • 2
  • 3
  • 4
  • 5

廣義表的運算:

(1)取表頭GetHead(LS):取出的表頭爲非空廣義表的第一個元素,可以是一個單原子,也可以是一個子表。

(2)取表尾GetTail(LS):取出的表尾爲除去表頭之外,由其餘元素構成的表。即表尾一定是一個廣義表。

4.5.2廣義表的存儲結構

1.頭尾鏈表的存儲結構

表結點:

tag=1 hp tp

原子結點:

tag=0 atom

(1)除空表的表頭指針爲空外,對任意非空廣義表,其表頭指針均指向一個表結點,且該結點中hp域指示廣義表表頭(或爲原子結點,或爲表結點),tp域指向廣義表表尾(除非表尾爲空,則指針爲空,否則必爲表結點)。

(2)容易分清列表中原子和子表所在層次。

(3)最高層的表結點個數即爲廣義表的長度。

2.擴展線性鏈表的存儲結構

表結點:

tag=1 hp tp

原子結點:

tag=0 atom tp

(1)tp指向同層的下一個

廣義表的長度:n

廣義表的深度:最多的括號層數

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