数据结构与算法分析(6)表的应用实例

在这里我介绍四个使用表解决实际中的问题的例子,分别是:

1.多项式的加法和乘法运算;

2.基数排序;

3.表的游标实现;

4.多重表在学生选课系统中的应用。(可选)

    (1)多项式的加法和乘法:

多项式的加法和乘法有两个实现方式,第一个是用数组来实现,它适合大多数项都有的稠密的多项式;第二个是用链表来实现,它适用于比较稀疏的多项式。但总体而言,还是链表实现的比较好!

1)下面给出链表实现多项式加法和乘法的范例:

  1 //多项式加法乘法的链表实现
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <time.h>
  5 #define MaxNodeNum 10
  6 #define MaxMiNum 20;
  7
  8 struct Node{
  9   int Coefficient;//系数
 10   int N;//次方数
 11   int Element;//元素
 12   struct Node *Next;
 13 };
 14 typedef struct Node *Polynomial;
 15 typedef struct Node *Poly_List;
 16
 17 int *RandInt4(int total,int i,int j,int order){
 18     int *numberGroup=malloc(total*sizeof(int));//用于返回一个指定大小的数组
 19     int tempory[j-i+1];//辅助产生随机数的数组。
 20     int k;//用于循环遍历
 21     int x;//接收产生的随机变量
 22     //srand(time(NULL));
 23     //初始化辅助数组
 24     for(k=0;k<=j-i;k++){
 25         tempory[k]=0;
 26     }
 27     for(k=0;k<total;k++){
 28 L:        x=rand()%(j-i+1)+i;//产生从i到j,包括i和j的随机数
 29         if(tempory[x-i]==0){
 30           tempory[x-i]=1;
 31           //当需要产生的数组是无序的则执行:
 32           if(order==0){
 33             numberGroup[k]=x;
 34             }
 35         }else{
 36             goto L;
 37         }
 38     }
 39     //当需要产生有序的随机数组时执行:
 40     int w=0;
 41     if(order!=0){
 42       for(k=0;k<j-i+1;k++){
 43           if(tempory[k]==1){
 44               numberGroup[w++]=k+i;
 45               if(w>=total){
 46                   break;
 47               }
 48           }
 49       }
 50     }
 51
 52     return numberGroup;
 53 }
 54
 55 Poly_List create(){
 56     Poly_List list=malloc(sizeof(struct Node));
 57     list->Next=NULL;
 58     return list;
 59 }
 60 //初始化一个代表多项式的链,按次方数n排列,并且元素都是一样的
 61 void initList(Poly_List list,int element){
 62 //每个链表的结点数是任意的,但为了测试方便,这里要求节点数小于10,并且最大次方数为20
 63     int nodeNumber=rand()%(MaxNodeNum-3)+4;
 64     int *tempNumGroup;//次方数的随机数组
 65     tempNumGroup=RandInt4(nodeNumber,0,20,1);
 66     int *coeffNumGroup;//系数的随机数组
 67     coeffNumGroup=RandInt4(nodeNumber,1,20,0);
 68     int i;
 69     Polynomial tempNode;
 70     Polynomial ptr=list;
 71     for(i=0;i<nodeNumber;i++){
 72         tempNode=malloc(sizeof(struct Node));
 73         tempNode->Element=element;
 74         tempNode->Coefficient=coeffNumGroup[i];
 75         tempNode->N=tempNumGroup[i];
 76         ptr->Next=tempNode;
 77         ptr=ptr->Next;
 78     }
 79     ptr->Next=NULL;
 80 }
 81 void initList_MR(Poly_List p){
 82      initList(p,1);
 83 }
 84 //求两个多项式的和,返回一个链表的头指针
 85 Poly_List sumPolyList(Poly_List    list1,Poly_List list2){
 86     Poly_List list=create();
 87     Polynomial ptr_list=list;
 88     Polynomial ptr1,ptr2,temp;
 89     ptr1=list1->Next;
 90     ptr2=list2->Next;
 91     while(ptr1!=NULL&&ptr2!=NULL){
 92         temp=malloc(sizeof(struct Node));
 93         if(ptr1->N==ptr2->N){
 94           temp->Coefficient=ptr1->Coefficient+ptr2->Coefficient;
 95           temp->N=ptr1->N;
 96           temp->Element=ptr1->Element;
 97           ptr1=ptr1->Next;
 98           ptr2=ptr2->Next;
 99         }else if(ptr1->N<ptr2->N){
100           temp->Coefficient=ptr1->Coefficient;
101           temp->N=ptr1->N;
102           temp->Element=ptr1->Coefficient;
103           ptr1=ptr1->Next;
104         }else{
105           temp->Coefficient=ptr2->Coefficient;
106           temp->N=ptr2->N;
107           temp->Element=ptr2->Coefficient;
108           ptr2=ptr2->Next;
109         }
110         ptr_list->Next=temp;
111         ptr_list=ptr_list->Next;
112     }
113     if(ptr1==NULL){
114         while(ptr2!=NULL){
115             temp=malloc(sizeof(struct Node));
116             temp->N=ptr2->N;
117             temp->Element=ptr2->Element;
118             temp->Coefficient=ptr2->Coefficient;
119             ptr2=ptr2->Next;
120             ptr_list->Next=temp;
121             ptr_list=ptr_list->Next;
122         }
123     }else if(ptr2==NULL){
124         while(ptr1!=NULL){
125             temp=malloc(sizeof(struct Node));
126             temp->N=ptr1->N;
127             temp->Element=ptr1->Element;
128             temp->Coefficient=ptr1->Coefficient;
129             ptr1=ptr1->Next;
130             ptr_list->Next=temp;
131             ptr_list=ptr_list->Next;
132         }
133     }
134     ptr_list->Next=NULL;
135     return list;
136 }
137 int exsist(Poly_List    list,int N){
138     Polynomial ptr=list->Next;
139     while(ptr!=NULL){
140         if(ptr->N==N){
141             return 1;
142         }
143         ptr=ptr->Next;
144     }
145     return 0;
146 }
147 Polynomial findInsertPosition(Poly_List    list,int N){
148     Poly_List ptr1=list->Next;
149     Poly_List ptr2=list;
150     while(ptr1!=NULL){
151         //如果元素存在,则不需要插入,直接返回元素所在位置
152         if(ptr1->N==N){
153             return ptr1;
154         //如果N的值小于当前结点的值,则插入在当前结点的前面
155         }else if(ptr1->N>N){
156             return ptr2;
157         }//如果N的值大于当前结点的值,则看下一个元素,如果下一个元素为空,则返回最后一个元素
158         ptr2=ptr1;
159         ptr1=ptr2->Next;
160     }
161     return ptr2;
162 }
163 void insertIntoList(Poly_List list,int N,int C){
164     Polynomial temp;
165     Poly_List ptr1=list->Next;
166     Poly_List ptr2=list->Next;
167     if(list->Next==NULL){
168         temp=malloc(sizeof(struct Node));
169         temp->Coefficient=C;
170         temp->N=N;
171         list->Next=temp;
172         temp->Next=NULL;
173     }else if(ptr1!=NULL){
174         if(exsist(list,N)){
175             ptr2=findInsertPosition(list,N);
176             ptr2->Coefficient+=C;
177         }else{
178             ptr2=findInsertPosition(list,N);
179             temp=malloc(sizeof(struct Node));
180             temp->N=N;
181             temp->Coefficient=C;
182             temp->Next=ptr2->Next;
183             ptr2->Next=temp;
184         }
185     }
186 }
187 void printPolyList(Poly_List list){
188     Polynomial ptr=list->Next;
189     while(ptr!=NULL){
190         if(ptr!=list->Next){
191           printf("+%dx^%d",ptr->Coefficient,ptr->N);
192         }else{
193           printf("%dx^%d",ptr->Coefficient,ptr->N);
194         }
195         ptr=ptr->Next;
196     }
197 }
198 //求多项式的乘积
199 Poly_List subPolyList(Poly_List    list1,Poly_List list2){
200     Poly_List list=create();
201     Poly_List ptr1=list1->Next;
202     Poly_List ptr2=list2->Next;
203     int list1_noNum=0;
204     int list2_noNum=0;
205     while(ptr1!=NULL){
206         ptr1=ptr1->Next;
207         list1_noNum++;
208     }
209     while(ptr2!=NULL){
210         ptr2=ptr2->Next;
211         list2_noNum++;
212     }
213     int *list1_NnumGroup=malloc(sizeof(int)*list1_noNum);
214     int *list1_CnumGroup=malloc(sizeof(int)*list1_noNum);
215     int *list2_NnumGroup=malloc(sizeof(int)*list2_noNum);
216     int *list2_CnumGroup=malloc(sizeof(int)*list2_noNum);
217     ptr1=list1->Next;
218     ptr2=list2->Next;
219     int i=0;
220     while(ptr1!=NULL){
221         list1_NnumGroup[i]=ptr1->N;
222         list1_CnumGroup[i]=ptr1->Coefficient;
223         i++;
224         ptr1=ptr1->Next;
225     }
226     i=0;
227     while(ptr2!=NULL){
228         list2_NnumGroup[i]=ptr2->N;
229         list2_CnumGroup[i]=ptr2->Coefficient;
230         i++;
231         ptr2=ptr2->Next;
232     }
233     int k,w=0;
234     //作乘法得到的多项式的结点数
235        int listNN=list1_noNum*list2_noNum;
236     int *list_NnumGroup=malloc(sizeof(int)*listNN);
237     int *list_CnumGroup=malloc(sizeof(int)*listNN);
238     for(i=0;i<list1_noNum;i++){
239         for(k=0;k<list2_noNum;k++){
240             list_NnumGroup[w]=list1_NnumGroup[i]+list2_NnumGroup[k];
241             list_CnumGroup[w]=list1_CnumGroup[i]*list2_CnumGroup[k];
242             w++;
243         }
244     }
245     free(list1_CnumGroup);
246     free(list1_NnumGroup);
247     free(list2_CnumGroup);
248     free(list2_NnumGroup);
249     for(i=0;i<listNN;i++){
250         insertIntoList(list,list_NnumGroup[i],list_CnumGroup[i]);
251     }
252     return list;
253 }
254 int main(){
255   srand(time(NULL));
256   Poly_List p1=create();
257   Poly_List p2=create();
258   //初始化两个多项式链表
259   initList_MR(p1);
260   initList_MR(p2);
261   printf("第一个多项式为:\n");
262   printPolyList(p1);
263   printf("\n第二个多项式为:\n");
264   printPolyList(p2);
265   printf("\n");
266   Poly_List Sum_p1_p2;
267   Poly_List Sub_p1_p2;
268   Sum_p1_p2=sumPolyList(p1,p2);
269   Sub_p1_p2=subPolyList(p1,p2);
270   printf("\n这两个多项式之和为:\n");
271   printPolyList(Sum_p1_p2);
272   printf("\n这两个多项式的乘积为:\n");
273   printPolyList(Sub_p1_p2);
274   return 0;
275 } 

