數據結構課件:第2章 線性表_第1頁
數據結構課件:第2章 線性表_第2頁
數據結構課件:第2章 線性表_第3頁
數據結構課件:第2章 線性表_第4頁
數據結構課件:第2章 線性表_第5頁
已閱讀5頁,還剩85頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

教學內容第1章緒論第2章線性表第3章棧和隊列第4章串第5章數組和廣義表第6章樹和二叉樹第7章圖第8章查找第9章排序第2章線性表2.1線性表的定義2.2線性表的順序表示和實現2.3線性表的鏈式表示和實現2.4雙向鏈表2.5一元多項式的表示及相加線性結構(線性表、棧、隊列、串)

線性結構是最常用、最簡單的一種數據結構。而線性表是一種典型的線性結構。其基本特點是線性表中的數據元素是有序且是有限的。在這種結構中:①

存在一個唯一的被稱為“第一個”的數據元素;②存在一個唯一的被稱為“最后一個”的數據元素;③

除第一個元素外,每個元素均有唯一一個直接前驅;④

除最后一個元素外,每個元素均有唯一一個直接后繼。2.1線性表的定義線性表(LinearList):是由n(n≧0)個數據元素(結點)a1,a2…an組成的有限序列。該序列中的所有結點具有相同的數據類型。其中數據元素的個數n稱為線性表的長度。當n=0時,稱為空表。當n>0時,將非空的線性表記作:(a1,a2,…an)a1稱為線性表的第一個(首)結點,an稱為線性表的最后一個(尾)結點。a1,a2…ai-1都是ai(2≦i≦n)的前驅,其中ai-1是ai的直接前驅;ai+1,ai+2…an都是ai(1≦i≦n-1)的后繼,其中ai+1是ai的直接后繼。線性表的邏輯結構線性表中的數據元素ai所代表的具體含義隨具體應用的不同而不同,在線性表的定義中,只不過是一個抽象的表示符號。線性表中的結點可以是單值元素(每個元素只有一個數據項)。例1:26個英文字母組成的字母表:(A,B,…、Z)例2:某校從1978年到1983年各種型號的計算機擁有量的變化情況:(6,17,28,50,92,188)例3:一副撲克的點數(2,3,4…,J,Q,K,A)線性表的邏輯結構線性表中的結點可以是記錄型元素,每個元素含有多個數據項,每個項稱為結點的一個域。每個元素有一個可以唯一標識每個結點的數據項組,稱為關鍵字。例4:某校2001級同學的基本情況:線性表的邏輯結構若線性表中的結點是按值(或按關鍵字值)由小到大(或由大到小)排列的,稱線性表是有序的。線性表是一種相當靈活的數據結構,其長度可根據需要增長或縮短。對線性表的數據元素不僅可以訪問,還可以進行插入和刪除等操作。線性表的抽象數據類型定義(1)ADTList{數據對象:D={ai|ai∈ElemSet,i=1,2,…,n,n≧0}數據關系:R={<ai-1,ai>|ai-1,ai∈D,i=2,3,…,n}基本操作:InitList(&L)操作結果:構造一個空的線性表L;ListLength(L)初始條件:線性表L已存在;操作結果:返回L中數據元素個數;線性表的抽象數據類型定義(2)…GetElem(L,i,&e)初始條件:線性表L已存在,1≦i≦ListLength(L);操作結果:用e返回L中第i個數據元素的值;ListInsert(L,i,&e)初始條件:線性表L已存在,1≦i≦ListLength(L);操作結果:在線性表L中的第i個位置插入元素e;…}ADTList線性表的基本操作(1)(1)初始化線性表InitList(&L):構造一個空的線性表L。(2)銷毀線性表DestroyList(&L):釋放線性表L占用的內存空間。(3)清空線性表ClearList(&L):將線性表重置為空表。(4)判線性表是否為空表ListEmpty(L):若L為空表,則返回真,否則返回假。(5)求線性表的長度ListLength(L):返回L中元素個數。線性表的基本操作(2)(6)求線性表L中指定位置的某個數據元素GetElem(L,i,&e):用e返回L中第i(1≤i≤ListLength(L))個元素的值。(7)定位查找LocateElem(L,e):返回L中第1個值域與e相等的位序。若這樣的元素不存在,則返回值為0。(8)插入數據元素ListInsert(&L,i,e):在L的第i(1≤i≤ListLength(L)+1)個元素之前插入新的元素e,L的長度增1。(9)刪除數據元素ListDelete(&L,i,&e):刪除L的第i(1≤i≤ListLength(L))個元素,并用e返回其值,L的長度減1。

