zoukankan      html  css  js  c++  java
  • 数据结构和算法分析(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("内存不足!
    ");
    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!='
    ') {
    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("
    自调整后的链表是:
    ");
    61   printList(list);
    62   printf("
    ");
    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("没有此元素!
    ");
    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("
    自调整后的链表是:
    ");
    71   printList(list);
    72   printf("
    ");
    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("空间已经使用完,溢出!
    ");
     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("
    ");
     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("出现错误
    ");             
     95         }
     96     }
     97     printf("栈a中的元素有:
    ");
     98     printStack(stack_a); 
     99     printf("
    栈b中的元素有:
    ");    
    100     printStack(stack_b); 
    101     printf("
    栈c中的元素有:
    ");
    102     printStack(stack_c); 
    103     printf("
    栈d中的元素有:
    ");
    104     printStack(stack_d); 
    105     printf("
    ");
    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("请输入适当的数字完成特定的任务:
    ");
     25     printf("1.---车辆进行登记 ");
     26     printf("2.---渡轮进行登记 ");
     27     printf("3.---当前排队情况 "); 
     28     printf("4.---汽车装上渡轮 ");
     29     printf("5.---命令渡轮起航 ");
     30     printf("6.---结束程序运行 
    "); 
     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("
    "); 
     77 }
     78 void printBoat(Car *boat,int n){
     79     //printf("已经装到渡轮上的车有:
    ");
     80     int i;
     81     for(i=0;i<n;i++){
     82         printf(boat[i]->name);printf("%d ",boat[i]->id);
     83     }
     84     printf("
    ");
     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没有被定义,请重新输入
    ");    
    105       }while(flag<1||flag>6);
    106       //将每个数字对应的功能实现 
    107       switch(flag){
    108           //将等待装船的各种车放在各自等待的队列中 
    109           case 1:{
    110               int num;int i;
    111               printf("此时间段有多少辆客车到达港口:
    ");
    112               scanf("%d",&num);getchar(); 
    113               for(i=0;i<num;i++){
    114                   EnQueue(queue_human); 
    115               }
    116               printf("此时间段有多少辆货车到达港口:
    ");
    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("已经有渡船在渡口等待!
    ");
    126                 break;
    127             }
    128             mark=YES;
    129             printf("渡口来了一只船,车辆可以装船。
    ");
    130             n=0;
    131             t1=time(0);
    132         }break;           
    133         case 3:{
    134             printf("等待过江的客车有:
    ");
    135             printQueue(queue_human);
    136             printf("等待过江的货车有:
    ");
    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);
    158                   //当有轮渡且队列不为空时
    159                 //先上4辆客车        
    160                 while(!IsEmptyQueue(queue_human)&&n<10&&temp_num<4){
    161                     //printf("
    %d,%d
    ",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("轮渡开走!
    ");
    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("轮渡起航,载的车辆有:
    ");
    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("轮渡上没有车过江或者港口没有渡轮!不能起航!
    ");
    200             else{
    201                 printf("轮渡起航,载的车辆有:
    ");
    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("还有汽车未渡江,暂且不能结束!
    ");
    209                 break;
    210             }
    211             if(n!=0){
    212                 printf("渡轮上还有车,暂且不能结束!
    ");
    213                 break;
    214             }
    215             printf("程序运行结束
    ");
    216             return 0; 
    217         }break;    
    218         default:printf("不知名错误!
    ");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("
    ");
     70 }
     71 void PrintEventList(){
     72     printf("Current Eventlist is:
    ");
     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
    ",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.
    ");
    107         return ERROR;
    108     }
    109     while(p!=NULL){
    110         printf("OccurTime:%d,Event Type:%d
    ",p->OccurTime,p->NType);
    111         p=p->next;
    112     }
    113     printf("
    ");
    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.
    ");
    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.
    ");
    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.
    ");
    180         return ERROR;
    181     }
    182     while(p){
    183         printf("(%d,%d) ",p->ArriveTime,p->Duration);
    184         p=p->next;
    185     }
    186     printf("
    ");
    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.
    ");
    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.
    ");
    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
    ",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
    ",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.
    ",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("
    ");
     73 }
     74 int main(){
     75   Queue queue=createQueue(); 
     76   int i;
     77   PtrToNode tempNode=NULL;
     78   printf("测试Push和Eject:
    "); 
     79   for(i=0;i<10;i++){
     80       Push((ElementType)('A'+i),queue);
     81       //printQueue(queue);printf("
    ");
     82   }
     83   printf("队列中的所有元素有:");
     84   printQueue(queue); 
     85   for(i=0;i<5;i++){
     86       tempNode=Eject(queue);
     87     putchar(tempNode->element); 
     88   }
     89   printf("
    测试Inject和Pop:
    ");
     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  }

  • 相关阅读:
    Kafka usecase
    kafka 的quick start(windows平台)
    kafka介绍
    问题记录 为ubuntu16.04添加windows字体(解决JIRA图表乱码的问题)
    问题记录,如何解决confluence的office预览的时候的乱码问题
    为gitlab10.x增加使用remote_user HTTP头的方式登录
    基于spring-cloud的微服务(4)API网关zuul
    基于spring-cloud的微服务(3)eureka的客户端如何使用IP地址来进行注册
    基于spring-cloud的微服务(2) eureka服务提供方的注册和消费方的消费
    WebView 上传文件 WebChromeClient之openFileChooser函数
  • 原文地址:https://www.cnblogs.com/MenAngel/p/5805786.html
Copyright © 2011-2022 走看看