2)用数组实现多项式的范例:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<time.h>
  4 #define MaxDegree 40//定义多项式的最大的次数为40,最小的为0
  5 #define MaxCoffe 30//定义系数为的最大值为30
  6 struct Node{
  7   int CoeffArray[MaxDegree+1];
  8   int HighPower;
  9 };//每个结点代表一个多项式
 10 typedef struct Node *Polynomial;
 11 int *RandInt4(int total,int i,int j,int order){
 12     int *numberGroup=malloc(total*sizeof(int));//用于返回一个指定大小的数组
 13     int tempory[j-i+1];//辅助产生随机数的数组。
 14     int k;//用于循环遍历
 15     int x;//接收产生的随机变量
 16     //srand(time(NULL));
 17     //初始化辅助数组
 18     for(k=0;k<=j-i;k++){
 19         tempory[k]=0;
 20     }
 21     for(k=0;k<total;k++){
 22 L:        x=rand()%(j-i+1)+i;//产生从i到j,包括i和j的随机数
 23         if(tempory[x-i]==0){
 24           tempory[x-i]=1;
 25           //当需要产生的数组是无序的则执行:
 26           if(order==0){
 27             numberGroup[k]=x;
 28             }
 29         }else{
 30             goto L;
 31         }
 32     }
 33     //当需要产生有序的随机数组时执行:
 34     int w=0;
 35     if(order!=0){
 36       for(k=0;k<j-i+1;k++){
 37           if(tempory[k]==1){
 38               numberGroup[w++]=k+i;
 39               if(w>=total){
 40                   break;
 41               }
 42           }
 43       }
 44     }
 45
 46     return numberGroup;
 47 }
 48 void zeroPolymial(Polynomial p){
 49     int i;
 50     for(i=0;i<=MaxDegree;i++)
 51       p->CoeffArray[i]=0;
 52     p->HighPower=0;
 53 }
 54 void printMulti(Polynomial p){
 55     int i;
 56     int flag=0;
 57     for(i=0;i<=p->HighPower;i++){
 58         if(p->CoeffArray[i]!=0){
 59           if(flag==1){
 60             printf("+");
 61             }
 62           if(i!=(p->HighPower-1)){
 63              printf("%dx^%d",p->CoeffArray[i],i);
 64              flag=1;
 65           }else{
 66              printf("%d^%d", p->CoeffArray[i],i);
 67           }
 68         }
 69     }
 70 }
 71 Polynomial initMulti(){
 72     Polynomial p=malloc(sizeof(struct Node));
 73     zeroPolymial(p);
 74     int r=rand()%7+4;//在一个多项式中含有r个元素
 75     int *temp=RandInt4(r,0,20,0);
 76     int i;
 77     for(i=0;i<r;i++){
 78         p->CoeffArray[temp[i]]=rand()%MaxCoffe+1;
 79         if(p->HighPower<temp[i]){
 80             p->HighPower=temp[i];
 81         }
 82     }
 83     return p;
 84 }
 85 Polynomial sumOf(Polynomial p1,Polynomial p2){
 86     Polynomial p;
 87     p=malloc(sizeof(struct Node));
 88     zeroPolymial(p);
 89     int a=p1->HighPower;
 90     int b=p2->HighPower;
 91     p->HighPower=a>b?a:b;
 92     int i;
 93     for(i=p->HighPower;i>=0;i--){
 94         p->CoeffArray[i]=p1->CoeffArray[i]+p2->CoeffArray[i];
 95     }
 96     return p;
 97 }
 98 Polynomial subOf(Polynomial p1,Polynomial p2){
 99     Polynomial p;
100     int i,j;
101     p=malloc(sizeof(struct Node));
102     zeroPolymial(p);
103     p->HighPower=p1->HighPower+p2->HighPower;
104     if(p->HighPower>MaxDegree){
105         printf("多项式最高项溢出,次数为%d",p->HighPower);
106     }else{
107         for(i=0;i<=p1->HighPower;i++){
108             if(p1->CoeffArray[i]==0){
109                 continue;
110             }
111             for(j=0;j<=p2->HighPower;j++){
112                 p->CoeffArray[i+j]+=p1->CoeffArray[i]*p2->CoeffArray[j];
113             }
114         }
115     }
116     return p;
117 }
118
119 int main(){
120     srand(time(NULL));
121     Polynomial multItem1;
122     Polynomial multItem2;
123     multItem1=initMulti();
124     multItem2=initMulti();
125     printf("第一个多项式为:\n");
126     printMulti(multItem1);
127     printf("\n第二个多项式为:\n");
128     printMulti(multItem2);
129     printf("\n这两个多项式的和是:\n");
130     printMulti(sumOf(multItem1,multItem2));
131     printf("\n这两个多项式的乘积为\n");
132     printMulti(subOf(multItem1,multItem2));
133     return 0;
134 } 