例2.1

假設有兩個集合A和B分別用兩個線性表LA和LB表示,即線性表中的數據元素即為集合中的成員。編寫一個算法求一個新的集合A=A∪B,即將兩個集合的并集放在線性表LC中。解:算法思想是:擴大線性表LA,將存在于線性表LB中而不存在于線性表LA中的數據元素插入到線性表LA中去。只要從線性交LB中依次取得每個數據元素,并依值在線性表LA中進行查訪,若不存在,則插入到表中。算法如下:voidUnion(List&La,ListLb){//算法2.1

//將所有在線性表Lb中但不在La中的數據元素插入到La中

intLa_len,Lb_len,i;

ElemTypee;

La_len=ListLength(La);//求線性表的長度

Lb_len=ListLength(Lb);

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

GetElem(Lb,i,e);//取Lb中第i個數據元素賦給e

if(!LocateElem(La,e,equal))//La中不存在和e相同的數據元素

ListInsert(La,++La_len,e);//插入

}}//union由于LocateElem(LA,e)運算的時間復雜度為O(ListLength(LA)),所以本算法的時間復雜度為:

O(ListLength(LA)*ListLength(LB))。2.2線性表的順序表示和實現順序存儲:把線性表的結點按邏輯順序依次存放在一組地址連續(xù)的存儲單元里。用這種方法存儲的線性表簡稱順序表。順序存儲的線性表的特點:

線性表的邏輯順序與物理順序一致;

數據元素之間的關系是以元素在計算機內“物理位置相鄰”來體現。2.2.1

線性表的順序存儲結構設有非空的線性表:(a1,a2,…an)。順序存儲如圖所示。

…a1a2…ai…an…Loc(a1)Loc(a1)+(i-1)*l

在具體的機器環(huán)境下:設線性表的每個元素需占用l個存儲單元,以所占的第一個單元的存儲地址作為數據元素的存儲位置。則線性表中第i+1個數據元素的存儲位置LOC(ai+1)和第i個數據元素的存儲位置LOC(ai)之間滿足下列關系:

LOC(ai+1)=LOC(ai)+l

線性表的第i個數據元素ai的存儲位置為:

LOC(ai)=LOC(a1)+(i-1)*l

LOC(a1)是線性表的第一個數據元素a1的存儲位置,通常稱做線性表的起始位置或基地址。元素在計算機內物理位置相鄰來表示線性表中數據元素之間的邏輯關系。只要確定了存儲線性表的起始位置,線性表中任一數據元素都可以隨機可取,所以線性表的順序存儲結構是一種隨機存取的存儲結構。

在高級語言(如C語言)環(huán)境下:數組也具有隨機存取的特性,因此,借助數組來描述順序表的存儲結構。由于線性表的長度可變,且所需最大存儲空間隨問題不同而不同,所以在C語言中可以用動態(tài)分配的一維數組來描述。#defineLIST_INIT_SIZE100

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

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

typedefstruct{

ElemType*elem;

//線性表存儲空間基址

intlength;

//當前線性表長度

intlistsize;

//當前分配的線性表存儲空間大小,以//sizeof(ElemType)為單位)

}SqList;在介紹基本操作的算法之前,先回顧本書算法中常用的兩C函數1)

malloc(intsize)

功能:在系統(tǒng)內存中分配size個的存儲單元,并返回該空間的基址。

使用方法:...intm=100,float*p;

p=(float*)malloc(m*sizeof(float));

執(zhí)行語句p=(float*)malloc(m*sizeof(float)),計算機將按float

類型變量所占空間的大?。ㄒ话銥?2bit)分配m*sizeof(float)個的存儲單元,并將其基址賦值給指針變量p;2)

free(p)

功能:將指針變量p所指示的存儲空間,回收到系統(tǒng)內存空間中去;

使用方法:

...

intm=100;float*p;

p=(float*)malloc(m*sizeof(float));//一旦p所指示的內存空間不再使用

//調用free()回收之

free(p);2.2.2

順序表的基本操作

