數據結構與算法分析(5)表、棧和隊列(一)

      本節討論最簡單和最基本的三種數據結構:表,棧和隊列。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表的簡單數組實現:

    對錶的全部操做均可以使用數組來實現。雖然數組是動態指定的,可是仍是須要對錶的大小的最大值進行估算。這會致使有可能浪費大量的空間。數組實現使得PrintListFind以線性時間執行,FindKth以常數時間。而插入和刪除的代價昂貴。

      由於插入和刪除的運行時間是如此的慢以及表的大小必須事先已知,因此簡單數組通常不用來實現表這種結構。

      2.2鏈表

      爲了不插入和刪除的線性開銷,咱們容許表能夠不連續存儲。

      鏈表由一系列在沒必要再內存中相連的結構組成。每個結構均包含表元素和包含指向該元素後繼元的Next指針。最後一個單元的Next指針指向NULLANSI C規定NULL0

  圖:

      一個鏈表:

    

     從鏈表中刪除一個元素:

     

      向鏈表中插入:

      

      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分鐘就完成了。而第一個程序用了幾個小時。

相關文章
相關標籤/搜索