(2)使用链表的第二个例子叫做基数排序(radix sort)。基数排序有时也成为卡式排序(card sort),因为直到现代计算机出现之前,它一直用于老式穿孔卡的排序。

1)在介绍基数排序之前,先介绍一下桶式排序:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<time.h>
 4
 5 int *RandInt4(int total,int i,int j,int order){
 6     int *numberGroup=malloc(total*sizeof(int));//用于返回一个指定大小的数组
 7     int tempory[j-i+1];//辅助产生随机数的数组。
 8     int k;//用于循环遍历
 9     int x;//接收产生的随机变量
10     //srand(time(NULL));
11     //初始化辅助数组
12     for(k=0;k<=j-i;k++){
13         tempory[k]=0;
14     }
15     for(k=0;k<total;k++){
16 L:        x=rand()%(j-i+1)+i;//产生从i到j,包括i和j的随机数
17         if(tempory[x-i]==0){
18           tempory[x-i]=1;
19           //当需要产生的数组是无序的则执行:
20           if(order==0){
21             numberGroup[k]=x;
22             }
23         }else{
24             goto L;
25         }
26     }
27     //当需要产生有序的随机数组时执行:
28     int w=0;
29     if(order!=0){
30       for(k=0;k<j-i+1;k++){
31           if(tempory[k]==1){
32               numberGroup[w++]=k+i;
33               if(w>=total){
34                   break;
35               }
36           }
37       }
38     }
39     return numberGroup;
40 }
41 void *bucketSort(int *p,int low,int high,int total){
42     int *bucket=malloc(sizeof(int)*(high-low+1));
43     int i;
44     //初始化桶,桶里的数值将代表元素出现的次数(适用于有重复元素的情况),下标代表响应的元素
45     for(i=0;i<(high-low+1);i++){
46           bucket[i]=0;
47     }
48     for(i=0;i<total;i++){
49         bucket[p[i]]+=1;
50     }
51     int j,w=0;
52     for(i=0;i<(high-low+1);i++){
53         //虽然不会有重复数据,但还是在这里实现允许重复数据的例子
54         for(j=0;j<bucket[i];j++){
55             p[w]=i;
56             w++;
57         }
58     }
59 }
60 int main(){
61       int *numGroup=RandInt4(40,0,104,0);
62       int i;
63     printf("未排序的数组是:\n");
64     for(i=0;i<40;i++){
65         printf("%3d  ",numGroup[i]);
66         if((i+1)%10==0){
67             printf("\n");
68         }
69     }
70     bucketSort(numGroup,0,105,40);
71     printf("排过序的数组是:\n");
72     for(i=0;i<40;i++){
73         printf("%3d  ",numGroup[i]);
74         if((i+1)%10==0){
75             printf("\n");
76         }
77     }
78 } 