順序存儲結構中,很容易實現線性表的一些操作:如隨機存取第i個數據元素等。特別注意的是,C語言中數組的下標是從0開始的,因此,若L是SqList類型的順序表,則表中第i個數據元素是L.elem[i-1]。有關順序表的操作有初始化、賦值、查找、修改、插入、刪除、求長度等。以下將對幾種主要的操作進行討論。1線性表的初始化操作voidInitList(SqList&L,intmaxsize){//算法2.3

//構造一個空的線性表LL.elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType));if(!L.elem)exit(OVERFLOW);//存儲分配失敗

L.length=0;//空表長度為0

L.listsize=LIST_INIT_SIZE;//初始存儲容量

ReturnOK;}//InitList_Sq2

順序線性表的插入

在線性表L=(a1,…ai-1,ai,ai+1,…,an)中的第i(1≦i≦n)個位置上插入一個新結點e,使其成為線性表:

L=(a1,…ai-1,e,ai,ai+1,…,an)

實現步驟:將線性表L中的第i個至第n個結點后移一個位置。將結點e插入到結點ai-1之后。線性表長度加1。算法描述:StatusListInsert_Sq(SqList&L,inti,ElemTypee){//算法2.4

//在順序線性表L的第i個元素之前插入新的元素e,

//i的合法值為1≤i≤ListLength_Sq(L)+1

ElemType*p;

if(i<1||i>L.length+1)returnERROR;//i值不合法

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

ElemType*newbase=(ElemType*)realloc(L.elem,

(L.listsize+LISTINCREMENT)*sizeof(ElemType));

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

L.elem=newbase;//新基址

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

}

ElemType*q=&(L.elem[i-1]);//q為插入位置

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

//插入位置及之后的元素右移*q=e;//插入e

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

returnOK;}//ListInsert_Sq

時間復雜度分析

在線性表L中的第i個元素之前插入新結點,其時間主要耗費在表中結點的移動操作上,因此,可用結點的移動來估計算法的時間復雜度。

設在線性表L中的第i個元素之前插入結點的概率為Pi,不失一般性,設各個位置插入是等概率,則Pi=1/(n+1),而插入時移動結點的次數為n-i+1??偟钠骄苿哟螖担篍insert=∑pi*(n-i+1)(1≦i≦n+1)∴Einsert=n/2。即在順序表上做插入運算,平均要移動表上一半結點。當表長n較大時,算法的效率相當低。因此算法的平均時間復雜度為O(n)。3順序線性表的刪除

在線性表L=(a1,…ai-1,ai,ai+1,…,an)中刪除結點ai(1≦i≦n),使其成為線性表:

L=(a1,…ai-1,ai+1,…,an)

