数据结构和算法分析(10)表栈和队列的实际应用(二)
本节继续介绍表、栈、队列在编程实践中的应用。
(1)行编辑程序:(允许用户输入出差错,并在发现错误时可以及时更正。)
功能:接受用户从终端输入的字符型的数据,并存入用户的数据区。由于不能保证不出差错,因此“每接受一个字符即存入用户数据区”的做法不是最恰当的;较好的做法是,设立一个输入的缓冲区,用以接受用户输入的一行字符,然后逐行存入用户数据区。
算法原理:当用户发现刚刚键入的一个字符是错的时,可补进一个退格符“#”,以表示前一个字符无效;如果发现当前键入的行内差错较多或者难以补救,则可以键入一个退行符“@”,以表示当前行中的字符均无效。
1 #include <stdio.h> 2 3 #define STACK_SIZE 100 //自定义能够临时存储用户输入的字符数 4 #define STACKINCREMENT 10 5 #define OVERFLOW -2 6 typedef char ElemType; 7 struct StackNode{ 8 ElemType *base; 9 ElemType *top; 10 int stacksize; 11 }; 12 typedef struct StackNode *TempStack; 13 void InitStack(TempStack S,int stackSize); 14 void Push(TempStack S,ElemType e); 15 void Pop(TempStack S,ElemType *e); 16 void DestoryStack(TempStack S); 17 void LineEdit(TempStack S); 18 void ClearStack(TempStack S); 19 20 void InitStack(TempStack S,int stackSize) { 21 S->base = (ElemType *)malloc(stackSize*sizeof(ElemType)); 22 if(!S->base) { 23 printf("内存不足!\n"); 24 exit(OVERFLOW); 25 } 26 S->top = S->base; 27 S->stacksize = stackSize; 28 } 29 void Push(TempStack S,ElemType e) { 30 //这段话能够使程序有很好的扩容性 31 if((S->top-S->base)>=S->stacksize) { 32 S->base = (ElemType*)realloc(S->base,(S->stacksize+STACKINCREMENT)*sizeof(ElemType)); 33 if(!S->base) { 34 exit(OVERFLOW); 35 } 36 S->top = S->base + S->stacksize; 37 S->stacksize += STACKINCREMENT; 38 } 39 *S->top++ = e; 40 } 41 void Pop(TempStack S,ElemType *e) { 42 if(S->top == S->base) 43 return; 44 *e = *--S->top; 45 } 46 void ClearStack(TempStack S) { 47 S->top = S->base; 48 } 49 void DestoryStack(TempStack S) { 50 S->top = S->base; 51 free(S->base); 52 S->top = NULL; 53 S->base = NULL; 54 } 55 void LineEdit(TempStack S) { 56 ElemType *p,ch,c; 57 InitStack(S, STACK_SIZE); 58 ch = getchar(); 59 while(ch != EOF) { 60 //进行字符入栈操作 61 while(ch!=EOF&&ch!='\n') { 62 switch(ch) { 63 case '#':Pop(S,&c);break; 64 case '@':ClearStack(S);break; 65 default:Push(S,ch);break; 66 } 67 ch = getchar(); 68 } 69 Push(S,ch);//最后的回车也要进入临时区 70 //遍历栈中的字符 71 p = S->base; 72 while(p!=S->top) { 73 printf("%c",*p); 74 ++p; 75 } 76 ClearStack(S); 77 if(ch!=EOF) ch = getchar(); 78 } 79 } 80 int main(){ 81 TempStack sq; 82 LineEdit(sq); 83 DestoryStack(sq); 84 return 0; 85 }
一个可调整的地方:
在接受终端输入时,每输入每一行字符(按回车)行编辑程序就自动执行一次,并返回临时栈中所有字符组成的字符串,并再次调用自身,当一行字符为空时程序运行结束。这个程序的缺点在于输出与处理没有分开。
(2)自调整链表:
自调整表如同一个规则的表,但是所有的插入都在表头进行。当一个元素被Find访问时,它就被移到表头而不改变其余项的相对位置。
1)数组实现:
1 /*---------------数组法实现自调整链表---------------*/ 2 #include <stdio.h> 3 #define LIST_SIZE 30 //数组大小 4 typedef char ElemeType; 5 6 struct ListNode{ 7 ElemeType *Array; 8 int num; 9 int Capicity; 10 }; 11 typedef struct ListNode *List; 12 List CreateList(int size){ 13 List list=malloc(sizeof(struct ListNode)); 14 list->Array=malloc(size*sizeof(ElemeType)); 15 list->num=0; 16 list->Capicity=size; 17 return list; 18 } 19 void InitList(List list){ 20 int i; 21 for(i=0;i<26;i++){ 22 list->Array[list->num]=(ElemeType)('A'+list->num); 23 list->num++; 24 } 25 } 26 void printList(List list){ 27 int i; 28 for(i=0;i<list->num;i++){ 29 putchar(list->Array[i]); 30 putchar(' '); 31 } 32 } 33 void find(ElemeType ch,List list){ 34 int i; 35 for(i=0;i<list->num;i++){ 36 if(ch==list->Array[i]){ 37 int j; 38 for(j=i;j>0;j--) 39 list->Array[j]=list->Array[j-1]; 40 list->Array[0]=ch; 41 return; 42 } 43 } 44 printf("链表里没有这个元素%c",ch); 45 } 46 int main(){ 47 List list=CreateList(LIST_SIZE); 48 InitList(list); 49 printList(list); 50 ElemeType temp[20]={ 51 'B','Z','B','C','W', 52 'Z','R','E','B','V', 53 'E','W','E','T','S', 54 'B','C','K','B','C' 55 };//B出现5次,E、C出现3次,Z出现2次,W出现2次,R、K、T、V、S各一次 56 int i; 57 for(i=0;i<20;i++){ 58 find(temp[i],list); 59 } 60 printf("\n自调整后的链表是:\n"); 61 printList(list); 62 printf("\n"); 63 return 0; 64 }
2)链表实现:
1 /*---------------链表法实现自调整链表---------------*/ 2 #include <stdio.h> 3 typedef char ElemeType; 4 5 struct ElemeNode{ 6 ElemeType element; 7 struct ElemeNode *next; 8 }; 9 typedef struct ElemeNode *PtrToNode; 10 typedef PtrToNode List; 11 List createList(){ 12 List list=malloc(sizeof(struct ElemeNode)); 13 list->next=NULL; 14 return list; 15 } 16 void InsertIntoList(ElemeType temp,List list){ 17 PtrToNode ptr=malloc(sizeof(struct ElemeNode)); 18 ptr->element=temp; 19 ptr->next=list->next; 20 list->next=ptr; 21 } 22 23 InitList(List list){ 24 int i; 25 for(i=25;i>=0;i--){ 26 ElemeType temp=(ElemeType)((int)'A'+i); 27 InsertIntoList(temp,list); 28 } 29 } 30 void printList(List list){ 31 PtrToNode ptr=list->next; 32 while(ptr){ 33 putchar(ptr->element); 34 putwchar(' '); 35 ptr=ptr->next; 36 } 37 } 38 int DeleteFromList(ElemeType element,List list){ 39 PtrToNode ptr=list; 40 while(ptr->next->element!=element){ 41 ptr=ptr->next; 42 } 43 if(ptr->next==NULL){ 44 return 0;//没有此元素 45 }else{ 46 ptr->next=ptr->next->next; 47 return 1; 48 } 49 } 50 void find(ElemeType element,List list){ 51 if(DeleteFromList(element,list)) 52 InsertIntoList(element,list); 53 else 54 printf("没有此元素!\n"); 55 } 56 int main(){ 57 List list=createList(); 58 InitList(list); 59 printList(list); 60 ElemeType temp[20]={ 61 'B','Z','B','C','W', 62 'Z','R','E','B','V', 63 'E','W','E','T','S', 64 'B','C','K','B','C' 65 };//B出现5次,E、C出现3次,Z出现2次,W出现2次,R、K、T、V、S各一次 66 int i; 67 for(i=0;i<20;i++){ 68 find(temp[i],list); 69 } 70 printf("\n自调整后的链表是:\n"); 71 printList(list); 72 printf("\n"); 73 return 0; 74 }
(3)用一个数组实现多个栈:(除非数组中的每个单元都被使用否则不能有溢出声明)
算法原理:对与不支持指针的语言(例如java)采用游标法实现表:(与这个例子作对比:http://www.cnblogs.com/MenAngel/p/5539085.html)
1 /*---------------游标模式下栈的实现---------------*/ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #define SpaceSize 60 5 6 typedef int PtrToNode; 7 typedef PtrToNode Stack; 8 typedef PtrToNode Position; 9 10 struct Node{ 11 int Element; 12 int flag;//记录元素出现的次数 13 Position Next;//Next指针指向的不是具体的结点的首地址,而是结点的下标 14 }; 15 //编译时预先分配的结点数组 16 struct Node CursorSpace[SpaceSize]; 17 //CursorSpace[0]是表头指针 18 static void InitialCursor(void){ 19 int i; 20 for(i=0;i<SpaceSize;i++){ 21 CursorSpace[i].Next=i+1; 22 } 23 CursorSpace[i].Next=0; 24 } 25 26 static Position CursorAlloc(void){ 27 Position p; 28 p=CursorSpace[0].Next; 29 CursorSpace[0].Next=CursorSpace[p].Next; 30 CursorSpace[p].Next=0; 31 return p;//当p的值为0时说明没有空间可用了 32 } 33 34 static void CursorFree(Position p){ 35 CursorSpace[p].Next=CursorSpace[0].Next; 36 CursorSpace[0].Next=p; 37 } 38 void InitStack(Stack *S){ 39 PtrToNode p=CursorAlloc(); 40 //新建的结点需要指向头结点 41 CursorSpace[p].Next=0; 42 *S=p; 43 } 44 45 int IsLast(Position p,Stack S){ 46 return CursorSpace[p].Next==0; 47 } 48 void InsertIntoStack(int x,Stack S){ 49 Position TmpCell; 50 TmpCell=CursorAlloc(); 51 if(TmpCell==0){ 52 printf("空间已经使用完,溢出!\n"); 53 //exit(0); 54 return; 55 } 56 CursorSpace[TmpCell].Element=x; 57 CursorSpace[TmpCell].flag=1; 58 CursorSpace[TmpCell].Next=CursorSpace[S].Next; 59 CursorSpace[S].Next=TmpCell; 60 } 61 void printStack(Stack stack){ 62 Position p=stack; 63 Position temp; 64 int i; 65 int w=0; 66 while((temp=CursorSpace[p].Next)!=0){ 67 //printf("%d",CursorSpace[temp].flag); 68 for(i=0;i<CursorSpace[temp].flag;i++){ 69 printf("%3d",CursorSpace[temp].Element); 70 w++; 71 if(w%30==0){ 72 printf("\n"); 73 } 74 } 75 p=CursorSpace[p].Next; 76 } 77 } 78 int main(){ 79 InitialCursor(); 80 Stack stack_a;InitStack(&stack_a); 81 Stack stack_b;InitStack(&stack_b); 82 Stack stack_c;InitStack(&stack_c); 83 Stack stack_d;InitStack(&stack_d); 84 int i; 85 int rand_num; 86 //程序准备的是60个,这里需要4+57=61个空间,一次最后一次操作将会溢出 87 for(i=0;i<=56;i++){ 88 rand_num=rand()%4+1; 89 switch(rand_num){ 90 case 1:InsertIntoStack(i,stack_a);break; 91 case 2:InsertIntoStack(i,stack_b);break; 92 case 3:InsertIntoStack(i,stack_c);break; 93 case 4:InsertIntoStack(i,stack_d);break; 94 default:printf("出现错误\n"); 95 } 96 } 97 printf("栈a中的元素有:\n"); 98 printStack(stack_a); 99 printf("\n栈b中的元素有:\n"); 100 printStack(stack_b); 101 printf("\n栈c中的元素有:\n"); 102 printStack(stack_c); 103 printf("\n栈d中的元素有:\n"); 104 printStack(stack_d); 105 printf("\n"); 106 return 0; 107 }
(4)渡轮模拟问题:(队列的实际应用)
有一个渡口,每条渡船能一次性装载10辆汽车过河,车辆分为客车和货车两类。上渡轮有如下规定:
1.同类车辆先到先上船,客车先于货车上船;
2.每上3辆客车才允许上一辆货车,但若等待的客车不足4辆则用货车填补,反过来,若没有货车等待则用客车填补。
3.装满10辆后则自动开船,当等待时间较长时车辆不足10辆也应认为控制发船。
1)c语言版本:
1 /*---------------队列模拟渡轮问题---------------*/ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <time.h> 5 #include <string.h> 6 #define YES 1 7 #define NO 0; 8 //采用链表法实现队列 9 struct CarNode{ 10 char name[5];//存车辆的名称 11 int id;//标志车辆的类型 12 struct CarNode *next; 13 }; 14 typedef struct CarNode *Car; 15 struct LinkQueueNode{ 16 Car front; 17 Car rear; 18 int flag; 19 int size;//队列元素的大小 20 }; 21 typedef struct LinkQueueNode *Queue; 22 23 void PrintInfo(){ 24 printf("请输入适当的数字完成特定的任务:\n"); 25 printf("1.---车辆进行登记 "); 26 printf("2.---渡轮进行登记 "); 27 printf("3.---当前排队情况 "); 28 printf("4.---汽车装上渡轮 "); 29 printf("5.---命令渡轮起航 "); 30 printf("6.---结束程序运行 \n"); 31 } 32 void InitQueue(Queue q,int flag){; 33 //让队列拥有一个元素,这个元素不存任何东西 34 q->front=q->rear=malloc(sizeof(struct CarNode)); 35 q->front=q->rear; 36 q->flag=flag; 37 //printf(q->front->name); 38 q->front->id=-1; 39 q->front->next=NULL; 40 q->size=0; 41 } 42 //将车加入队列 43 void EnQueue(Queue q){ 44 Car temp_car=malloc(sizeof(struct CarNode)); 45 if(q->flag==0){ 46 strcpy(temp_car->name,"客车"); 47 temp_car->id=q->size+1; 48 }else{ 49 strcpy(temp_car->name,"货车"); 50 temp_car->id=q->size+1; 51 } 52 temp_car->next=NULL; 53 q->rear->next=temp_car; 54 q->rear=temp_car; 55 q->size++; 56 //printf(q->rear->name); 57 } 58 Car DeQueue(Queue q){ 59 //printf(q->front->name); 60 Car temp_car=q->front->next; 61 q->front->next=q->front->next->next; 62 q->size--; 63 //printf(temp_car->name); 64 //printf("%d出队",temp_car->id); 65 return temp_car; 66 } 67 int IsEmptyQueue(Queue q){ 68 return q->size==0; 69 } 70 void printQueue(Queue temp_queue){ 71 Car temp_car=temp_queue->front->next; 72 while(temp_car!=NULL){ 73 printf(temp_car->name);printf("%d ",temp_car->id); 74 temp_car=temp_car->next; 75 } 76 printf("\n"); 77 } 78 void printBoat(Car *boat,int n){ 79 //printf("已经装到渡轮上的车有:\n"); 80 int i; 81 for(i=0;i<n;i++){ 82 printf(boat[i]->name);printf("%d ",boat[i]->id); 83 } 84 printf("\n"); 85 } 86 int main(){ 87 int flag=0;//用来接收用户输入的命令数字 88 int mark=NO;//mark标志渡轮是否已经到渡口 89 long t1,t2;//分别记录渡轮到达渡口和离开渡口的时间 90 //这里出现一个错误 91 Queue queue_human=malloc(sizeof(struct LinkQueueNode)); 92 Queue queue_thing=malloc(sizeof(struct LinkQueueNode)); 93 Car boat[10];//用数组记录渡轮上每个汽车的汽车号,和已经装的车数 94 int n; 95 InitQueue(queue_human,0); 96 InitQueue(queue_thing,1); 97 while(1){ 98 //1.显示功能菜单: 99 L: PrintInfo(); 100 do{ 101 scanf("%d",&flag); 102 getchar(); 103 if(flag<1||flag>6) 104 printf("功能%d没有被定义,请重新输入\n"); 105 }while(flag<1||flag>6); 106 //将每个数字对应的功能实现 107 switch(flag){ 108 //将等待装船的各种车放在各自等待的队列中 109 case 1:{ 110 int num;int i; 111 printf("此时间段有多少辆客车到达港口:\n"); 112 scanf("%d",&num);getchar(); 113 for(i=0;i<num;i++){ 114 EnQueue(queue_human); 115 } 116 printf("此时间段有多少辆货车到达港口:\n"); 117 scanf("%d",&num);getchar(); 118 for(i=0;i<num;i++){ 119 EnQueue(queue_thing); 120 } 121 }break; 122 //标记此事是否有渡船已到达港口 123 case 2:{ 124 if(mark==YES){ 125 printf("已经有渡船在渡口等待!\n"); 126 break; 127 } 128 mark=YES; 129 printf("渡口来了一只船,车辆可以装船。\n"); 130 n=0; 131 t1=time(0); 132 }break; 133 case 3:{ 134 printf("等待过江的客车有:\n"); 135 printQueue(queue_human); 136 printf("等待过江的货车有:\n"); 137 printQueue(queue_thing); 138 }break; 139 case 4:{ 140 //当队列为空,已有轮渡在准备 141 if(IsEmptyQueue(queue_thing)&&IsEmptyQueue(queue_human)){ 142 printf("暂无车辆准备过河"); 143 if(mark==1&&n>0&&n<10){ 144 t2=time(0); 145 long t=t2-t1;//渡轮到目前为止等待的秒数; 146 printf("轮渡未满,有%d辆车已经装船,等待其他汽车上渡轮,并且已经等待%d分%d秒。",n,t/60,t%60); 147 } 148 break; 149 } 150 //当没有轮渡时 151 if(mark!=1){ 152 printf("渡轮未到,请汽车稍后上渡轮"); 153 break; 154 } 155 do{ 156 int temp_num=0; 157 //printf("n=%d\n",n); 158 //当有轮渡且队列不为空时 159 //先上4辆客车 160 while(!IsEmptyQueue(queue_human)&&n<10&&temp_num<4){ 161 //printf("\n%d,%d\n",temp_num,n); 162 boat[n]=DeQueue(queue_human);n++; 163 //printBoat(boat,n); 164 temp_num++; 165 } 166 //如果满10辆,自动开船,转到功能菜单 167 if(n==10){ 168 printf("轮渡开走!\n"); 169 printBoat(boat,n); 170 mark=0; 171 n=0; 172 goto L; 173 } 174 //如果未满10辆,判断4辆客车的名额是否用满,未用满用货车补 175 if(temp_num==4){ 176 if(!IsEmptyQueue(queue_thing)){ 177 boat[n]=DeQueue(queue_thing);n++; 178 temp_num++; 179 } 180 } 181 else{ 182 //这里连货车的名额一块加上了,所以是小于5 183 while(!IsEmptyQueue(queue_thing)&&temp_num<5&&n<10) 184 boat[n]=DeQueue(queue_thing);n++; 185 printf(boat[temp_num]->name); 186 temp_num++; 187 } 188 if(n==10){ 189 printf("轮渡起航,载的车辆有:\n"); 190 printBoat(boat,n); 191 mark=0; 192 n=0; 193 goto L; 194 } 195 }while(!IsEmptyQueue(queue_human)||!IsEmptyQueue(queue_thing)); 196 }break; 197 case 5:{ 198 if(n==0||mark==0) 199 printf("轮渡上没有车过江或者港口没有渡轮!不能起航!\n"); 200 else{ 201 printf("轮渡起航,载的车辆有:\n"); 202 printBoat(boat,n); 203 mark=NO;n=0; 204 } 205 }break; 206 case 6:{ 207 if(!IsEmptyQueue(queue_human)||!IsEmptyQueue(queue_thing)){ 208 printf("还有汽车未渡江,暂且不能结束!\n"); 209 break; 210 } 211 if(n!=0){ 212 printf("渡轮上还有车,暂且不能结束!\n"); 213 break; 214 } 215 printf("程序运行结束\n"); 216 return 0; 217 }break; 218 default:printf("不知名错误!\n");break; 219 } 220 } 221 }
2)c++版:
c++版将会在后续的c++系列中涉及,用面向对象的思想解决。
(5)队列的离散时间模拟:
银行业务的模拟程序:
1.有多个窗口对外接待客户。(模拟时指定为4个)
2.从银行开门不断有客户进入银行。
3.对于刚进银行的客户,如果有空闲窗口则上前办理业务,否则插在最短队列后。
4.不考虑顾客中途离开,顾客到达事件随机,业务办理时间。
求在这一事件驱动模拟过程中客户在银行的平均逗留时间。
1 /*---------------模拟银行营业时的排队情况---------------*/ 2 #include <stdio.h> 3 #include <time.h> 4 #include <stdlib.h> 5 6 #define OK 1 7 #define ERROR 0 8 #define TRUE 1 9 #define FALSE 0 10 11 typedef int Status; 12 typedef struct Event{ 13 int OccurTime;//事件发生时刻 14 int NType;//事件类型,0表示到达事件,1至4表示四个窗口的离开事件 15 struct Event *next; 16 }Event,ElemType; 17 typedef struct{//单向链表结构 18 ElemType *head;//头指针 19 ElemType *tail;//尾指针 20 int len;//长度 21 }LinkList; 22 typedef LinkList EventList; //事件链表 23 typedef struct QElemType{ //队列元素 24 int ArriveTime;//到达时间 25 int Duration;//办理业务所需时间 26 struct QElemType *next; 27 }QElemType; 28 typedef struct{//队列结构 29 QElemType *head;//头指针 30 QElemType *tail;//尾指针 31 }LinkQueue; 32 33 /*-----全局变量-----*/ 34 EventList ev; 35 Event en; 36 LinkQueue q[5]; 37 QElemType customer; 38 int TotalTime,CustomerNum; 39 int CloseTime=50;//关闭时间,即营业时间长度 40 41 Event NewEvent(int occurT,int nType);//根据OccurTime和NType值,创建新事件 42 Status InitList(LinkList *L);//初始化事件链表 43 Status OrderInsert(LinkList *L,Event e);//将事件e按发生时间顺序插入有序链表L中 44 Status ListEmpty(LinkList *L);//判断链表L是否为空,为空返回TRUE,否则返回FALSE 45 Status DelFirst(LinkList *L,ElemType *e);//链表L不为空,删除其首结点,用e返回,并返回OK;否则返回ERROR 46 Status ListTraverse(LinkList *L);//遍历链表 47 Status InitQueue(LinkQueue *Q);//初始化队列Q 48 Status EmptyQueue(LinkQueue *Q);//若队列Q为空,返回TRUE,否则返回FALSE 49 Status DelQueue(LinkQueue *Q,QElemType *e);//若队列Q不为空,首结点出队,用e返回,并返回OK;否则返回ERROR 50 Status EnQueue(LinkQueue *Q,QElemType e);//结点e入队Q 51 int QueueLength(LinkQueue Q);//返回队列Q的长度,即元素个数 52 Status GetHead(LinkQueue *Q,QElemType *e);//若队列Q不为空,用e返回其首结点,并返回OK,否则返回ERROR 53 Status QueueTraverse(LinkQueue *Q);//遍历队列Q 54 int Min(int a[],int n); //返回长度为n的数组a第一个最小值的下标,从1开始 55 int ShortestQueue();//获取最短队列的编号 56 void OpenForDay();//初始化操作 57 void CustomerArrived();//顾客达到事件 58 void CustomerDepature();//顾客离开事件 59 void Bank_Simulation();//银行排队模拟 60 void PrintEventList();//输出事件队列 61 void PrintQueue();//打印当前队列 62 63 void PrintQueue(){ 64 int i; 65 for(i=1;i<=4;i++){ 66 printf("Queue %d have %d customer(s):",i,QueueLength(q[i])); 67 QueueTraverse(&q[i]); 68 } 69 printf("\n"); 70 } 71 void PrintEventList(){ 72 printf("Current Eventlist is:\n"); 73 ListTraverse(&ev); 74 } 75 int Min(int a[],int n){ 76 //返回长度为n的数组a第一个最小值的下标,从0开始 77 int i,tmp,ind=0; 78 tmp=a[0]; 79 for(i=1;i<n;i++){ 80 if(a[i]<tmp){ 81 tmp=a[i]; 82 ind=i; 83 } 84 } 85 return ind; 86 } 87 int ShortestQueue(){ 88 int i,a[4]; 89 for(i=1;i<=4;i++){ 90 a[i-1]=QueueLength(q[i]); 91 //printf("队%d的长度为%d\n",i,QueueLength(q[i])); 92 } 93 return Min(a,4)+1;//队列从1开始编号 94 } 95 96 Event NewEvent(int occurT,int nType){ 97 Event e; 98 e.OccurTime=occurT; 99 e.NType=nType; 100 return e; 101 } 102 Status ListTraverse(LinkList *L){ 103 //遍历链表 104 Event *p=L->head->next; 105 if(!p){ 106 printf("List is empty.\n"); 107 return ERROR; 108 } 109 while(p!=NULL){ 110 printf("OccurTime:%d,Event Type:%d\n",p->OccurTime,p->NType); 111 p=p->next; 112 } 113 printf("\n"); 114 return OK; 115 } 116 Status InitQueue(LinkQueue *Q){ 117 //初始化队列Q 118 Q->head=Q->tail=(QElemType *)malloc(sizeof(QElemType)); 119 if(!Q->head){ 120 printf("Apply for memory error.LinkQueue initialize failed.\n"); 121 exit(0); 122 } 123 Q->head->next=NULL; 124 return OK; 125 } 126 Status EmptyQueue(LinkQueue *Q){ 127 //若队列Q为空,返回TRUE,否则返回FALSE 128 if(Q->head==Q->tail&&Q->head!=NULL) 129 return TRUE; 130 else 131 return FALSE; 132 } 133 Status DelQueue(LinkQueue *Q,QElemType *e){ 134 //若队列Q不为空,首结点出队,用e返回,并返回OK;否则返回ERROR 135 QElemType *p=Q->head->next; 136 if(!p) 137 return ERROR; 138 *e=*p; 139 Q->head->next=p->next;//修正队首指针 140 free(p); 141 if(!Q->head->next)//队空 142 Q->tail=Q->head; 143 return OK; 144 } 145 Status EnQueue(LinkQueue *Q,QElemType e){ 146 //结点e入队Q 147 QElemType *p=(QElemType *)malloc(sizeof(QElemType)); 148 if(!p){ 149 printf("Apply for memory error,new element can't enqueue.\n"); 150 exit(0); 151 } 152 *p=e; 153 p->next=NULL; 154 Q->tail->next=p;//插入队尾 155 Q->tail=p;//修改队尾指针 156 return OK; 157 } 158 int QueueLength(LinkQueue Q){ 159 //返回队列Q的长度,即元素个数 160 int count=0; 161 QElemType *p=Q.head->next; 162 while(p){ 163 p=p->next; 164 count++; 165 } 166 return count; 167 } 168 Status GetHead(LinkQueue *Q,QElemType *e){ 169 //若队列Q不为空,用e返回其首结点,并返回OK,否则返回ERROR 170 if(EmptyQueue(Q)) 171 return ERROR; 172 *e=*(Q->head->next); 173 return OK; 174 } 175 Status QueueTraverse(LinkQueue *Q){ 176 //遍历队列Q 177 QElemType *p=Q->head->next; 178 if(!p){ 179 printf("--Is empty.\n"); 180 return ERROR; 181 } 182 while(p){ 183 printf("(%d,%d) ",p->ArriveTime,p->Duration); 184 p=p->next; 185 } 186 printf("\n"); 187 return OK; 188 } 189 Status InitList(LinkList *L){ 190 L->head=L->tail=(ElemType *)malloc(sizeof(ElemType)); 191 if(!L->head){ 192 printf("Apply for memory error.LinkList initialize failed.\n"); 193 exit(0); 194 } 195 L->head->next=NULL; 196 return OK; 197 } 198 Status OrderInsert(LinkList *L,Event e){ 199 ElemType *p,*q,*newptr; 200 newptr=(ElemType *)malloc(sizeof(ElemType)); 201 if(!newptr){ 202 printf("Apply for memory error,new node can't insert intot the Eventlist.\n"); 203 exit(0); 204 } 205 *newptr=e; 206 if(TRUE==ListEmpty(L)){//链表为空 207 L->head->next=newptr; 208 L->tail=newptr; 209 L->tail->next=NULL; 210 return OK; 211 } 212 q=L->head; 213 p=L->head->next; 214 while(p){//遍历整个链表 215 if(p->OccurTime>=newptr->OccurTime) 216 break; 217 q=p; 218 p=p->next; 219 } 220 q->next=newptr; 221 newptr->next=p; 222 if(!p)//插入位置为链表尾部 223 L->tail=newptr; 224 return OK; 225 } 226 void OpenForDay(){ 227 //初始化操作 228 int i; 229 TotalTime=0; CustomerNum=0; 230 InitList(&ev);//初始化事件队列 231 en.OccurTime=0; 232 en.NType=0; 233 OrderInsert(&ev,en); 234 for(i=1;i<=4;i++) 235 InitQueue(&q[i]);//初始化四个窗口队列 236 } 237 Status ListEmpty(LinkList *L){ 238 //判断链表L是否为空,为空返回TRUE,否则返回FALSE 239 if((L->head==L->tail)&&(L->head!=NULL)) 240 return TRUE; 241 else 242 return FALSE; 243 } 244 Status DelFirst(LinkList *L,ElemType *e){ 245 //链表L不为空,删除其首结点,用e返回,并返回OK;否则返回ERROR 246 ElemType *p=L->head->next; 247 if(!p) 248 return ERROR; 249 L->head->next=p->next; 250 *e=*p; 251 free(p); 252 if(L->head->next==NULL) 253 L->tail=L->head; 254 return OK; 255 } 256 void CustomerArrived(){ 257 //顾客达到事件 258 int durtime,intertime,i,t; 259 QElemType e; 260 ++CustomerNum; 261 intertime=rand()%5+1;//间隔时间在5分钟内 262 durtime=rand()%30+1;//办理业务时间在30分钟内 263 t=en.OccurTime+intertime; 264 if(t<CloseTime){//银行尚未关门 265 printf("A new customer will arrive at:%d\n",en.OccurTime);//下一位顾客达到时间 266 OrderInsert(&ev,NewEvent(t,0)); 267 i=ShortestQueue();//最短队列 268 e.ArriveTime=en.OccurTime; 269 e.Duration=durtime; 270 EnQueue(&q[i],e); 271 if(QueueLength(q[i])==1) 272 OrderInsert(&ev,NewEvent(en.OccurTime+durtime,i)); 273 } 274 } 275 void CustomerDepature(){ 276 int i=en.NType; 277 DelQueue(&q[i],&customer); 278 printf("A customer leaves at:%d\n",en.OccurTime);//输出顾客离开时间 279 TotalTime+=en.OccurTime-customer.ArriveTime; 280 if(!EmptyQueue(&q[i])){ 281 GetHead(&q[i],&customer); 282 OrderInsert(&ev,NewEvent(en.OccurTime+customer.Duration,i)); 283 } 284 } 285 void Bank_Simulation(){ 286 OpenForDay(); 287 srand((unsigned)time(NULL)); 288 while(!ListEmpty(&ev)){ 289 DelFirst(&ev,&en);//取出一个事件给en 290 if(en.NType==0) 291 CustomerArrived(); 292 else 293 CustomerDepature(); 294 //PrintEventList(); 295 //PrintQueue(); 296 } 297 printf("Total time is: %d min,average time is: %g min.\n",TotalTime,(float)TotalTime/CustomerNum); 298 } 299 int main(){ 300 Bank_Simulation(); 301 return 0; 302 }
这里还有一个地方模拟的不准确:
这个程序做到了在营业时间内允许用户到达队列,在营业时间以外,正在办理的用户需要完成办理业务,而已经在队列中的客户需要被迫离开。
(6)双端队列(deque):
双端队列是由一些项的表组成的数据结构,对该数据结构可以进行下列操作:
1.Push(X,D)将项x插入双端队列的前端; 2.Pop(D)从双端队列D中删除前端项并将其返回; 3.Inject(X,D)将项x插入双端队列的尾端; 4.Eject(D)从双端队列D中删除尾端项并将其返回;
编写支持双端队列的例程,每种操作仅花费O(1)时间。
1 /***************双端队列的链表实现***************/ 2 #include<stdio.h> 3 typedef char ElementType; 4 //定义元素结点 5 struct DataNode{ 6 ElementType element; 7 struct DataNode *next; 8 }; 9 typedef struct DataNode *Data; 10 typedef Data PtrToNode; 11 //定义队列结点 12 struct QueueNode{ 13 Data front; 14 Data rear; 15 }; 16 typedef struct QueueNode *Queue; 17 Queue createQueue(){ 18 Queue tempQueue=malloc(sizeof(struct QueueNode)); 19 tempQueue->rear=tempQueue->front=NULL; 20 return tempQueue; 21 } 22 //插入元素到首端 23 void Push(ElementType element,Queue Q){ 24 PtrToNode tempNode=malloc(sizeof(struct DataNode)); 25 tempNode->element=element; 26 tempNode->next=NULL; 27 if(Q->front==NULL){ 28 tempNode->next=Q->front; 29 Q->front=tempNode; 30 Q->rear=Q->front; 31 }else{ 32 tempNode->next=Q->front; 33 Q->front=tempNode; 34 } 35 } 36 //删除并返回首端的元素 37 Data Pop(Queue Q){ 38 PtrToNode tempNode=Q->front; 39 Q->front=Q->front->next; 40 return tempNode; 41 } 42 //插入元素到尾端 43 void Inject(ElementType element,Queue Q){ 44 PtrToNode tempNode=malloc(sizeof(struct DataNode)); 45 tempNode->element=element; 46 tempNode->next=NULL; 47 if(Q->rear==NULL){ 48 Q->rear=tempNode; 49 Q->front=Q->front; 50 }else{ 51 Q->rear->next=tempNode; 52 Q->rear=tempNode; 53 } 54 } 55 //删除并返回尾端的元素 56 Data Eject(Queue q){ 57 PtrToNode tempNode=q->rear; 58 PtrToNode ptr=q->front; 59 while(ptr->next!=q->rear){ 60 ptr=ptr->next; 61 } 62 q->rear=ptr; 63 return tempNode; 64 } 65 //输出队列中的数据,用于测试 66 void printQueue(Queue q){ 67 PtrToNode ptr=q->front; 68 while(ptr!=NULL){ 69 putchar(ptr->element); 70 ptr=ptr->next; 71 } 72 printf("\n"); 73 } 74 int main(){ 75 Queue queue=createQueue(); 76 int i; 77 PtrToNode tempNode=NULL; 78 printf("测试Push和Eject:\n"); 79 for(i=0;i<10;i++){ 80 Push((ElementType)('A'+i),queue); 81 //printQueue(queue);printf("\n"); 82 } 83 printf("队列中的所有元素有:"); 84 printQueue(queue); 85 for(i=0;i<5;i++){ 86 tempNode=Eject(queue); 87 putchar(tempNode->element); 88 } 89 printf("\n测试Inject和Pop:\n"); 90 for(i=0;i<10;i++){ 91 Inject((ElementType)('A'+i),queue); 92 } 93 printf("队列中的所有元素有:"); 94 printQueue(queue); 95 for(i=0;i<15;i++){ 96 tempNode=Pop(queue); 97 putchar(tempNode->element); 98 } 99 return 0; 100 }