2)基数排序是桶式排序的推广,当数的取值范围非常大的时候,进行多趟桶排序以减少桶空间的使用:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #define bucketSize 10
  4
  5 struct Node{
  6   int Element;
  7   struct Node *Next;
  8 };
  9 typedef struct Node *Number;
 10 typedef struct Node *NumList;
 11
 12 int pow(int x,int N){
 13     if(N==0){
 14         return 1;
 15     }else{
 16         return pow(x,N-1)*x;
 17     }
 18 }
 19 int *RandInt4(int total,int i,int j,int order){
 20     int *numberGroup=malloc(total*sizeof(int));//用于返回一个指定大小的数组
 21     int tempory[j-i+1];//辅助产生随机数的数组。
 22     int k;//用于循环遍历
 23     int x;//接收产生的随机变量
 24     //srand(time(NULL));
 25     //初始化辅助数组
 26     for(k=0;k<=j-i;k++){
 27         tempory[k]=0;
 28     }
 29     for(k=0;k<total;k++){
 30 L:        x=rand()%(j-i+1)+i;//产生从i到j,包括i和j的随机数
 31         if(tempory[x-i]==0){
 32           tempory[x-i]=1;
 33           //当需要产生的数组是无序的则执行:
 34           if(order==0){
 35             numberGroup[k]=x;
 36             }
 37         }else{
 38             goto L;
 39         }
 40     }
 41     //当需要产生有序的随机数组时执行:
 42     int w=0;
 43     if(order!=0){
 44       for(k=0;k<j-i+1;k++){
 45           if(tempory[k]==1){
 46               numberGroup[w++]=k+i;
 47               if(w>=total){
 48                   break;
 49               }
 50           }
 51       }
 52     }
 53     return numberGroup;
 54 }
 55 void initNumList(NumList bucketlist[]){
 56     int i;
 57     for(i=0;i<bucketSize;i++){
 58         bucketlist[i]=malloc(sizeof(struct Node));
 59         bucketlist[i]->Next=NULL;
 60     }
 61 }
 62 void insertIntoNumList(int x,NumList list){
 63     Number temp=malloc(sizeof(struct Node));
 64     temp->Element=x;
 65     NumList ptr=list;
 66     while(ptr->Next!=NULL){
 67         if(x<=ptr->Next->Element){
 68             temp->Next=ptr->Next;
 69             ptr->Next=temp;
 70             return;
 71         }else if(x>ptr->Next->Element){
 72             ptr=ptr->Next;
 73         }
 74     }
 75     //当ptr的下一个结点为空时
 76     ptr->Next=temp;
 77     temp->Next=NULL;
 78 }
 79 void printBucketNumberGroup(NumList    bucklist[]){
 80   int i;
 81   NumList ptr;
 82   for(i=0;i<bucketSize;i++){
 83       ptr=bucklist[i]->Next;
 84       printf("桶%d里存的数据有:",i);
 85       while(ptr!=NULL){
 86         printf("%4d  ",ptr->Element);
 87         ptr=ptr->Next;
 88       }
 89       printf("\n");
 90     }
 91 }
 92 void cardSort(int *p,int Max,int total){
 93     NumList bucklist[bucketSize];
 94     initNumList(bucklist);
 95     int ranks;//记录基数排序所需的趟数
 96     int i,j;
 97     int temp;//记录基数排序过程中每个元素的末尾数字
 98     for(ranks=-1;Max>0;ranks++){
 99         Max/=bucketSize;
100     }
101     //printf("此次基数排序共分%d趟进行:\n",ranks);
102     for(i=0;i<total;i++){
103         temp=(p[i]/1)%10;
104         //printf("%d的个位数字是:%d  \n",p[i],temp);
105         insertIntoNumList(p[i],bucklist[temp]);
106     }
107     //printf("第%d次桶排序的桶存的数据为:\n",1);
108     //printBucketNumberGroup(bucklist);
109     NumList ptr,ptrForFree;
110     int element;
111     for(i=2;i<=ranks;i++){
112         for(j=0;j<bucketSize;j++){
113              ptr=bucklist[j];
114             while(ptr->Next!=NULL){
115                 element=(ptr->Next->Element);
116                 temp=(element/pow(10,i-1))%10;
117                 //如果此元素的对应位数的下标不属于此桶
118                 if(temp!=j){
119                     ptrForFree=ptr->Next;
120                     ptr->Next=ptr->Next->Next;
121                     free(ptrForFree);
122                     //插入另一个桶
123                       insertIntoNumList(element,bucklist[temp]);
124                 }else{
125                     ptr=ptr->Next;
126                 }
127             }
128         }
129     //printf("第%d次桶排序的桶存的数据为:\n",i);
130     //printBucketNumberGroup(bucklist);
131     }
132
133     j=0;
134     for(i=0;i<bucketSize;i++){
135       ptr=bucklist[i]->Next;
136       while(ptr!=NULL){
137         p[j++]=ptr->Element;
138         //printf("第%d个数为%d\n",j,p[j-1]);
139         if(j>total){
140             printf("数组溢出,大小最大为%d,出现错误\n",total);
141             exit(0);
142         }
143         ptr=ptr->Next;
144       }
145     }
146 }
147 int main(){
148       int *numGroup=RandInt4(100,0,10000,0);
149     int i;
150     printf("未排序的数组是:\n");
151       for(i=0;i<100;i++){
152           printf("%4d  ",numGroup[i]);
153           if((i+1)%10==0){
154               printf("\n");
155           }
156     }
157     cardSort(numGroup,10000,100);
158     printf("排过序的数组是:\n");
159     for(i=0;i<100;i++){
160           printf("%4d  ",numGroup[i]);
161           if((i+1)%10==0){
162               printf("\n");
163           }
164     }
165     return 0;
166 } 