實現步驟:將線性表L中的第i+1個至第n個結點依此向前移動一個位置。線性表長度減1。算法描述:StatusListDelete_Sq(SqList&L,inti,ElemType&e){//算法2.5//在順序線性表L中刪除第i個元素,并用e返回其值。

//i的合法值為1≤i≤ListLength_Sq(L)。

ElemType*p,*q;if(i<1||i>L.length)returnERROR;//i值不合法

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

e=*p;//被刪除元素的值賦給eq=L.elem+L.length-1;//表尾元素的位置

for(++p;p<=q;++p)*(p-1)=*p;//被刪除元素之后的元素左移

--L.length;//表長減1returnOK;}//ListDelete_Sq時間復雜度分析:刪除線性表L中的第i個元素,其時間主要耗費在表中結點的移動操作上,因此,可用結點的移動來估計算法的時間復雜度。設在線性表L中刪除第i個元素的概率為Pi,不失一般性,設刪除各個位置是等概率,則Pi=1/n,而刪除時移動結點的次數為n-i。則總的平均移動次數:Edelete=∑pi*(n-i)(1≦i≦n)∴Edelete=(n-1)/2。即在順序表上做刪除運算,平均要移動表上一半結點。當表長n較大時,算法的效率相當低。因此算法的平均時間復雜度為O(n)。4順序線性表的查找定位刪除

在線性表L=(a1,a2,…,an)中刪除值為x的第一個結點。實現步驟:在線性表L查找值為x的第一個數據元素。將從找到的位置至最后一個結點依次向前移動一個位置。

線性表長度減1。算法描述:StatusLocate_Delete_SqList(Sqlist*L,ElemTypex)/*刪除線性表L中值為x的第一個結點*/{inti=0,k;while(i<L->length)/*查找值為x的第一個結點*/{if(L->Elem_array[i]!=x)i++;else{for(k=i+1;k<L->length;k++)L->Elem_array[k-1]=L->Elem_array[k];L->length--;break;}}if(i>L->length){printf(“要刪除的數據元素不存在!\n”);returnERROR;}returnOK;}

時間復雜度分析:

時間主要耗費在數據元素的比較和移動操作上。首先,在線性表L中查找值為x的結點是否存在;其次,若值為x的結點存在,且在線性表L中的位置為i,則在線性表L中刪除第i個元素。設在線性表L刪除數據元素概率為Pi,不失一般性,設各個位置是等概率,則Pi=1/n。

◆比較的平均次數:Ecompare=∑pi*i(1≦i≦n)∴Ecompare=(n+1)/2?!魟h除時平均移動次數:Edelete=∑pi*(n-i)(1≦i≦n)∴Edelete=(n-1)/2。

◆平均時間復雜度:Ecompare+Edelete=n,即為O(n)線性表的順序存儲特點:1通過元素的存儲順序反映線性表中數據元素之間的邏輯關系;2可隨機存取順序表的元素;3順序表的插入刪除操作要通過移動元素實現(平均移動一半的元素,n/2);2.3線性表的鏈式表示和實現

2.3.1線性表的鏈式存儲結構

鏈式存儲:用一組任意的存儲單元存儲線性表中的數據元素。用這種方法存儲的線性表簡稱線性鏈表。

存儲鏈表中結點的一組任意的存儲單元可以是連續(xù)的,也可以是不連續(xù)的,甚至是零散分布在內存中的任意位置上的。鏈表中結點的邏輯順序和物理順序不一定相同。

為了正確表示結點間的邏輯關系,在存儲每個結點值的同時,還必須存儲指示其直接后繼結點的地址(或位置),稱為指針(pointer)或鏈(link),這兩部分組成了鏈表中的結點結構,如圖所示。

鏈表是通過每個結點的指針域將線性表的n個結點按其邏輯次序鏈接在一起的。

每一個結只包含一個指針域的鏈表,稱為單鏈表。

為操作方便,總是在鏈表的第一個結點之前附設一個頭結點(頭指針)head指向第一個結點。頭結點的數據域可以不存儲任何信息(或鏈表長度等信息)。datanextdata:數據域,存放結點的值。next:指針域,存放結點的直接后繼的地址。數據域指針域存儲地址數據域指針域

1 Li 437 Qian 1313 Sun 1 19 Wang NULL25 Wu 3731 Zhao 737 Zheng1943 Zhou 2531頭指針H單鏈表:

線性鏈表的邏輯狀態(tài)LiZhaoQianSunZhouWuZhengWang^H1

結點的描述與實現

C語言中用帶指針的結構體類型,即結構指針來描述:typedefstructLnode{ElemTypedata;/*數據域,保存結點的值*/structLnode*next;/*指針域*/}LNode;/*結點的類型*/a1an^a2...頭指針H頭結點H^非空表空表線性表的順序存儲結構中,邏輯上相鄰的兩個元素在物理位置上緊鄰,每個元素的存儲位置都可以從線性表的起始位置計算得到,因此是隨機可取的。線性表的鏈式存儲結構中,單鏈表中的任何兩個元素的存儲位置之間沒有固定的聯(lián)系,因此單鏈表是非隨機可取的存儲結構。單鏈表中每個元素的位置都包含在其直接前驅結點的信息之中。假設p指向線性表中的第i個數據元素(結點ai)的指針,則p->next是指向第i+1個數據元素(結點ai+1)的指針。若p->data=ai,則p->next->data=ai+12結點的實現

結點是通過動態(tài)分配和釋放來的實現,即需要時分配,不需要時釋放。實現時是分別使用C語言提供的標準函數:malloc(),realloc(),sizeof(),free()。動態(tài)分配

p=(LNode*)malloc(sizeof(LNode));函數malloc分配了一個類型為LNode的結點變量的空間,并將其首地址放入指針變量p中。動態(tài)釋放free(p);系統(tǒng)回收由指針變量p所指向的內存區(qū)。P必須是最近一次調用malloc函數時的返回值。3常用的基本操作及其示意圖⑴結點的賦值LNode*p;p=(LNode*)malloc(sizeof(LNode));p->data=20;p->next=NULL;p20NULL①

q=p;pa……操作前pa……q操作后②

q=p->next;bpa……操作前操作后qbpa……③

p=p->next;bpa……操作前操作后pba……④

q->next=p;c…pbqa……操作前操作后qb……ac…p(a)⑵常見的指針操作⑤

q->next=p->next;(a)xy…pbqa……操作前操作后qb……axy…p操作前ypx……bqa…操作后ypx……bqa…(b)操作前ypx……bqa…操作后ypx……bqa…(b)課堂練習:對以下單鏈表分別執(zhí)行下列各程序段,畫出結果示意圖。2573864∧LPQRSL=P->next;R->data=P->data;R->data=P->next->data;P->next->next->next->data=P->data;T=P;while(T!=NULL){T->data=T->data*2;T=T->next;}T=P;while(T->next!=NULL){T->data=T->data*2;T=T->next;}2.3.2

單鏈表的基本操作1建立單鏈表2單鏈表的查找3單鏈表的插入4單鏈表的刪除5單鏈表的合并1

建立單鏈表動態(tài)地建立單鏈表的常用方法有如下兩種:頭插入法,尾插入法。尾部插入方法生成的鏈表中結點的次序和輸入的順序是相同的,即將新結點插入到當前鏈表的表尾,使其成為當前鏈表的尾結點。算法描述:voidCreateList_L(LinkList&L,intn){//算法2.11

//逆位序輸入(隨機產生)n個元素的值,建立帶表頭結點的單鏈線性表L

LinkListp;

inti;

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

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

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

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

p->data=random(200);//改為一個隨機生成的數字

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

}}//CreateList_L無論是哪種插入方法,如果要插入建立的單線性鏈表的結點是n個,算法的時間復雜度均為O(n)。(1)

