在这里我介绍四个使用表解决实际中的问题的例子,分别是:
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 }
这样每个学生和一个班级的对应关系将转化为一个结点存在此二重链表中,而班级和学生的每一个子链的最后一个一个都指向该班级或学生,这个功能是为了这种情况:找某个同学所在的班级。这个功能是在输出这个结点时,如果它指向班级或者学生的头指针,则后面会加“末尾”两个字。