本实例的桶数可以任意指定,多少都行,而且也不限制数的大小。缺点是产生随机数组的过程十分消耗资源。

(3)许多语言并不支持指针。如果需要链表而又不能使用指针,那么就必须使用另外的实现方法。我们将描述这种方法,并称为游标(cursor)实现法。

在链表的指针实现的过程中有两个重要的特点:

1)数据存在一组结构体中。每个结构体包含有数据以及指向下一个结构体的指针。

2)一个新的结构体可以通过调用malloc从系统全局内存中得到,并可通过free而被释放掉。

游标法必须能够模仿实现这两条特性。

下面给出用游标法写出的链表例程:

  1 #include<stdio.h>
  2 #define SpaceSize 40
  3
  4 typedef int PtrToNode;
  5 typedef PtrToNode List;
  6 typedef PtrToNode Position;
  7
  8 struct Node{
  9     int Element;
 10     int flag;//记录元素出现的次数
 11     Position Next;//Next指针指向的不是具体的结点的首地址,而是结点的下标
 12 };
 13 int *RandInt4(int total,int i,int j,int order){
 14     int *numberGroup=malloc(total*sizeof(int));//用于返回一个指定大小的数组
 15     int tempory[j-i+1];//辅助产生随机数的数组。
 16     int k;//用于循环遍历
 17     int x;//接收产生的随机变量
 18     srand(time(NULL));
 19     //初始化辅助数组
 20     for(k=0;k<=j-i;k++){
 21         tempory[k]=0;
 22     }
 23     for(k=0;k<total;k++){
 24 L:        x=rand()%(j-i+1)+i;//产生从i到j,包括i和j的随机数
 25         if(tempory[x-i]==0){
 26           tempory[x-i]=1;
 27           //当需要产生的数组是无序的则执行:
 28           if(order==0){
 29             numberGroup[k]=x;
 30             }
 31         }else{
 32             goto L;
 33         }
 34     }
 35     //当需要产生有序的随机数组时执行:
 36     int w=0;
 37     if(order!=0){
 38       for(k=0;k<j-i+1;k++){
 39           if(tempory[k]==1){
 40               numberGroup[w++]=k+i;
 41               if(w>=total){
 42                   break;
 43               }
 44           }
 45       }
 46     }
 47
 48     return numberGroup;
 49 }
 50 //编译时预先分配的结点数组
 51 struct Node CursorSpace[SpaceSize];
 52 //CursorSpace[0]是表头指针
 53 static void InitialCursor(void){
 54     int i;
 55     for(i=0;i<SpaceSize;i++){
 56         CursorSpace[i].Next=i+1;
 57     }
 58     CursorSpace[i].Next=0;
 59 }
 60 static Position CursorAlloc(void){
 61     Position p;
 62     p=CursorSpace[0].Next;
 63     CursorSpace[0].Next=CursorSpace[p].Next;
 64     CursorSpace[p].Next=0;
 65     return p;//当p的值为0时说明没有空间可用了
 66 }
 67 static void CursorFree(Position p){
 68     CursorSpace[p].Next=CursorSpace[0].Next;
 69     CursorSpace[0].Next=p;
 70 }
 71 void InitList(List *L){
 72     PtrToNode p=CursorAlloc();
 73     //新建的结点需要指向头结点
 74     CursorSpace[p].Next=0;
 75     *L=p;
 76 }
 77 int IsLast(Position p,List L){
 78     return CursorSpace[p].Next==0;
 79 }
 80 Position FindPrevious(int x,List L){
 81     Position p;
 82     p=L;
 83     Position temp=CursorSpace[p].Next;
 84     while((temp!=0)&&(CursorSpace[temp].Element!=x)){
 85         p=temp;
 86         temp=CursorSpace[temp].Next;
 87     }
 88     return p;//当p为0时说明没有找到
 89 }
 90 Position Find(int x,List L){
 91     Position p;
 92     p=CursorSpace[L].Next;
 93     while((p!=0)&&(CursorSpace[p].Element!=x)){
 94         p=CursorSpace[p].Next;
 95     }
 96     return p;//当p为0时说明没有找到
 97 }
 98 void Delete(int x,List L){
 99     Position p,TmpCell;
100     p=FindPrevious(x,L);
101     //处理要删除的元素的出现在表中很多次的情况
102     TmpCell=CursorSpace[p].Next;
103     int flag=CursorSpace[TmpCell].flag;
104     if(flag>1){
105         CursorSpace[TmpCell].flag--;
106         return;
107     }
108     if(!IsLast(p,L)){//如果是最后一个的话,肯定没找着,p的下一个为头结点,此时不需要执行删除操作
109       TmpCell=CursorSpace[p].Next;
110       CursorSpace[p].Next=CursorSpace[TmpCell].Next;
111       CursorFree(TmpCell);
112     }
113 }
114 //插入操作将新元素插到p的后面
115 void Insert(int x,List L,Position p){
116     Position TmpCell;
117     TmpCell=CursorAlloc();
118     if(TmpCell==0){
119         printf("空间已经使用完!\n");
120         exit(0);
121     }
122     CursorSpace[TmpCell].Element=x;
123     CursorSpace[TmpCell].flag=1;
124     CursorSpace[TmpCell].Next=CursorSpace[p].Next;
125     CursorSpace[p].Next=TmpCell;
126 }
127 Position FindInsertPosition(int x,List L){
128     Position p=Find(x,L);
129     int temp;
130     //如果没有找到这个元素,则需要返回一个插入的位置
131     if(p==0){
132        p=L;
133        //当p的下一个元素不是头元素时
134        while((temp=CursorSpace[p].Next)!=0){
135             if(CursorSpace[temp].Element<x){
136             p=CursorSpace[p].Next;
137             }
138          else if(CursorSpace[temp].Element>x){
139                break;
140             }//由于前面已经判断过x不在这个表中,所以只有大于小于两种可能
141        }
142        //当p的下一个元素是头元素时
143        return p;
144     }else{
145         CursorSpace[p].flag++;
146         //插入一个已经存在的元素,不需要再执行申请新元素的插入操作
147         return 0;
148     }
149 }
150 void InsertIntoList(int x,List L){
151     Position p=FindInsertPosition(x,L);
152     //如果p!=0说明找到了一个插入的位置
153     if(p!=0){
154       Insert(x,L,p);
155     }//p等于0的情况出现在插入一个在表中已经存在的元素时
156 }
157 void printList(List list){
158     Position p=list;
159     Position temp;
160     int i;
161     int w=0;
162     while((temp=CursorSpace[p].Next)!=0){
163         //printf("%d",CursorSpace[temp].flag);
164          for(i=0;i<CursorSpace[temp].flag;i++){
165              printf("%3d",CursorSpace[temp].Element);
166              w++;
167              if(w%30==0){
168                  printf("\n");
169              }
170          }
171          p=CursorSpace[p].Next;
172     }
173 }
174 int main(){
175     InitialCursor();
176     List a_list;
177     InitList(&a_list);
178     int *a_tempNumGroup;
179     a_tempNumGroup=RandInt4(35,0,99,0);
180     int i;
181     printf("即将插入到游标模式组成的链表中的元素组是:\n");
182     for(i=0;i<35;i++){
183         printf("%3d",a_tempNumGroup[i]);
184         if((i+1)%30==0){
185             printf("\n");
186         }
187     }
188     for(i=0;i<35;i++){
189         //printf("这次要插入的有:%d\n",a_tempNumGroup[i]);
190         InsertIntoList(a_tempNumGroup[i],a_list);
191         //printList(a_list);
192     }
193     printf("\n下面是功能测试部分:");
194     printf("\n链表中的元素是:\n");
195     printList(a_list);
196     int n;
197     printf("\n请再输入一个数,执行删除操作:\n",&n);
198     scanf("%d",&n);
199     getchar();
200     Delete(n,a_list);
201     printf("删除一个元素后的链表是:\n");
202     printList(a_list);
203     printf("\n请再输入一个数,执行插入链表中已经存在数操作:\n",&n);
204     scanf("%d",&n);
205     getchar();
206     InsertIntoList(n,a_list);
207     printf("添加一个元素已存在元素后的链表是:\n");
208     printList(a_list);
209     printf("\n请再输入一个数,执行删除链表中已经存在很多次的元素的操作:\n",&n);
210     scanf("%d",&n);
211     getchar();
212     Delete(n,a_list);
213     printf("删除一个元素已存在很多次元素后的链表是:\n");
214     printList(a_list);
215 } 