按序號查找

取單鏈表中的第i個元素。

對于單鏈表,不能象順序表中那樣直接按序號i訪問結點,而只能從鏈表的頭結點出發(fā),沿鏈域next逐個結點往下搜索,直到搜索到第i個結點為止。因此,鏈表不是隨機存取結構。

設單鏈表的長度為n,要查找表中第i個結點,僅當1≦i≦n時,i的值是合法的。2

單鏈表的查找算法描述StatusGetElem_L(LinkList&L,inti,ElemType&e){//算法2.8

//L為帶頭結點的單鏈表的頭指針。

//當第i個元素存在時,其值賦給e并返回OK,否則返回ERROR

LinkListp;

p=L->next;

intj=1;//初始化,p指向第一個結點,j為計數器

while(p&&j<i){//順指針向后查找,直到p指向第i個元素或p為空

p=p->next;++j;

}

if(!p||j>i)returnERROR;//第i個元素不存在

e=p->data;//取第i個元素

returnOK;}//GetElem_L移動指針p的頻度:i<1時:0次;i∈[1,n]:i-1次;i>n:n次。∴時間復雜度:O(n)。(2)

按值查找

按值查找是在鏈表中,查找是否有結點值等于給定值key的結點?若有,則返回首次找到的值為key的結點的存儲位置;否則返回NULL。查找時從開始結點出發(fā),沿鏈表逐個將結點的值和給定值key作比較。算法描述:LNode

*Locate_Node(LNode*L,intkey)/*在以L為頭結點的單鏈表中查找值為key的第一個結點*/{LNode*p=L–>next;while(p!=NULL&&p–>data!=key)p=p–>next;if(p–>data==key)returnp;else{printf(“所要查找的結點不存在!!\n”);retutn(NULL);}}算法的執(zhí)行與形參key有關,平均時間復雜度為O(n)。插入運算是將值為e的新結點插入到表的第i個結點的位置上,即插入到ai-1與ai之間。因此,必須首先找到ai-1所在的結點p,然后生成一個數據域為e的新結點s,s結點作為p的直接后繼結點。3

單鏈表的插入abps->next=p->next;p->next=s;注意:順序不能反abesp

算法描述:StatusListInsert_L(LinkList&L,inti,ElemTypee){//算法2.9

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

LinkListp,s;

p=L;

intj=0;

while(p&&j<i-1){//尋找第i-1個結點

p=p->next;

++j;

}

if(!p||j>i-1)returnERROR;//i小于1或者大于表長

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

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

p->next=s;

returnOK;}//LinstInsert_L

