<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    我所理解的鏈表(來自網絡)


    雖然使用數組可以很方便的查找每一個元素,但如果要插入或刪除元素時,因為要移動大量的元素,所以需要一定的運行時間,而且代碼也變的復雜。為了能夠方便的刪除和插入元素,我們一般不采用順序存取結構,而采用鏈表存取。根據鏈表中結點的性質,我把它分為兩種,一種是使用指針來指向它的后繼(為簡單起見,我暫時只講一下單向鏈表,至于雙向鏈表和循環鏈表,大家可以在單向鏈表的基礎上做一定擴展即可),每一個結點的空間由系統動態分配,我們稱之為動態鏈表;另一種是用游標(相當于指針)來指向它的后繼,每一個結點的空間由程序建立的“模擬空間分配站”來分配,這個“模擬空間分配站”實際上是一個事先給定足夠空間的結構數組,它為鏈表的結點分配空間,鏈表上釋放的結點空間再返回給“模擬空間分配, 站”,由于這個“模擬空間分配站”的空間是由系統事先靜態分配好空間的,所以稱這種鏈表為靜態鏈表。靜態鏈表滿足了那些不支持指針的高級語言(如BASIC和FORTRAN)需要鏈表的要求,它的使用方法和動態鏈表極為相似。 首先我們來了解動態鏈表。它的類型聲明和基本操作如下表所示: //-----------線性表的單鏈表存儲結構------------- typedef struct Node{ ??? ElemType data; ??? struct Node *next; } *LNode, *LinkList; //----------線性表的單鏈表基本操作------------ LinkList InitList(void); //構造一個空的線性表 ? void DestroyList(LinkList *L);//初始條件:線性表L已存在。 操作結果:銷毀線性表L。 ? LinkList MakeEmpty(LinkList L);//初始條件:線性表L已存在。 操作結果:將線性表L重置為空表。 ? int IsEmpty(LinkList L);//初始條件:線性表L已存在。 操作結果:判斷線性表是否為空表。 ? int ListLength(LinkList L);//初始條件:線性表L已存在。 操作結果:返回線性表L結點的個數。 ? LNode IsLast(LinkList L); //初始條件:線性表L已存在。 操作結果:返回線性表L的最后一個結點(尾結點)。 LNode NewLNode(ElemType X);//構造一個數據域為X的新結點 ? LNode FindPrefious(ElemType X, LinkList L);//初始條件:線性表L已存在。 操作結果:在線性表L中尋找值為X的結點,若找到則返回該結點的前驅,否則返回NULL。 ? void ListDelete(LNode Pre);//初始條件:線性表L中結點P已找到。 操作結果:刪除該結點。 ? void ListInsert(LNode Pre, LNode S);//初始條件:線性表L中結點P已找到,新結點S已構造。 操作結果:在該結點之前插入新結點X。 ? ----------線性表的單鏈表基本操作的算法實現------------ //我給鏈表設置了一個頭結點,雖然它的數據域毫無意義,但它作為一個指針卻意義非凡! //它的作用我們在下面的例程中可以領教 LinkList InitList(void) //構造一個空的線性表 { ??? LNode Head; ??????? ? ??? Head = (LNode)malloc(sizeof(struct Node)); //為鏈表的頭結點分配空間 ??? if(!Head) ??? { ??? ??? printf("Out of space!"); ??? ??? return NULL; ??? } ??? Head->next = NULL; ??? return Head;//返回頭結點 } ? void DestroyList(LinkList *L)//初始條件:線性表L已存在。 操作結果:銷毀線性表L。 { ?? LNode Head, P; ??? ??? if(*L)//若線性表L已存在 ??? { ??????? Head = *L; ??????? P = Head->next; ??? ??? while(!P)? //把鏈表中除頭結點外的所有結點釋放 ??????? { ??????? ??? free(Head); ??????? ??? Head = P; ??????????? P = Head->next;??????? ??? ?? } ??? ??? free(Head); //釋放頭結點 ??? } } ??? ? LinkList MakeEmpty(LinkList L)//初始條件:線性表L已存在。 操作結果:將線性表L重置為空表。 { ?? LNode Head, P; ? ??? Head = *L; ??? P = Head->next; ??? while(!P)//把鏈表中除頭結點外的所有結點釋放 ??? { ??? ??? free(Head); ??????? Head = P; ??????? P = Head->next; ??? ??? } ??? return (Head); //返回頭結點 } ? int IsEmpty(LinkList L);//初始條件:線性表L已存在。 操作結果:判斷線性表是否為空表。 { ??? return L->next == NULL; } ? int ListLength(LinkList L)//初始條件:線性表L已存在。 操作結果:返回線性表L結點的個數。 { ??? LNode P = L->next; ??? int num = 0; ??? ? ??? while(P) //累積線性表L結點的個數 ??? { ??? ??? num++; ??????? P = P->next; ??? } ?? return num;? //返回線性表L結點的個數 } ? //初始條件:線性表L已存在。 操作結果:返回線性表L的最后一個結點(尾結點)。 LNode IsLast(LinkList L) { ??? LNode P = L->next; ??? ??? if(P) ??? { ??? ??? while(P->next) //遍歷線性表L ??????????? P = P->next; ??? } ??? return P;? //返回線性表L的最后一個結點,若為空表則返回NULL } ? LNode NewLNode(ElemType X)//構造一個數據域為X的新結點 { ??? LNode S; ??? ??? S = (LNode)malloc(sizeof(struct Node))//為新結點分配空間 ??? if(!S) ??? { ??? ??? printf("Out of space!"); ??? ??? return NULL; ??? } ??? S->data = X; ??? S->next = NULL; ??? return S;//返回新結點 } ? //線性表L已存在。 操作結果:在線性表L中尋找值為X的結點,若找到則返回該結點的前驅,否則返回NULL。 LNode FindPrefious(ElemType X, LinkList L) { ??? LNode P = L; ??? ??? while(P->next && P->next->data != X)//遍歷鏈表尋找值為X的結點 ??????? P = P->next; ??? if(!P->next)? //如果找不到值為X的結點,返回NULL ??? ??? return NULL; ??? else???????? //若找到則返回該結點的前驅P ??? ??? return P;??? } ?????????????????????????? void ListDelete(LNode Pre)//初始條件:線性表L中結點P已找到。 操作結果:刪除該結點。 { ??? LNode P = Pre->next; ??? ??? Pre->next = P->next; ??? free(P); } //初始條件:線性表L中結點P已找到,新結點S已構造。。操作結果:在該結點之前插入新結點X。 void ListInsert(LNode Pre, LNode S) { ??? S->next = Pre->next; ??? Pre->next = S; } 注意:為操作方便起見,在執行函數void ListDelete(LNode Pre, LinkList L)

    和void ListInsert(LNode Pre, LNode X, LinkList L)時,通常把結點P的前驅Pre作為實參。而且這兩個函數通常與函數LNode FindPrefious(ElemType X, LinkList L)一起使用,即先查找結點,再執行插入或刪除操作。

    以上操作為線性單鏈表的最基本的操作,其他操作可以是上述操作的組合。如,執行“在線性表L中尋找值為X的結點,并刪除之”操作時,可先執行LNode FindPrefious(ElemType X, LinkList L),再執行void ListDelete(LNode Pre)。 又如,執行“把一個值為X的新結點插入結點P之前”,可先執行LNode FindPrefious(ElemType X, LinkList L),再執行LinkList NewLNode((ElemType X),最后執行void ListInsert(LNode Pre, LNode S)。

    我特意向大家推薦這種”堅持使用頭結點“和“鎖定前驅結點”的設計方法,這正是我和一般書本上有著不同理解的地方。有些書上的例程有時設置一個頭結點,還有些根本就不使用頭結點,也許是他們認為頭結點占地方罷,但我認為為了更方便的編程實現我們的意圖和更好的編程風格---主要指代碼清晰易讀,我再一次吐血推薦我的設計方法。因為這種設計方法就像一把萬能鑰匙---也許有些夸張了,呵呵!一般書上的例程在刪除或插入結點時,要分別討論鏈表頭,鏈表中和鏈表尾三種不同的情況,采取不同的操作;而我上面所列的”刪除“和”插入“操作可以全面搞定對鏈表中任意位置的結點(頭結點除外)插入和刪除功能。(除了”把新結點插入到鏈表尾“,但這可以組合執行LNode IsLast(LinkList L)和void ListInsert(LNode Pre, LNode S))。

    舉一個實際的例子。已知集合A={1,2,3,4,5},B={3,4,5,6,7,8,9,11},求集合A和B的交集。

    算法思路是先把集合A和B分別存入兩個單向鏈表LA和LB中,以LA的結點P為研究對象,遍歷LB,看是否有與其同值的結點,根據情況判斷是否執行刪除結點P的指令。最后得到的LA就是集合A和B的交集。

    具體的實現如下所示,因為函數部分已經包含在“線性表的單鏈表基本操作的算法實現“中,所以不做重復,只把其他的部分列出來。程序經過測試,可以運行。

    #include

    #include

    #include

    ?

    typedef int ElemType;

    typedef struct Node{

    ??? ElemType data;

    ??? struct Node *next;

    } *LNode, *LinkList;

    LinkList CreateList(ElemType a[], ElemType len);//用來構造一個鏈表

    。。。//其他函數聲明

    int main(void)

    {

    ?? LNode LA, LB, Pre,Flag;

    ?? ElemType X, A[5]={1,2,3,4,5}, B[8]={3,4,5,6,7,8,9,11};

    ?? //把集合A和B分別存入兩個單向鏈表LA和LB中

    ?? LA = CreateList(A, 5);

    ?? LB = CreateList(B, 8);

    ?? //以LA的結點P為研究對象,遍歷LB,看是否有與其同值的結點,根據情況判斷是否執行刪除結點P的指令

    ?? Pre = LA;

    ?? while(Pre->next)

    ?? {

    ??????? X = Pre->next->data;

    ??????? Flag = FindPrefious(X, LB);

    ??? ??? if(!Flag)

    ??????? ??? ListDelete(Pre);

    ??????? else

    ??????? ??? Pre = Pre->next;?

    ??? }

    ??? //輸出集合A和B的交集

    ? ? Pre = LA;

    ? ? printf("集合A和B的交集:\n");

    ? ??? if(!Pre->next)

    ? ? ??? printf("交集為空集!");

    ? ? else??????????

    ??? ? ??? while(Pre->next)

    ??? ?? {

    ??????????? X = Pre->next->data;

    ??????? ??? printf("%2d", X);

    ??????? ??? Pre = Pre->next;?

    ??????? }

    ??

    ? ??? system("pause");????

    ?? return 0;

    }

    ?

    LinkList CreateList(ElemType a[], ElemType len)//用來構造一個鏈表

    {

    ??? LNode L, S;

    ??? ElemType i;

    ??? ?

    ??? L = InitList(); //構造一個空的線性表

    ??? for(i=0; i

    ??? {

    ??????? S = NewLNode(a[i]); //構造一個數據域為a[i]的新結點

    ??? ??? ListInsert(L, S); //把新結點S插到頭結點后面。

    ??? }

    ??? return L;

    }??


    動態鏈表我們就先講到這里,實際上更讓我感興趣的是靜態鏈表。這種無需指針而有能夠實現鏈表功能的結構,對于那些不支持指針的高級語言來說,無疑是個巨大的福音。它既可以像數組一樣隨機存取數據---它本身就是一個數組,又具有鏈表方便地實現插入和刪除結點的功能;由于它是模擬的“動態分配空間”,實際上它的存儲空間是由系統一次性分配好了的,這樣在“動態分配空間”的時候,不需要內存管理程序,如果運行的Find函數相對較少,它實現的速度比動態鏈表要快很多;此外,他很少出現因為內存空間不夠的原因而導致程序不正常終止的情況,因為它的空間一早就分配好了,只要不超出鏈表的最大長度,空間就足夠。因此它真可以稱的上是一個“寶貝”。

    在鏈表的指針實現(即動態鏈表)中,有兩個重要的特點: 1.數據存儲在一組結構體中,每個結構包含有數據以及指向下一個結構體的指針. 2.一個新的結構體可以通過調用malloc()而從系統全局內存(global memory)得到,并可以通過調用 free()而被釋放. 靜態鏈表必須能夠模仿實現這兩條特性.滿足條件1的邏輯方法是要有一個全局的結構體數組.對于該數組中的任何單元(元素),其數組下標可以用來表示一個地址(結點).也就是說數組元素(結構體)包含有數據以及指向下一個結構體的游標---即下一個結點的數組下標.可以建立不同的鏈表,但實際上每一個鏈表都是結構體數組一部分元素的集合。 為了模擬條件2,我們需要建立一個“模擬空間分配站”,它是一個規模較大的結構體數組。我們可以建立不同的鏈表,實際上我們創造的每一個鏈表都來自這個“模擬空間分配站”,每一個結點都是該結構體數組的元素,每一個鏈表都是結構體數組一部分元素的集合。 它的類型聲明和基本操作如下表所示: //-------------------線性表的靜態單鏈表存儲結構------------------------ #define MAXSIZE 1000//鏈表的最大長度 typedef int Position; typedef int SLink; typedef struct Node{ ??? ElemType data; ??? Position next; } SLinkList[MAXSIZE]; //-------------------線性表的靜態單鏈表基本操作------------------------ static void InitSpace_SL(SLinkList Space);//構造一個“模擬空間分配站”,為全局變量 //初始條件:“模擬空間分配站”已存在。操作結果:"動態"分配空間 給結點P? static Position malloc_SL(void); //初始條件:“模擬空間分配站”已存在。操作結果:釋放結點P 的空間 到“模擬空間分配站” static void free_SL(Position P); Position MakeEmpty(SLink L);//初始條件:線性表L已存在。 操作結果:將線性表L重置為空表。 Position InitList(void); //構造一個空的線性表 void DestroyList(SLink L);//初始條件:線性表L已存在。 操作結果:銷毀線性表L。 int IsEmpty(SLink L);//初始條件:線性表L已存在。 操作結果:判斷線性表是否為空表。 int SListLength(SLink L);//初始條件:線性表L已存在。 操作結果:返回線性表L結點的個數。 Position NewSLNode(ElemType X);//構造一個數據域為X的新結點 //初始條件:線性表L和結點P已存在。操作結果:判斷P是否為鏈表L的結點 int LContaiP(SLink L, Position P); int IsLast(Position P); //初始條件:結點P已存在。 操作結果:判斷P是否為尾結點 Position FindPrefious(ElemType X, SLink L); //初始條件:線性表L已存在。操作結果:在線性表L中尋找值為X的結點,若找到則返回該結點的前驅,否則返回NULL。 void SListDelete(Position Pre);//初始條件:線性表L中結點P已找到。 操作結果:刪除該結點。 void SListInsert(Position Pre, Position S); //初始條件:線性表L中結點P已找到,新結點S已構造。操作結果:在該結點之前插入新結點X。 //-------------------線性表的靜態單鏈表基本操作的算法實現------------------------ static void InitSpace_SL(SLinkList Space)//構造一個“模擬空間分配站”,為全局變量 { ??? int i; ??? ??? for(i=0; i<MAXSIZE-1; i++) //每個結點的游標值均表示其后繼結點的數組下標 ??? { ??? ??? Space[i].next = i+1; ??? ??? Space[i].data = i+1; ??? } ??? Space[MAXSIZE-1].next = 0;//尾結點的后繼結點下標為0,即NULL } //初始條件:“模擬空間分配站”已存在。操作結果:"動態"分配空間 給結點P? static Position malloc_SL(void) { ??? Position P; ??? ??? P = Space[0].next;? //每一個結點的空間均從Space[0]這里取得,當前被取走的結點乃Space[0]的直接后繼 ??? Space[0].next = Space[P].next; //為P結點分配空間,實際上相當于出棧,Space[0]即棧頂 ??? return P;?? //把結點P從“模擬空間分配站”中取出來 ,并返回其值(實際上是一個數組下標) } ? //初始條件:“模擬空間分配站”已存在。操作結果:釋放結點P 的空間 到“模擬空間分配站” static void free_SL(Position P) { ??? ?Space[P].next = Space[0].next; ??? ?Space[0].next = P;//回收P結點的空間,實際上相當于入棧 ,Space[0]即棧頂 } ? Position MakeEmpty(SLink L)//初始條件:線性表L已存在。 操作結果:將線性表L重置為空表。 { ??? Position P = Space[L].next; ??? ??? while(P) ??? { ??? ??? free_SL(L); //從頭結點開始依次釋放回收結點的空間 ??????? L = P; ??????? P = Space[L].next; ??? }?? //最后使? Space[L].next = 0; } ? Position InitList(void) //構造一個空的線性表 { ??? SLink L; ??? ??? L = malloc_SL(); //為鏈表的頭結點分配空間 ??? if(!L) ??? { ??? ??? printf("Out of space!"); ??? ??? return 0; ??? } ??? Space[L].next = 0; //使頭結點的直接后繼為0,構造一個空的線性表 ??? return L; } ? void DestroyList(SLink L)//初始條件:線性表L已存在。 操作結果:銷毀線性表L。 { ??? Position P = Space[L].next; ??? ??? while(P) ??? { ??? ??? free_SL(L); //從頭結點開始依次釋放回收結點的空間 ??????? L = P; ??????? P = Space[L].next; ??? }? ??? ?free_SL(L);//把頭結點的空間也釋放回收,徹底銷毀線性表L } ? int IsEmpty(SLink L)//初始條件:線性表L已存在。 操作結果:判斷線性表是否為空表。 { ??? return Space[L].next == 0; } ? int SListLength(SLink L)//初始條件:線性表L已存在。 操作結果:返回線性表L結點的個數。 { ??? Position P = Space[L].next; ??? int num = 0; ??? ? ??? while(P) //累積線性表L結點的個數 ??? { ??? ??? num++; ??????? P = Space[P].next; ??? } ??? return num;? //返回線性表L結點的個數 } ? Position NewSLNode(ElemType X)//構造一個數據域為X的新結點 { ??? Position S; ??? ??? S = malloc_SL(); //為新結點分配空間? ??? if(!S) ??? { ??? ??? printf("Out of space!"); ??? ??? return 0; ??? } ??? Space[S].data = X; ??? Space[S].next = 0; ??? return S;//返回新結點 } ? //初始條件:線性表L和結點P已存在。操作結果:判斷P是否為鏈表L的結點 int LContaiP(SLink L, Position P) { ??? Position R = Space[L].next; ??? ??? while(R && R!=P) //遍歷整個鏈表 ??????? R = Space[R].next; ??? return R;//返回R,若P不是鏈表L的結點,則R=0,否則R不為0 } ? int IsLast(Position P) //初始條件:結點P已存在。 操作結果:判斷P是否為尾結點 { ??? return? Space[P].next == 0; } //初始條件:線性表L已存在。操作結果:在線性表L中尋找值為X的結點,若找到則返回該結點的前驅,否則返回NULL。 Position FindPrefious(ElemType X, SLink L) { ??? Position P = L; ??? ??? while(Space[P].next && Space[Space[P].next].data != X)//遍歷鏈表尋找值為X的結點 ??????? P = Space[P].next; ??? if(!Space[P].next)? //如果找不到值為X的結點,返回NULL ??? ??? return 0; ??? else???????? //若找到則返回該結點的前驅P ??? ??? return P;??? } ? void SListDelete(Position Pre)//初始條件:線性表L中結點P已找到。 操作結果:刪除該結點。 { ??? ?Position P; ??? ? ??? ?P = Space[Pre].next; //刪除結點P ??? ?Space[Pre].next = Space[P].next; ??? ?free_SL(P);//釋放回收結點P的空間 } //初始條件:線性表L中結點P已找到,新結點S已構造。操作結果:在該結點之前插入新結點X。 void SListInsert(Position Pre, Position S) { ??? ?Space[S].next = Space[Pre].next; ??? ?Space[Pre].next = S;

    }

    和動態鏈表一樣,以上操作為線性靜態單鏈表的最基本的操作,其他操作可以是上述操作的組合。

    例如要實現“判斷結點P是否為鏈表L的尾結點”操作,函數如下:

    int IsLLast(SLink L, Position P)

    {

    ??? if(LContaiP(L, P)

    ??? ??? return IsLast(P);

    ??? return 0;

    }

    如果你仔細的閱讀這些代碼,你會發現動態鏈表和靜態鏈表的基本操作的實現算法很相似,游標實現的接口和指針實現是一樣的。靜態鏈表可以代替動態鏈表實現,實際上在程序的其余部分不需要變化,而且速度更快。

    同樣的讓我們用一個實際的例子說明。已知集合A={1,2,3,4,5},B={3,4,5,6,7,8,9,11},求集合A和B的交集的非,即(A-B)并(B-A)。

    算法思路是先把集合A和B分別存入兩個單向鏈表LA和LB中,以LB的結點P為研究對象,遍歷LA,看是否有與其同值的結點,若有刪除與結點P相同的結點,否則把結點P插入鏈表LA。最后得到的LA就是集合A和B的交集的非。

    具體的實現如下所示,因為函數部分已經包含在“線性表的靜態單鏈表基本操作的算法實現“中,所以不做重復,只把其他的部分列出來。程序經過測試,可以運行。

    ?

    #include<stdio.h>

    #include<stdlib.h>

    #include<malloc.h>

    #define MAXSIZE 100//鏈表的最大長度

    typedef int Position;

    typedef int SLink;

    typedef int ElemType;

    typedef struct Node{

    ??? ElemType data;

    ??? Position next;

    } SLinkList[MAXSIZE];

    ?

    SLink CreateList(ElemType a[], ElemType len);//用來構造一個鏈表

    。。。//其他函數聲明

    int main(void)

    {

    ?? SLink LA, LB;

    ??? Position P, Pre, S;

    ?? ElemType X, A[5]={1,2,3,4,5}, B[8]={3,4,5,6,7,8,9,1};

    ?

    ?? InitSpace_SL(Space);//構造一個“模擬空間分配站”,為全局變量

    ?

    ?? //把集合A和B分別存入兩個單向鏈表LA和LB中

    ?? LA = CreateList(A, 5);

    ?? LB = CreateList(B, 8);

    ?? //以LB的結點P為研究對象,遍歷LA,看是否有與其同值的結點,若有刪除與結點P相同的結點,否則把結點P插入鏈表LA。

    ?? P = Space[LB].next;??

    ??? while(P)

    ?? {?

    ??????? X = Space[P].data;??? //把結點P的值賦給X

    ??? ??? Pre = FindPrefious(X, LA); //判斷LA中是否有與P同值的結點 ,返回同值結點的前驅? ???

    ??? ??? if(Pre)??? //若有,刪除結點PA??????????????????

    ??????? ??? SListDelete(Pre);

    ??? ??? else ?//否則

    ??????? {

    ??????? ??? ?S = NewSLNode(X); //構造一個數據域為X的新結點,即復制結點P到S

    ??????? ??? ?SListInsert(LA, S);? //把結點S插入鏈表LA

    ??????? }??? ?? ?

    ??????? P = Space[P].next;? //繼續分析鏈表中的下一個結點????????

    ??? }

    ??? //輸出集合A和B的交集的非

    ? ? Pre = LA;

    ? ??? printf("集合A和B的交集的非:\n");

    ? ??? if(!Space[Pre].next)

    ? ? ??? printf("交集的非為空集!");

    ? ? else?? //輸出鏈表LA的所有結點的值????????????

    ??? ? ??? while(Space[Pre].next)

    ??? ?? {

    ??????? ??? X = Space[Space[Pre].next].data;

    ??????? ??? printf("%d ", X);

    ??????? ??? Pre = Space[Pre].next;

    ??????? }

    ?? ??

    ? ??? system("pause");????

    ?? return 0;

    }

    ?

    SLink CreateList(ElemType a[], ElemType len)//用來構造一個鏈表

    {

    ??? SLink L, S;

    ??? int i;

    ??? ?

    ??? L = InitList(); //構造一個空的線性表

    ??? for(i=0; i<len; i++)

    ??? {?

    ??????? S = NewSLNode(a[i]); //構造一個數據域為a[i]的新結點

    ??? ??? SListInsert(L, S); //把新結點S插到頭結點后面。

    ??? }

    ??? return L;

    }?

    ?

    如果你用靜態鏈表去做“求集合A和B的交集”的題目,你會發現,它的主函數部分和用動態鏈表做幾乎一樣。

    提問:如果要同時求集合A和B的交集以及交集的非 ,又該怎么辦呢?

    提示:算法思路是先把集合A和B分別存入兩個單向鏈表LA和LB中,以LB的結點P為研究對象,遍歷LA,看是否有與其同值的結點,若有刪除與結點P相同的結點,否則把結點P插入鏈表LA;還要根據情況判斷是否執行刪除結點P的指令,以便得到A和B的交集。最后得到的LA就是集合A和B的交集的非;而LB是集合A和B的交集。

    主函數部分:

    int main(void)

    {

    ?? SLink LA, LB;

    ??? Position PreA, PreB, S;

    ?? ElemType X, A[5]={1,2,3,4,5}, B[8]={3,4,5,6,7,8,9,11};

    ?

    ?? InitSpace_SL(Space);//構造一個“模擬空間分配站”,為全局變量

    ?

    ?? //把集合A和B分別存入兩個單向鏈表LA和LB中

    ?? LA = CreateList(A, 5);

    ?? LB = CreateList(B, 8);

    ?? //以LB的結點P為研究對象,遍歷LA,看是否有與其同值的結點,若有刪除與結點P相同的結點,否則把結點P插入鏈表LA。

    ? //還要根據情況判斷是否執行刪除結點P的指令

    ?? PreB = LB; //PreB表示結點P的前驅,在所有的操作中,我們都不直接操作被處理的結點,而是操作其前驅??

    ??? while(Space[PreB].next)

    ?? {?

    ??????? X = Space[Space[PreB].next].data;? //把結點PB的值賦給X

    ??? ??? PreA = FindPrefious(X, LA); //判斷LA中是否有與PB同值的結點 ,返回同值結點的前驅

    ??? ??? if(PreA)? //若有,刪除結點PA,繼續分析鏈表中的下一個結點

    ??????? {????????????????????????????

    ??????? ??? SListDelete(PreA);

    ??????? ??? PreB = Space[PreB].next;?

    ??????? }

    ??? ??? else //否則

    ??????? {

    ??????? ??? ?S = NewSLNode(X); //構造一個數據域為X的新結點,即復制結點PB到S

    ??????? ??? ?SListInsert(LA, S);//把結點S插入鏈表LA???

    ??????? ??? ?SListDelete(PreB); //刪除鏈表LB的結點PB

    ??????? }??? ?? ??? ???

    ??? }

    ??? //輸出集合A和B的交集的非

    ? ? PreA = LA;

    ? ??? printf("集合A和B的交集的非:\n");

    ? ??? if(!Space[PreA].next)

    ? ? ??? printf("交集的非為空集!");

    ? ? else??????????

    ??? ? ??? while(Space[PreA].next)

    ??? ?? {

    ??????? ??? X = Space[Space[PreA].next].data;

    ??????? ??? printf("%d ", X);

    ??????? ??? PreA = Space[PreA].next;???

    ??????? }

    ?? //輸出集合A和B的交集?

    ??? PreB = LB;

    ? ??? printf("\n集合A和B的交集:\n");

    ? ??? if(!Space[PreB].next)

    ? ? ??? printf("交集為空集!");

    ? ? else??????????

    ??? ? ??? while(Space[PreB].next)

    ??? ?? {

    ??????? ??? X = Space[Space[PreB].next].data;

    ??????? ??? printf("%d ", X);

    ??????? ??? PreB = Space[PreB].next;???

    ??????? }?

    ? ??? system("pause");????

    ?? return 0;

    }


    posted on 2007-03-18 10:26 金家寶 閱讀(525) 評論(0)  編輯  收藏 所屬分類: 數據結構和算法


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 无码天堂亚洲国产AV| 亚洲国产高清在线精品一区 | 亚洲最大福利视频网站| 精品免费tv久久久久久久| 国产亚洲精品无码成人| a毛片久久免费观看| 亚洲AV无码一区二区三区DV| 久久精品视频免费看| 亚洲最新中文字幕| 在线免费观看一级毛片| 香港一级毛片免费看| 亚洲人成影院在线无码按摩店| 99久久婷婷免费国产综合精品| 亚洲av日韩av无码| 成人AV免费网址在线观看| 亚洲国产精品日韩av不卡在线| 免费一区二区三区四区五区 | 99精品视频在线观看免费播放| 久久亚洲AV无码精品色午夜麻豆 | 国产精品无码永久免费888 | 亚洲男人的天堂久久精品| 女性无套免费网站在线看| 羞羞视频免费网站日本| 亚洲AV无码AV男人的天堂| 一二三四视频在线观看中文版免费 | 成人影片一区免费观看| 亚洲精品一卡2卡3卡三卡四卡| 拨牐拨牐x8免费| av片在线观看永久免费| 久久精品亚洲一区二区三区浴池| 成人免费视频软件网站| 久青草视频在线观看免费| 亚洲欧洲尹人香蕉综合| 免费国产成人午夜私人影视| 久9这里精品免费视频| WWW国产亚洲精品久久麻豆| 亚洲国产三级在线观看| 天天看免费高清影视| 日韩免费高清播放器| 亚洲欧美国产欧美色欲| 亚洲人成电影在线天堂|