(4)我们的最后一个例子阐述链表更复杂的应用。大学需要生成两种不同的报告,一个是每个班级的所有学生,一个是每个学生所在的班级(可能在很多个班级里)。我们用多重表来实现:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<time.h>
  5
  6 struct Student;
  7 struct Class;
  8 struct StuCla;
  9
 10 struct Student{
 11   char Name[10];
 12   struct StuCla *FirstStu;//指向的第一个学生
 13 };
 14 struct Class{
 15     char Name[10];
 16     struct StuCla *FirstStu;//本班的第一个学生
 17 };
 18 struct StuCla{
 19     char Stu_name[10];//学生的姓名
 20     char Class_name[10];//班级的名称
 21     int cla;//用于排序
 22     int stu; //用于排序
 23     struct Student *BelongStudent;//用于最后一个结点,指向学生主结点
 24     struct Class   *BelongClass;//用于最后一个结点,指向班级主结点
 25     struct StuCla  *SameCNextStudent;//用于同班同学那条链
 26     struct StuCla  *SameSNextStudent;//用于一个学生所选的课程
 27 };
 28 typedef    struct StuCla *PtrToNode;
 29 //在这里进行测试,为了简单,只有5个班级,5名学生。
 30 struct Class classes[5];
 31 struct Student student[5];
 32 //初始化所有的班级和学生
 33 static void Initial(){
 34     int i;
 35     char str1[10];
 36     char str2[10];
 37     char temp[2];
 38     for(i=0;i<5;i++){
 39       strcpy(str1,"class");
 40       strcpy(str2,"student");
 41       itoa(i+1,temp,10);
 42       strcat(str1,temp);
 43       strcat(str2,temp);
 44       //printf("%s,%s\n",str1,str2);
 45       strcpy(classes[i].Name,str1);
 46       strcpy(student[i].Name,str2);
 47       classes[i].FirstStu=NULL;
 48       student[i].FirstStu=NULL;
 49     }
 50 }
 51 static void InsertIntoDoubleList(int stuN,int claN){
 52     PtrToNode temp=malloc(sizeof(struct StuCla));
 53     strcpy(temp->Stu_name,student[stuN].Name);
 54     strcpy(temp->Class_name,classes[claN].Name);
 55     temp->cla=claN;
 56     temp->stu=stuN;
 57     temp->BelongStudent=NULL;
 58     temp->BelongClass=NULL;
 59     temp->SameCNextStudent=NULL;
 60     temp->SameSNextStudent=NULL;
 61
 62     //让学生主结点指向新生成的结点
 63     PtrToNode Pre_ptr=NULL;
 64     PtrToNode ptr=student[stuN].FirstStu;
 65     //处理第一次插入的情况
 66     if(ptr==NULL){
 67         student[stuN].FirstStu=temp;
 68         temp->BelongStudent=&student[stuN];
 69         goto L;
 70     }
 71     while(ptr!=NULL){
 72         //插在当前结点之前
 73         if(ptr->cla>temp->cla){
 74           temp->SameSNextStudent=ptr;
 75           //如果当前结点是主结点后的第一个结点
 76           if(ptr==student[stuN].FirstStu){
 77               student[stuN].FirstStu=temp;
 78               goto L;
 79             }else{
 80             Pre_ptr->SameSNextStudent=temp;
 81             goto L;
 82             }
 83         }else if(ptr->cla<temp->cla){
 84           //如果不是第一个,找到它前面的一个。
 85            Pre_ptr=ptr;
 86           ptr=ptr->SameSNextStudent;
 87         }else{
 88           printf("学生%d重复插入班级%d\n",stuN,claN);
 89           return;
 90         }
 91     }
 92     //用来处理插入到末尾的情况
 93     Pre_ptr->SameSNextStudent=temp;
 94     Pre_ptr->BelongStudent=NULL;
 95     temp->BelongStudent=&student[claN];
 96
 97     //让班级主结点指向新生成的结点
 98 L:  ptr=classes[claN].FirstStu;
 99     //处理第一次插入的情况
100     if(ptr==NULL){
101         classes[claN].FirstStu=temp;
102         temp->BelongClass=&classes[claN];
103         return;
104     }
105     while(ptr!=NULL){
106         //插在当前结点之前
107         if(ptr->stu>temp->stu){
108           temp->SameCNextStudent=ptr;
109           //如果当前结点是主结点后的第一个结点
110           if(ptr==classes[claN].FirstStu){
111               classes[claN].FirstStu=temp;
112               return;
113             }else{
114                 //如果不是第一个,找到它前面的一个。
115             Pre_ptr->SameCNextStudent=temp;
116             return;
117             }
118         }else if(ptr->stu<temp->stu){
119            Pre_ptr=ptr;
120           ptr=ptr->SameCNextStudent;
121         }else{
122             printf("学生%d重复插入班级%d\n",stuN,claN);
123             return;
124         }
125     }
126     //用来处理插入到末尾的情况
127     Pre_ptr->SameCNextStudent=temp;
128     Pre_ptr->BelongClass=NULL;
129     temp->BelongClass=&classes[claN];
130 }
131 static void printStudent(int N){
132   printf("学生%d所选的班级有:",N+1);
133   PtrToNode ptr=student[N].FirstStu;
134   while(ptr!=NULL){
135     printf("%10s",ptr->Class_name);
136     if(ptr->BelongStudent!=NULL){
137         printf("末尾");
138     }
139     ptr=ptr->SameSNextStudent;
140   }
141   printf("\n");
142 }
143 static void printClass(int N){
144   printf("班级%d所有的学生有:",N+1);
145   PtrToNode ptr=classes[N].FirstStu;
146   while(ptr!=NULL){
147     printf("%10s",ptr->Stu_name);
148     if(ptr->BelongClass!=NULL){
149         printf("末尾");
150     }
151     ptr=ptr->SameCNextStudent;
152   }
153   printf("\n");
154 }
155 static void printInformation(){
156     printf("先输出所有学生所选的班级:\n");
157     int i;
158     for(i=0;i<5;i++){
159         printStudent(i);
160     }
161     printf("再输出所有班级里都有什么学生:\n");
162     for(i=0;i<5;i++){
163         printClass(i);
164     }
165 }
166 int main(){
167     srand(time(NULL));
168     Initial();
169      int StuAndCla[5][5];
170     int i;
171     int j;
172     int w;
173     for(i=0;i<5;i++){
174         for(j=0;j<5;j++){
175             StuAndCla[i][j]=0;
176         }
177     }
178     for(w=0;w<20;w++){
179         i=rand()%5;
180         j=rand()%5;
181         if(StuAndCla[i][j]==0){
182           StuAndCla[i][j]=1;
183           //printf("学生%d选了班级%d",i+1,j+1);
184           InsertIntoDoubleList(i,j);
185           //printInformation();
186           //printf("\n");
187         }
188     }
189     printInformation();
190 }