設鏈表的長度為n,合法的插入位置是1≦i≦n。算法的時間主要耗費移動指針p上,故時間復雜度亦為O(n)。⑴按序號刪除

刪除單鏈表中的第i個結點。

為了刪除第i個結點ai,必須找到結點的存儲地址。該存儲地址是在其直接前趨結點ai-1的next域中,因此,必須首先找到ai-1的存儲位置p,然后令p–>next指向ai的直接后繼結點,即把ai從鏈上摘下。最后釋放結點ai的空間,將其歸還給“存儲池”。

4

單鏈表的刪除abpcabpp->next=p->next->next設單鏈表長度為n,則刪去第i個結點僅當1≦i≦n時是合法的。則當i=n+1時,雖然被刪結點不存在,但其前趨結點卻存在,是終端結點。故判斷條件之一是p–>next!=NULL。顯然此算法的時間復雜度也是O(n)。算法描述StatusListDelete_L(LinkList&L,inti,ElemType&e){//算法2.10

//在帶頭結點的單鏈線性表L中,刪除第i個元素,并由e返回其值

LinkListp,q;

p=L;

intj=0;

while(p->next&&j<i-1){//尋找第i個結點,并令p指向其前趨

p=p->next;

++j;

}

if(!(p->next)||j>i-1)returnERROR;//刪除位置不合理

q=p->next;

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

e=q->data;

free(q);

returnOK;}//ListDelete_L⑵按值刪除

刪除單鏈表中值為key的第一個結點。與按值查找相類似,首先要查找值為key的結點是否存在?若存在,則刪除;否則返回NULL。算法描述voidDelete_LinkList(LNode*L,intkey)/*刪除以L為頭結點的單鏈表中值為key的第一個結點*/{LNode*p=L,*q=L–>next;while(q!=NULL&&q–>data!=key){p=q;q=q–>next;}if(q–>data==key){p->next=q->next;free(q);}elseprintf(“所要刪除的結點不存在!!\n”);}

算法的執(zhí)行與形參key有關,平均時間復雜度為O(n)。從上面的討論可以看出,鏈表上實現插入和刪除運算,無需移動結點,僅需修改指針。解決了順序表的插入或刪除操作需要移動大量元素的問題。假設s為指向節(jié)點x的指針,則在p節(jié)點后面插入s節(jié)點指針修改語句為:s->next=p->next;p->next=s刪除p節(jié)點,修改指針語句為:p->next=p->next->next設有兩個有序的單鏈表,它們的頭指針分別是La、Lb,將它們合并為以Lc為頭指針的有序鏈表。合并前的示意圖如圖所示。15?-249……

Lb

pb-7312……

23?La

Lcpapc5

單鏈表的合并合并了值為-7,-2的結點后示意圖如圖所示。

合并了值為-7,-2的結點后的狀態(tài)-249……

15?Lb

pcpbLc-7312……

23?La

