本節討論最簡單和最基本的三種數據結構:表,棧和隊列。node
每種程序都明晰地至少使用一種這樣的數據結構,而棧在程序中總要間接地用到。算法
內容:編程
1.介紹抽象數據類型(ADT)的概念;小程序
2.闡述如何對錶進行有效的操做;數組
3.介紹棧ADT及其在實現遞歸方面的應用;數據結構
4.介紹隊列ADT及其在操做系統和算法設計上的與應用。模塊化
(1)抽象數據類型函數
程序設計的基本法則之一是:例程不該超過一頁。測試
模塊化的優勢:spa
1)調試小程序比調試大程序容易的多;
2)多我的同時對一個模塊式程序編程更加容易;
3)一個寫得好的模塊化程序把某些依賴關係只侷限在一個例程中,這樣使得修改起來更加容易。
由模塊化是有益的能夠推出:全局變量和反作用是有害的。
抽象數據類型(abstract data type ADT)是一些操做的集合。對諸如表、集合、圖和他們的操做一塊兒可看做是抽象數據類型。對於集合ADT,咱們有諸如並,交,測定大小以及取餘等操做。或者咱們也能夠只要兩種操做:並和查找,這兩種操做又在集合上定義了一種不一樣的ADT。
(2)表ADT
幾個概念:
1)空表:大小爲0的表;
2)後繼元:當前元素的後一個;
3)前驅元:當前元素的前一個;
與ADT的定義有關的就是在ADT上進行操做的集合了:printList,makeEmpty,find,findKth,findPreviousinsert,delete等。
2.1表的簡單數組實現:
對錶的全部操做均可以使用數組來實現。雖然數組是動態指定的,可是仍是須要對錶的大小的最大值進行估算。這會致使有可能浪費大量的空間。數組實現使得PrintList和Find以線性時間執行,FindKth以常數時間。而插入和刪除的代價昂貴。
由於插入和刪除的運行時間是如此的慢以及表的大小必須事先已知,因此簡單數組通常不用來實現表這種結構。
2.2鏈表
爲了不插入和刪除的線性開銷,咱們容許表能夠不連續存儲。
鏈表由一系列在沒必要再內存中相連的結構組成。每個結構均包含表元素和包含指向該元素後繼元的Next指針。最後一個單元的Next指針指向NULL,ANSI C規定NULL爲0;
圖:
一個鏈表:
從鏈表中刪除一個元素:
向鏈表中插入:
2.3程序設計細節:
可能遇到的問題:
1)不存在從所給定義出發在表的前面插入元素的真正顯示的方法;
2)從表的前面實行刪除是一個特殊狀況,由於它改變了表的起始段,在編程中對疏忽可能致使表的丟失。
3)在通常的刪除中要求咱們記住被刪除單元前面的表元。
爲了解決這個問題,咱們一般留出一個標記結點,有時咱們稱之爲表頭(header)或者啞結點(dummy node)。同時爲了不刪除中的一些問題,咱們須要編寫例程findPrevious返回咱們要刪除表元的前驅元的位置。表頭的使用可以使咱們表達基本的指針操做而又不導致特殊情形的代碼含糊不清。
在處理鏈表的刪除操做的相關問題時,咱們須要編寫例程findPrevious(),它將返回咱們要刪除的表元的前驅元的位置。若是咱們使用頭節點,那麼當咱們刪除表的第一個元素時,findPrevious()將返回表頭的位置。
2.4單向鏈表:
單向鏈表的ADT的例程:
#ifndef_List_H struct Node; typedef struct Node *PtrToNode; typedef PtrToNode List;//另起一個名字 typedef PtrToNode Position; typedef int ElementType; List MakeEmpty(List L); int IsEmtpy(List L); int IsLast(Position P,List L); Position Find(ElementType X,List L); void Delete(ElementType X,List L); Position FindPrevious(ElementType X,List L); void Insert(ElementType X,List L,Position P); void DeleteList(List L); Position Header(List L); Position First(List L); ElementType Retrieve(Position P); #endif /* _List_H */ /*Node結點的聲明是在.c文件中(Place in the implementation file)*/ struct Node{ ElementType Element; Position Next; }; //測試一個鏈表是否爲空表 int IsEmtpy(List L){ return L->Next==NULL; } //測試當前位置是否是鏈表的尾部 int IsLast(Position P,List L){ return P->next==NULL; } //Find例程 Position Find(ElementType X,List L){ Position P; P=P->Next; while(P!=NULL&&P->Element!=X){ P=P->Next; } return P; } //鏈表的刪除例程 void Delete(ElementType X,List L){ Position P,TmpCell; P=FindPrevious(X,L); if(!IsLast(P,L)){ //這裏須要判斷是不是鏈表的最後一個結點,若是是,則表示找的元素未在鏈表中 TmpCell=P->Next; P->Next=TmpCell->Next; free(TmpCell); } } //找到元素結點的前一個結點,找不到就返回鏈表的最後的結點 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 TmpCell; TmpCell=malloc(sizeof(struct Node)); if(TmpCell==NULL){ printf("Error!\n"); }else{ TmpCell->Element=X; TmpCell->Next=P->Next; P->Next=TmpCell; } } void DeleteList(List L){ Position P,Tmp; P=L->Next; L->Next=NULL; while(P!=NULL){ Tmp=p; P=P->Next; free(Tmp); } }
在表的例程運用中的幾個提醒:
1.指針變量包含僞地址,系統提醒"memory access vialation"或"segmentation violation"。例如:{free(p);p=p->Next;}
2.聲明一個指向結構的指針並不建立該結構,而只是給出足夠的空間容納結構可能使用的地址。建立還沒有聲明過的記錄的通常方法是使用malloc庫函數。malloc建立一個新的結構並返回指向該結構體的指針。一些比較老的編譯器須要在malloc的前面加上類型轉換(type cast)。C語言提供了兩種動態分配內存空間的庫函數,malloc和calloc。他們都要求包含stdlib頭文件。
3.free(p)的做用是:p正在指向的地址沒變,但在該地址處的數據此時已經無定義了。
4.malloc(sizeof(PtrToNode))是合法的,可是它並不給結構體分配足夠的內存空間,他只給指針分配內存空間。
單向鏈表的實例:
1)生成100個隨機整數並放入一個鏈表中,要求鏈表中的元素按從小到大順序排列:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<time.h> 4 5 struct Node{ 6 int Element; 7 struct Node *Next; 8 }; 9 typedef struct Node *List; 10 typedef struct Node *PtrToNode; 11 12 List create(){ 13 List L; 14 PtrToNode header=malloc(sizeof(struct Node)); 15 header->Next=NULL; 16 L=header; 17 return L; 18 } 19 20 //遞歸的有序的插入 21 void InsertRecursive(PtrToNode temp,List L){ 22 PtrToNode p=L; 23 if(p->Next==NULL){ 24 temp->Next=p->Next; 25 p->Next=temp; 26 } 27 else if(p->Next!=NULL){ 28 if(temp->Element<=p->Next->Element){ 29 temp->Next=p->Next; //temp指向p的指向的下一個元素 30 p->Next=temp; //p指向temp 31 }else if(temp->Element>p->Next->Element){ 32 InsertRecursive(temp,p->Next); 33 } 34 } 35 } 36 37 //非遞歸有序的插入 38 void InsertUnRecursive(PtrToNode temp,List L){ 39 PtrToNode p=L; 40 //一個元素也沒插入時 41 if(p->Next==NULL){ 42 temp->Next=p->Next; 43 p->Next=temp; 44 return; 45 } 46 //只有一個元素時 47 if((p->Next!=NULL)&&(p->Next->Next==NULL)){ 48 if((temp->Element)<=(p->Next->Element)){ 49 temp->Next=p->Next; 50 p->Next=temp; 51 }else if(temp->Element>p->Next->Element){ 52 temp->Next=p->Next->Next; 53 p->Next->Next=temp; 54 } 55 return; 56 } 57 while(p->Next!=NULL&&p->Next->Next!=NULL){ 58 if(temp->Element<=p->Next->Element){ 59 temp->Next=p->Next; 60 p->Next=temp; 61 return; 62 }else if(temp->Element>p->Next->Element&&temp->Element<=p->Next->Next->Element){ 63 temp->Next=p->Next->Next; 64 p->Next->Next=temp; 65 return; 66 }else{ 67 p=p->Next; 68 } 69 //有兩個元素,但執行p=p->Next時有可能碰到p->Next->Next==NULL; 70 if(p->Next->Next==NULL){ 71 if((temp->Element)<=(p->Next->Element)){ 72 temp->Next=p->Next; 73 p->Next=temp; 74 }else if(temp->Element>p->Next->Element){ 75 temp->Next=p->Next->Next; 76 p->Next->Next=temp; 77 } 78 return; 79 } 80 } 81 } 82 83 void printAll(List list){ 84 PtrToNode p=list; 85 int flag=1; 86 while(p->Next!=NULL){ 87 printf("a[%2d]=%3d ",flag,p->Next->Element); 88 p=p->Next; 89 if(flag%10==0){ 90 printf("\n"); 91 } 92 flag++; 93 } 94 } 95 96 int main(){ 97 srand(time(NULL)); 98 List list=create(); 99 int i,x; 100 PtrToNode p; 101 //InsertRecursive與InsertUnRecursive函數具備同樣的功能: 102 for(i=0;i<50;i++){ 103 x=rand()%1000; 104 p=malloc(sizeof(struct Node)); 105 p->Element=x; 106 InsertRecursive(p,list); 107 } 108 for(i=0;i<50;i++){ 109 x=rand()%1000; 110 p=malloc(sizeof(struct Node)); 111 p->Element=x; 112 InsertUnRecursive(p,list); 113 } 114 //輸出插入的結果 115 printAll(list); 116 }
2)將兩個從小到大排列的鏈表合併爲一個新鏈表,要求:
(1)原來的兩個鏈表不保存(合併時,無需生成新的空間來存放每一個結點,直接將全部結點合併爲新鏈表)
(2)原來的兩個鏈表不做改變(合併時,對每個結點須要複製併產生新鏈表)
(3)對以上兩小題,若鏈表中遇到有相同的元素,則在合併時去掉重複元素。(固然,你也能夠在鏈表合併完之後再掃描整個鏈表去掉重複元素,但這須要額外的運行時間,所以並非一個好的辦法)
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<time.h> 4 5 struct Node{ 6 int Element; 7 int flag; //用來不重複插入相同數據,作個標記 8 struct Node *Next; 9 }; 10 11 typedef struct Node *List; 12 typedef struct Node *PtrToNode; 13 typedef PtrToNode Position; 14 15 //建立具備頭節點的鏈表 16 List create(){ 17 List L; 18 PtrToNode header=malloc(sizeof(struct Node)); 19 header->Next=NULL; 20 L=header; 21 return L; 22 } 23 //執行插入操做,參數表示,element將插入到posi所指向的元素的後面 24 void Insert(int element,List list,Position posi){ 25 PtrToNode p=list;//用做循環遍歷鏈表,找到地址與posi相同的結點 26 PtrToNode temp;//用來新建結點 27 while(p!=posi){ 28 p=p->Next; 29 }//找到posi所在位置 30 if(p==list){//a1.當位置在頭節點 31 if(p->Next==NULL){//a1.b1在頭節點,當頭結點的下一個爲空時,直接插入 32 temp=malloc(sizeof(struct Node)); 33 temp->Element=element; 34 temp->flag=1; 35 temp->Next=p->Next; 36 p->Next=temp; 37 }else{//a1.b2在頭節點,當頭結點的下一個不爲空時 38 if(element==p->Next->Element){//a1.b2.c1當要插入的元素與位置指向的下一個元素相同時,不用重複插入 39 p->Next->flag++; 40 }else{//a1.b2.c2不一樣時,確定小於,因此插入 41 temp=malloc(sizeof(struct Node)); 42 temp->Element=element; 43 temp->flag=1; 44 temp->Next=p->Next; 45 p->Next=temp; 46 } 47 } 48 //a2.當位置不在頭節點 49 }else if(p!=list){ 50 if(element==posi->Element){//a2.b1當要插入元素與當前位置元素相同時,不插入 51 posi->flag++; 52 return; 53 }else{//a2.b2當不一樣時,確定大於當前元素 54 temp=malloc(sizeof(struct Node)); 55 temp->Element=element; 56 temp->flag=1; 57 temp->Next=p->Next; 58 p->Next=temp; 59 } 60 } 61 } 62 63 //一下這部分的功能是找到要插入的位置 64 Position FindInsertPosition(List list,int element){ 65 PtrToNode p=list; 66 Position position; 67 while(p!=NULL){ 68 if(p->Next==NULL){//a1若是下一個元素爲空,則必定是這個位置 69 position=p; 70 break; 71 }else if(p->Next!=NULL){//a2若是下一個不爲空 72 if(element<=p->Next->Element){//a2.b1要插入元素小於或等於下一個元素,均可以插在p和p指向的下一個元素之間 73 position=p; 74 break; 75 }else if(element>p->Next->Element){//a2.b2當要插入元素還大於p指向的下一個元素時,確定插入點在下一個元素的後面,只需循環遍歷 76 p=p->Next; 77 } 78 } 79 } 80 return position; 81 } 82 83 void InsertWithNode(PtrToNode temp,List list,Position posi){ 84 PtrToNode p=list;//用做循環遍歷鏈表,找到地址與posi相同的結點 85 int element=temp->Element; 86 while(p!=posi){ 87 p=p->Next; 88 }//找到posi所在位置 89 if(p==list){//a1.當位置在頭節點 90 if(p->Next==NULL){//a1.b1在頭節點,當頭結點的下一個爲空時,直接插入 91 temp->Next=p->Next; 92 p->Next=temp; 93 }else{//a1.b2在頭節點,當頭結點的下一個不爲空時 94 if(element==p->Next->Element){//a1.b2.c1當要插入的元素與位置指向的下一個元素相同時,不用重複插入 95 p->Next->flag+=temp->flag; 96 free(temp); 97 }else{//a1.b2.c2不一樣時,確定小於,因此插入 98 temp->Next=p->Next; 99 p->Next=temp; 100 } 101 } 102 //a2.當位置不在頭節點 103 }else if(p!=list){ 104 if(element==posi->Element){//a2.b1當要插入元素與當前位置元素相同時,不插入 105 posi->flag+=temp->flag; 106 free(temp); 107 return; 108 }else{//a2.b2當不一樣時,確定大於當前元素 109 temp->Next=p->Next; 110 p->Next=temp; 111 } 112 } 113 } 114 List UnitTwoList(List list1,List list2){ 115 //讓將要返回的鏈表先指向第一個,而後將第二個鏈表的每一個元素依次插入 116 List list=list1; 117 PtrToNode ptr=list2->Next; 118 Position position; 119 PtrToNode ptrD=ptr; 120 while(ptr!=NULL){ 121 //對於鏈表2中的每一個元素都要依次找出其在鏈表1中須要插入的位置 122 position=FindInsertPosition(list,ptr->Element); 123 //Insert(ptr->Element,list,position); 124 //ptr=ptr->Next; 125 ptrD=ptr->Next; 126 InsertWithNode(ptr,list,position); 127 ptr=ptrD; 128 } 129 return list; 130 } 131 132 void printListWithFlag(List list){ 133 PtrToNode p=list->Next; 134 int i,t=1; 135 while(p!=NULL){ 136 for(i=1;i<=p->flag;i++){ 137 printf("L[%2d]=%3d ",t,p->Element); 138 if(t%10==0){ 139 printf("\n"); 140 } 141 t++; 142 } 143 p=p->Next; 144 } 145 } 146 147 void initList(List list){ 148 int x,i; 149 Position position; 150 for(i=0;i<50;i++){ 151 x=rand()%1000; 152 printf("%4d",x); 153 if((i+1)%25==0){ 154 printf("\n"); 155 } 156 position=FindInsertPosition(list,x); 157 Insert(x,list,position); 158 } 159 } 160 int main(){ 161 srand(time(NULL)); 162 List list_a=create(); 163 List list_b=create(); 164 //初始化第一個鏈表 165 initList(list_a); 166 //初始化第二個鏈表 167 initList(list_b); 168 printf("\n"); 169 printf("輸出list_a:\n"); 170 printListWithFlag(list_a); 171 printf("輸出list_b:\n"); 172 printListWithFlag(list_b); 173 List list=UnitTwoList(list_a,list_b); 174 printf("輸出合併後的list:\n"); 175 printListWithFlag(list); 176 return 0; 177 }
2.5雙向鏈表:
雙向鏈表用來倒序掃描鏈表很方便,並且簡化了刪除操做,再也不迫使使用一個指向前驅元的指針來訪問一個關鍵字。
實例:編寫程序,從鍵盤輸入10個整數並放入一個循環雙向鏈表中(不排序),而後按輸入順序輸出這些整數和逆序輸出這些整數。
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<time.h> 4 5 struct Node{ 6 struct Node *Pre; 7 int Element; 8 struct Node *Next; 9 }; 10 typedef struct Node *List; 11 typedef struct Node *PtrToNode; 12 13 List create(){ 14 List list; 15 PtrToNode header,tailer; 16 header=malloc(sizeof(struct Node)); 17 tailer=malloc(sizeof(struct Node)); 18 list=header; 19 header->Pre=tailer; 20 header->Next=tailer; 21 tailer->Pre=header; 22 tailer->Next=header; 23 return list; 24 } 25 void Insert(List list,int x){ 26 PtrToNode temp; 27 PtrToNode p=list; 28 temp=malloc(sizeof(struct Node)); 29 temp->Element=x; 30 31 while(p->Next!=list){ 32 p=p->Next;//找到尾節點 33 } 34 temp->Next=p; 35 temp->Pre=p->Pre; 36 p->Pre->Next=temp; 37 p->Pre=temp; 38 39 } 40 void PrintTwoDListOrder(List list){ 41 printf("依次順序輸出的結果爲:\n"); 42 PtrToNode p=list; 43 int i=1; 44 while(p->Next!=list){ 45 if(p->Next!=list->Pre){ 46 printf("第%d個元素爲%2d ",i,p->Next->Element); 47 p=p->Next; 48 if(i%5==0){ 49 printf("\n"); 50 } 51 i++; 52 continue; 53 } 54 break; 55 } 56 } 57 void PrintTwoDListNOrder(List list){ 58 printf("依次逆序輸出的結果爲:\n"); 59 PtrToNode p=list->Pre; 60 int i=1; 61 while(p->Pre!=list->Pre){ 62 if(p->Pre!=list){ 63 printf("第%d個元素爲%2d ",i,p->Pre->Element); 64 p=p->Pre; 65 if(i%5==0){ 66 printf("\n"); 67 } 68 i++; 69 continue; 70 } 71 break; 72 } 73 } 74 int main(){ 75 //建立一個有頭有尾的雙向鏈表 76 srand(time(NULL)); 77 List list=create(); 78 int i,x; 79 for(i=0;i<10;i++){ 80 x=rand()%100; 81 printf("生成的隨機數爲%2d ",x); 82 if((i+1)%5==0){ 83 printf("\n"); 84 } 85 Insert(list,x); 86 } 87 PrintTwoDListOrder(list); 88 PrintTwoDListNOrder(list); 89 return 0; 90 }
雙向鏈表的另外一個特例是循環鏈表,即讓最後的單元反過來指向第一個單元。循環鏈表也能夠不是雙向鏈表。這種結構在某些應用程序中很流行。
2.6十字鏈表
主鏈表上的每一個結點都是支鏈表的頭結點:
實例:隨機抽取20張撲克牌(撲克牌有兩項數據,一爲花色,二爲大小),花色按黑桃、紅桃、梅花、方塊次序排列,要求創建鏈表來存放這些撲克牌,最後輸出。
(1)先按花色,再按大小排列
(2)先按大小,再按花色排列
注:一副牌共有52張,每張不能重複,請考慮如何隨機產生不重複的牌。
先按花色排序,後按大小:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<time.h> 4 5 struct Poker{ 6 int Element; 7 int Color; 8 int Num; 9 struct Poker *mainNext; 10 struct Poker *BranchNext; 11 }; 12 typedef struct Poker *List; 13 typedef struct Poker *PtrToNode; 14 15 void InitNode(PtrToNode p){ 16 if(p->Element%13==0){ 17 p->Num=13; 18 p->Color=p->Element/13-1; 19 }else{ 20 p->Num=p->Element%13; 21 p->Color=p->Element/13; 22 } 23 } 24 //用數組輔助產生不重複的52之內的無序的整數20個包含52 25 void InitDisOrder(int a[]){ 26 int s[52]; 27 int i,x; 28 for(i=0;i<52;i++){ 29 s[i]=1; 30 } 31 for(i=0;i<20;i++){ 32 L: x=rand()%52;//產生1到52的隨機數 33 if(s[x]==0){ 34 goto L; 35 }else{ 36 a[i]=x+1; 37 s[x]=0; 38 } 39 } 40 } 41 //用數組輔助產生不重複的有序的整數20個包括52 42 void InitOrder(int a[]){ 43 int s[52]; 44 int i,j,x; 45 for(i=0;i<52;i++){ 46 s[i]=1; 47 } 48 for(i=0;i<20;i++){ 49 L: x=rand()%52; 50 if(s[x]==0){ 51 goto L; 52 }else 53 s[x]=0; 54 } 55 for(i=0;i<52;i++){ 56 if(s[i]==0){ 57 a[j]=i+1; 58 j++; 59 }else 60 continue; 61 } 62 } 63 PtrToNode InsertBranch(List list,int x){ 64 PtrToNode p1,p2,temp; 65 p1=p2=list; 66 temp=malloc(sizeof(struct Poker)); 67 temp->Element=x; 68 temp->mainNext=NULL; 69 temp->BranchNext=NULL; 70 InitNode(temp); 71 while(p1!=NULL){ 72 if(temp->Num<p1->Num){ 73 temp->BranchNext=p1; 74 if(p2==list&&p1==p2){ 75 list=temp; 76 return list; 77 }else 78 p2->BranchNext=temp; 79 return list; 80 } 81 else if(temp->Num>p1->Num){ 82 p2=p1; 83 p1=p1->BranchNext; 84 //當p1==NULL,下一步會跳出while循環,也能夠放在while後 85 if(p1==NULL){ 86 temp->BranchNext=NULL; 87 p2->BranchNext=temp; 88 } 89 } 90 } 91 return list; 92 } 93 List InsertMain(List list,int x){ //(x/13表明花色,x%13表明大小) 94 PtrToNode p1,p2,temp; 95 p1=p2=list; 96 temp=malloc(sizeof(struct Poker)); 97 temp->Element=x; 98 InitNode(temp); 99 temp->mainNext=NULL; 100 temp->BranchNext=NULL; 101 //printf("\n%d=%d,%d",temp->Element,temp->Color,temp->Num); 102 if(list==NULL){ 103 list=temp; 104 } 105 else 106 while(p1!=NULL){ 107 if(temp->Color<p1->Color){ 108 if(p2==list&&p1==p2){ 109 temp->mainNext=p1; 110 list=temp; 111 }else{ 112 temp->mainNext=p1; 113 p2->mainNext=temp; 114 } 115 return list; 116 }else if(temp->Color==p1->Color){ 117 PtrToNode p3=p1->mainNext; 118 PtrToNode p4=p1; 119 PtrToNode p=InsertBranch(p1,x); 120 p->mainNext=p3; 121 if(p2==list&&p2==p4){ 122 list=p; 123 }else{ 124 p2->mainNext=p; 125 } 126 return list; 127 }else{ 128 p2=p1; 129 p1=p1->mainNext; 130 if(p1==NULL){ 131 temp->mainNext=NULL; 132 temp->BranchNext=NULL; 133 p2->mainNext=temp; 134 } 135 } 136 }//while結束 137 return list; 138 } 139 void printSingleList(List list){ 140 PtrToNode p1; 141 p1=list; 142 while(p1!=NULL){ 143 switch(p1->Color){ 144 case 0:printf("黑桃");break; 145 case 1:printf("紅桃");break; 146 case 2:printf("梅花");break; 147 case 3:printf("方塊");break; 148 } 149 printf("%2d ",p1->Num); 150 p1=p1->BranchNext; 151 } 152 } 153 void printDoubleList(List list){ 154 PtrToNode p=list; 155 while(p!=NULL){ 156 switch(p->Color){ 157 case 0:printf("\n下面輸出黑桃的數字排序:\n\t");break; 158 case 1:printf("\n下面輸出紅桃的數字排序:\n\t");break; 159 case 2:printf("\n下面輸出梅花的數字排序:\n\t");break; 160 case 3:printf("\n下面輸出方塊的數字排序:\n\t");break; 161 default:printf("沒有這個花色:\n");exit(0); 162 } 163 printSingleList(p); 164 p=p->mainNext; 165 } 166 } 167 void Warn(){ 168 printf("本程序的規定:\n"); 169 printf("\t1到13表明黑桃 14到26表明紅桃 27到39表明梅花 40到52表明方塊。\n\n" ); 170 } 171 int main(){ 172 Warn(); 173 PtrToNode temp; 174 int i; 175 srand(time(NULL)); 176 int select[20]; 177 InitDisOrder(select); 178 for(i=0;i<20;i++){ 179 temp=malloc(sizeof(struct Poker)); 180 temp->Element=select[i]; 181 temp->BranchNext=NULL; 182 InitNode(temp); 183 printSingleList(temp); 184 if((i+1)%10==0){ 185 printf("\n"); 186 } 187 } 188 List list=NULL; 189 for(i=0;i<20;i++){ 190 list=InsertMain(list,select[i]); 191 } 192 printDoubleList(list); 193 printf("\n"); 194 return 0; 195 }
再先按大小後按花色排序:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<time.h> 4 5 struct Poker{ 6 int Element; 7 int Color; 8 int Num; 9 struct Poker *mainNext; 10 struct Poker *BranchNext; 11 }; 12 typedef struct Poker *List; 13 typedef struct Poker *PtrToNode; 14 15 void InitNode(PtrToNode p){ 16 if(p->Element%13==0){ 17 p->Num=13; 18 p->Color=p->Element/13-1; 19 }else{ 20 p->Num=p->Element%13; 21 p->Color=p->Element/13; 22 } 23 } 24 //用數組輔助產生不重複的52之內的無序的整數20個包含52 25 void InitDisOrder(int a[]){ 26 int s[52]; 27 int i,x; 28 for(i=0;i<52;i++){ 29 s[i]=1; 30 } 31 for(i=0;i<20;i++){ 32 L: x=rand()%52;//產生1到52的隨機數 33 if(s[x]==0){ 34 goto L; 35 }else{ 36 a[i]=x+1; 37 s[x]=0; 38 } 39 } 40 } 41 //用數組輔助產生不重複的有序的整數20個包括52 42 void InitOrder(int a[]){ 43 int s[52]; 44 int i,j,x; 45 for(i=0;i<52;i++){ 46 s[i]=1; 47 } 48 for(i=0;i<20;i++){ 49 L: x=rand()%52; 50 if(s[x]==0){ 51 goto L; 52 }else 53 s[x]=0; 54 } 55 for(i=0;i<52;i++){ 56 if(s[i]==0){ 57 a[j]=i+1; 58 j++; 59 }else 60 continue; 61 } 62 } 63 PtrToNode InsertBranch(List list,int x){ 64 PtrToNode p1,p2,temp; 65 p1=p2=list; 66 temp=malloc(sizeof(struct Poker)); 67 temp->Element=x; 68 temp->mainNext=NULL; 69 temp->BranchNext=NULL; 70 InitNode(temp); 71 while(p1!=NULL){ 72 if(temp->Color<p1->Color){ 73 temp->BranchNext=p1; 74 if(p2==list&&p1==p2){ 75 list=temp; 76 return list; 77 }else 78 p2->BranchNext=temp; 79 return list; 80 } 81 else if(temp->Color>p1->Color){ 82 p2=p1; 83 p1=p1->BranchNext; 84 //當p1==NULL,下一步會跳出while循環,也能夠放在while後 85 if(p1==NULL){ 86 temp->BranchNext=NULL; 87 p2->BranchNext=temp; 88 } 89 } 90 } 91 return list; 92 } 93 List InsertMain(List list,int x){ //(x/13表明花色,x%13表明大小) 94 PtrToNode p1,p2,temp; 95 p1=p2=list; 96 temp=malloc(sizeof(struct Poker)); 97 temp->Element=x; 98 InitNode(temp); 99 temp->mainNext=NULL; 100 temp->BranchNext=NULL; 101 //printf("\n%d=%d,%d",temp->Element,temp->Color,temp->Num); 102 if(list==NULL){ 103 list=temp; 104 } 105 else 106 while(p1!=NULL){ 107 if(temp->Num<p1->Num){ 108 if(p2==list&&p1==p2){ 109 temp->mainNext=p1; 110 list=temp; 111 }else{ 112 temp->mainNext=p1; 113 p2->mainNext=temp; 114 } 115 return list; 116 }else if(temp->Num==p1->Num){ 117 PtrToNode p3=p1->mainNext; 118 PtrToNode p4=p1; 119 PtrToNode p=InsertBranch(p1,x); 120 p->mainNext=p3; 121 if(p2==list&&p2==p4){ 122 list=p; 123 }else{ 124 p2->mainNext=p; 125 } 126 return list; 127 }else{ 128 p2=p1; 129 p1=p1->mainNext; 130 if(p1==NULL){ 131 temp->mainNext=NULL; 132 temp->BranchNext=NULL; 133 p2->mainNext=temp; 134 } 135 } 136 }//while結束 137 return list; 138 } 139 void printSingleList(List list){ 140 PtrToNode p1; 141 p1=list; 142 while(p1!=NULL){ 143 switch(p1->Color){ 144 case 0:printf("黑桃");break; 145 case 1:printf("紅桃");break; 146 case 2:printf("梅花");break; 147 case 3:printf("方塊");break; 148 } 149 printf("%2d ",p1->Num); 150 p1=p1->BranchNext; 151 } 152 } 153 void printDoubleList(List list){ 154 PtrToNode p=list; 155 while(p!=NULL){ 156 printf("\n數字%d:\n\t",p->Num); 157 printSingleList(p); 158 p=p->mainNext; 159 } 160 } 161 void Warn(){ 162 printf("本程序的規定:\n"); 163 printf("\t1到13表明黑桃 14到26表明紅桃 27到39表明梅花 40到52表明方塊。\n" ); 164 } 165 166 int main(){ 167 Warn(); 168 int i; 169 srand(time(NULL)); 170 int select[20]; 171 PtrToNode temp; 172 InitDisOrder(select); 173 for(i=0;i<20;i++){ 174 printf("%3d=",select[i]); 175 temp=malloc(sizeof(struct Poker)); 176 temp->Element=select[i]; 177 temp->BranchNext=NULL; 178 InitNode(temp); 179 printSingleList(temp); 180 if((i+1)%10==0){ 181 printf("\n"); 182 } 183 } 184 List list=NULL; 185 for(i=0;i<20;i++){ 186 list=InsertMain(list,select[i]); 187 } 188 printDoubleList(list); 189 return 0; 190 }
其實第二個程序只是第一個程序在條件上,順序改了改,在作第一個時我考慮到了擴展性的問題,因而第二個程序只用了5分鐘就完成了。而第一個程序用了幾個小時。