这样每个学生和一个班级的对应关系将转化为一个结点存在此二重链表中,而班级和学生的每一个子链的最后一个一个都指向该班级或学生,这个功能是为了这种情况:找某个同学所在的班级。这个功能是在输出这个结点时,如果它指向班级或者学生的头指针,则后面会加“末尾”两个字。

时间: 2024-09-29 15:57:56

数据结构与算法分析(6)表的应用实例的相关文章

数据结构与算法分析(线性表实现)

★线性表是一个序列(线性结构),具有一定的顺序 ★如果有多个元素,第一个元素没有前驱,最后一个元素没有后继 ★线性表强调是有限的 一.线性表基本存储结构 ㈠.顺序表 --把线性表的结点按逻辑顺序依次存放在一组地址连续的存储单元里,用这种方法存储的线性表简称顺序表 --在顺序表中,线性表的逻辑顺序与物理顺序一致 --在顺序表中,数据元素之间的关系是以元素在计算机内"物理位置相邻"来体现 ㈡.单链表 --把线性表的元素任意存放在存储单元结点中,节点之间按照逻辑顺序通过一个个指针依次链接起来

数据结构与算法分析:哈希表

以下是阅读了<算法导论>后,对哈希表的一些总结: 哈希表又叫散列表,是实现字典操作的一种有效数据结构.哈希表的查询效率极高,在没有冲突(后面会介绍)的情况下可做到一次存取便能得到所查记录,在理想情况下,查找一个元素的平均时间为O(1)(最差情况下散列表中查找一个元素的时间与链表中查找的时间相同:O(n),但实际情况中一般散列表的性能是比较好的). 哈希表就是描述key-value对的映射问题的数据结构,更详细的描述是:在记录的存储位置和它的关键字之间建立一个确定的对应关系h,使每个关键字与哈希