pa算法說明算法中pa,pb分別是待考察的兩個鏈表的當前結點,pc是合并過程中合并的鏈表的最后一個結點。如果pa->data≤pb->data,則將pa所指節(jié)點鏈接到pc所指結點之后,否則將pb所指節(jié)點鏈接到pc所指結點之后。如果其中一個指針為空,說明有一個表的元素已經歸并完成,只需要將另外一個表的剩余段鏈接在pc所指節(jié)點之后。算法描述voidMergeList_L(LinkList&La,LinkList&Lb,LinkList&Lc){

//算法2.12

//已知單鏈線性表La和Lb的元素按值非遞減排列。

//歸并La和Lb得到新的單鏈線性表Lc,Lc的元素也按值非遞減排列。

LinkListpa,pb,pc;pa=La->next;pb=Lb->next;Lc=pc=La;//用La的頭結點作為Lc的頭結點

while(pa&&pb){if(pa->data<=pb->data){pc->next=pa;pc=pa;pa=pa->next;}else{pc->next=pb;pc=pb;pb=pb->next;}}pc->next=pa?pa:pb;//插入剩余段

free(Lb);//釋放Lb的頭結點}//MergeList_L若La,Lb兩個鏈表的長度分別是m,n,則鏈表合并的時間復雜度為O(m+n)。線性表的鏈式存儲特點:1通過保存直接后繼元素的存儲位置來表示數據元素之間的邏輯關系;2插入刪除操作通過修改結點的指針實現;3不能隨機存取元素;單鏈表與順序表的比較:比較順序存儲鏈式存儲訪問方式順序存取/直接存取從鏈表頭順序存取邏輯關系與物理位置完全對應不一定對應存儲空間利用率無附加空間附加一個指針的空間查找速度快慢插入和刪除速度慢快空間限制靜態(tài)分配:不能擴充不需事先分配動態(tài)分配:擴充需移動元素靜態(tài)鏈表(了解)可以借用一維數組來描述線性鏈表。靜態(tài)單鏈表的存儲結構:#defineMAXSIZE1000//鏈表的最大長度Typedefstruct{ElemTypedata;intcur;}component,SLinkList[MAXSIZE];數組的一個分量表示一個節(jié)點,同時用游標(cur)代替指針指示節(jié)點在數組中的相對位置。2.3.3

循環(huán)鏈表

循環(huán)鏈表(CircularLinkedList):是一種頭尾相接的鏈表。其特點是最后一個結點的指針域指向鏈表的頭結點,整個鏈表的指針域鏈接成一個環(huán)。從循環(huán)鏈表的任意一個結點出發(fā)都可以找到鏈表中的其它結點,使得表處理更加方便靈活。下圖是帶頭結點的單循環(huán)鏈表的示意圖。空表非空表a1

a2

……anhead

head

循環(huán)鏈表的操作

對于單循環(huán)鏈表,除鏈表的合并外,其它的操作和單線性鏈表基本上一致,僅僅需要在單線性鏈表操作算法基礎上作以下簡單修改:⑴判斷是否是空鏈表:head->next==head;⑵判斷是否是表尾結點:p->next==head

;2.4

雙向鏈表雙向鏈表(DoubleLinkedList):指的是構成鏈表的每個結點中設立兩個指針域:一個指向其直接前趨的指針域prior,一個指向其直接后繼的指針域next。這樣形成的鏈表中有兩個方向不同的鏈,故稱為雙向鏈表。

和單鏈表類似,雙向鏈表一般增加頭指針也能使雙鏈表上的某些運算變得方便。

將頭結點和尾結點鏈接起來也能構成循環(huán)鏈表,并稱之為雙向循環(huán)鏈表。

雙向鏈表是為了克服單鏈表的單向性的缺陷而引入的。1雙向鏈表的結點及其類型定義

雙向鏈表的結點的類型定義如下。其結點形式如圖所示,帶頭結點的雙向鏈表的形式如圖所示。typedefstructDulnode{ElemTypedata;structDulnode*prior,*next;}DulNode;datanextprior

雙向鏈表結點形式……非空雙向鏈表head?a2a1an?空雙向鏈表head??

帶頭結點的雙向鏈表形式雙向鏈表結構具有對稱性,設p指向雙向鏈表中的某一結點,則其對稱性可用下式描述:(p->prior)->next=p=(p->next)->prior;

結點p的存儲位置存放在其直接前趨結點p->prior的直接后繼指針域中,同時也存放在其直接后繼結點p->next的直接前趨指針域中。2雙向鏈表的基本操作

雙向鏈表中,有一些操作,比如說求鏈表長度,取鏈表中某個結點值,定位等操作僅僅需要涉及一個方向的指針,則它們的算法描述和線性鏈表的操作相同,但是在插入、刪除時又很大的不同,在雙向鏈表中需要同時修改兩個方向的指針。雙向鏈表的插入(算法2.18)

將值為e的結點插入雙向鏈表中。插入前后鏈表的變化如圖所示。s->prior=p->prior;p->prior->next=s;s->next=p;p->prior=sABCps

(2)雙向鏈表的結點刪除(算法2.19)

設要刪除的結點為p,刪除時可以不引入新的輔助指針變量,可以直接先斷鏈,再釋放結點。部分語句組如下:ABCpp->prior->next=p->next;p->next->prior=p->prior;free(p);2.5

一元多項式的表示和相加1一元多項式的表示

一元多項式p(x)=p0+p1x+p2x2+…

+pnxn,由n+1個系數唯一確定。則在計算機中可用線性表(p0

,p1

,p2

,…

,pn

)表示。既然是線性表,就可以用順序表和鏈表來實現。兩種不同實現方式的元素類型定義如下:(1)順序存儲表示的類型typedefstruct{floatcoef;/*系數部分*/intexpn;/*指數部分*/}ElemType;(2)鏈式存儲表示的類型typedefstructploy{floatcoef;/*系數部分*/intexpn;/*指數部分*/structploy*next;}Ploy; S(x)=1+3x10000+2x20000

可采用另一種方式,即用非0項(系數,指數)構成的線性表表示一元多項式,

S=((1,0),(3,10000),(2,20000))如果只存儲非0系數,則必須同時存儲相應的指數一元n次多項式可寫為:Pn(x)=p1xe1+p2xe2+p3xe3+…+pmxem(pi是指數為ei的項的非0系數,且0≤e1<e2<…<em=n我們可用一個長度為m且每個元素有兩個數據項(系數項和指數項)的線性表((p1,e1),(p2,e2),…,(pm,em)),便可唯一確定多項式Pn(x)-17031517∧98如果采用線性鏈表來實現一元多項式則

A(x)=7+3x+9x8+5x17 B(x)=8x+22x7-9x8

的存儲狀態(tài)如下:81-1227-98∧

2一元多項式的相加

不失一般性,設有兩個一元多項式:P(x)=p0+p1x+p2x2+…

+pnxn,Q(x)=q0+q1x+q2x2+…

+qmxm(m<n)R(x)=P(x)+Q(x)

R(x)由線性表R((p0+q0),(p1+q1),(p2+q2),…

,(pm+qm),…

,

pn)唯一表示。⑴順序存儲表示的相加線性表的定義typedefstruct{ElemTypea[MAX_SIZE];intlength;}Sqlist;

用順序表示的相加非常簡單。訪問第5項可直接訪問:L.a[4].coef,

L.a[4].expn(2)

鏈式存儲表示的相加當采用鏈式存儲表示時,根據結點類型定義,凡是系數為0的項不在鏈表中出現,從而可以大大減少鏈表的長度。一元多項式相加的實質:

指數不同:是鏈表的合并。指數相同:系數相加,和為0,去掉結點,和不為0,修改結點的系數域。算法之一:

就在原來兩個多項式鏈表的基礎上進行相加,相加后原來兩個多項式鏈表就不在存在。當然再要對原來兩個多項式進行其它操作就不允許了。算法描述Ploy*add_ploy(ploy*La,ploy*Lb)/*將以La,Lb為頭指針表示的一元多項式相加*/{ploy*Lc,*pc,*pa,*pb,*ptr;floatx;Lc=pc=La;pa=La->next;pb=Lb->next;while(pa!=NULL&&pb!=NULL){if(pa->expn<pb->expn){pc->next=pa;pc=pa;pa=pa->next;}/*將pa所指的結點合并,pa指向下一個結點*/if(pa->expn>pb->expn){pc->next=pb;pc=pb;pb=pb->next;}/*將pb所指的結點合并,pb指向下一個結點*/else{x=pa->coef+pb->coef;if(abs(x)<=1.0e-6)/*如果系數和為0,刪除兩個結點*/{ptr=pa;pa=pa->next;free(ptr);ptr=pb;pb=pb->next;free(ptr);}else/*如果系數和不為0,修改其中一個結點的系數域,刪除另一個結點*/{pc->next=pa;pa->coef=x;pc=pa;pa=pa->next;ptr=pb;pb=pb->next;free(pb);}}}/*endofwhile*/if(pa==NULL)pc->next=pb;elsepc->next=pa;return(Lc);}算法之二:

對兩個多項式鏈表進行相加,生成一個新的相加后的結果多項式鏈表,原來兩個多項式鏈表依然存在,不發(fā)生任何改變,如果要再對原來兩個多項式進行其它操作也不影響。算法描述Ploy*add_ploy(ploy*La,ploy*Lb)/*將以La,Lb為頭指針表示的一元多項式相加,生成一個新的結果多項式*/{ploy*Lc,*pc,*pa,*pb,*p;floatx;Lc=pc=(ploy*)malloc(sizeof(ploy));pa=La->next;pb=Lb->next;while(pa!=NULL&&pb!=NULL){if(pa->expn<pb->expn){p=(ploy*)malloc(sizeof(ploy));p->coef=pa->coef;p->expn=pa->expn;p->next

溫馨提示

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

最新文檔

評論

0/150

提交評論