《数据结构与算法分析:C语言描述》复习——第四章“树”——AVL树

2014.06.15 16:22 简介: AVL树是一种高度平衡的二叉搜索树,其命名源自于联合发明算法的三位科学家的名字的首字母.此处“平衡”的定义是:任意节点的左右子树的高度相差不超过1.有了这个平衡的性质,使得AVL树的高度H总是接近log(N),因此各种增删改查的操作的复杂度能够保证在对数级别.没有bad case是AVL树与普通的二叉搜索树的最大区别.为了实现平衡性质,我们需要记录每个节点的高度(或者平衡因子)来检测不平衡的情况.为了修正高度不平衡,需要用到“旋转”的方法,分为单旋转和双

《数据结构与算法分析—C语言描述》pdf

下载地址:网盘下载 内容简介 编辑 <数据结构与算法分析:C语言描述(原书第2版)>内容简介:书中详细介绍了当前流行的论题和新的变化,讨论了算法设计技巧,并在研究算法的性能.效率以及对运行时间分析的基础上考查了一些高级数据结构,从历史的角度和近年的进展对数据结构的活跃领域进行了简要的概括.由于<数据结构与算法分析:C语言描述(原书第2版)>选材新颖,方法实用,题例丰富,取舍得当.<数据结构与算法分析:C语言描述(原书第2版)>的目的是培养学生良好的程序设计技巧和熟练的算

数据结构与算法分析-索引

作者:xiabodan 出处:http://blog.csdn.net/xiabodan 算法和数据结构是计算机科学的核心内容.作为程序猿,编程是我们的实战项目.然而,写出程序还不够.一个程序在应对一些大型而复杂的情况时.会耗费大量的时间.我们能够非常easy写出一个从文件里找到一个词的程序.比方逐词扫描.看是否相符.但假设我们的文件有几十TB,并且要从文件里找到上百个词,逐个扫描的办法就差点儿不可行.我们须要优化程序,以便我们的程序能够应对复杂问题. 算法研究解决这个问题的方法,而数据结构则是

《数据结构与算法分析》学习笔记(五)&mdash;&mdash;队ADT

一.队的概念        队列也是一种表,但是是一种受限的表,只允许从一端插入,另一端山粗的表. 二.队列的数组实现 #define QMAXSIZE 100 typedef int Position; typedef int QElement; typedef struct queue { QElement Els[QMAXSIZE]; Position head,tail; }Queue; void QCreate(Queue &Q) { Q.head = Q.tail = 0; } vo

数据结构与算法分析(4)算法分析的编程练习

    数据结构和算法分析的编程习题.     (1)生成不重复的随机数,并且具有上界和下界.可以产生有序的,也可以产生无序的. 知识: C编程语言不允许返回整个数组作为函数的参数.但是,您也可以返回一个指针,没有索引到一个数组中指定数组的名称. 例如: 1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<time.h> 4 5 int *getRandom(){ 6 static int r[10]; 7 int i

《数据结构与算法分析》学习笔记(四)——栈ADT

一.栈ADT是what? 1.定义 栈,是限制插入和删除都只能在一个位置上进行的表. 2.图示 3.栈的基本功能 (1)是否为空 (2)进栈 (3)出栈 (4)清空 (5)取栈顶 二.栈的链表实现 <数据结构与算法分析>学习笔记(四)--栈ADT

数据结构与算法分析 c语言描述 pdf 高清下载

网盘下载:数据结构与算法分析 c语言描述 pdf 高清下载 – 易分享电子书PDF资源网 作者: [美] Mark Allen Weiss 出版社: 机械工业出版社 副标题: C语言描述 原作名: Data Structures and Algorithm Analysis in C:Second Edition 译者: 冯舜玺 出版年: 2004-1-1 页数: 391 定价: 35.00元 装帧: 平装 内容简介 · · · · · · 本书是<Data Structures and Alg

数据结构与算法分析-第3章

.title { text-align: center; margin-bottom: .2em } .subtitle { text-align: center; font-size: medium; font-weight: bold; margin-top: 0 } .todo { font-family: monospace; color: red } .done { font-family: monospace; color: green } .priority { font-fami