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

    介紹隊列的相關知識:html

 

    (3)隊列ADT:算法

      像棧同樣,隊列也是表。然而,使用隊列時插入在一端進行而刪除在另外一端進行。數組

    3.1隊列模型服務器

      隊列的基本操做是Enqueue(入隊),它是在表的末端插入一個元素;還有Dequeue(出隊),它是刪除(或同時)返回在表的開頭的元素。網絡

    3.2隊列的數組實現數據結構

      如同棧的情形同樣,對於隊列而言任何表的實現都是合法的。隊列的鏈表實現是直接的,如今咱們只討論隊列的數組實現。函數

      1)隊列數組實現的ADT:學習

#define MinQueueSize (5)
typedef int ElementType; 
struct QueueRecord{
  int Capacity;//隊列包含元素的最大值
  int Front;
  int Rear;
  int Size;//現有隊列的大小
  ElementType *Array;    
};
typedef struct QueueRecord Queue;
int IsEmpty(Queue Q);
int IsFull(Queue Q);
Queue CreateQueue(int MaxElements);
void DisposeQueue(Queue Q);
void MakeEmpty(Queue Q);
void EnQueue(ElementType X,Queue Q);
ElementType Front(Queue Q);
void Dequeue(Queue Q);
ElementType FrontAndDequeue(Queue Q); 
int IsEmpty(Queue Q){
  return Q->Size==0;
}
void MakeEmpty(){
  Q->Size=0;
  Q->Front=1;
  Q->Rear=0;
}
//對下標進行處理,防止躍出數組邊界
static int Succ(int Value,Queue Q){
  if(++Value==Q->Capacity){
    value=0;
  }
  return Value;
}
void Enqueue(ElementType X,Queue Q){
  if(IsFull(Q)){
    printf("隊列已經滿了!);
  }else{
    Q->Size++;
    Q->Rear=Succ(Q->Rear,Q);
    Q->Array[Q->Rear]==X;
  }
}

      2)隊列的數組實現的實例:url

      將一個隨機無序數組中的每一個元素依次插入隊列,再執行出隊操做和入隊操做。spa

  1 //隊列的應用實例 
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<time.h>
  5 #define MinQueueSize (5)
  6 
  7 struct QueueRecord;
  8 typedef int ElementType; 
  9 typedef struct QueueRecord *Queue;
 10 
 11 int IsEmpty(Queue Q);
 12 int IsFull(Queue Q);
 13 Queue CreateQueue(int MaxElements);
 14 void DisposeQueue(Queue Q);
 15 void MakeEmpty(Queue Q);
 16 void Enqueue(ElementType X,Queue Q);
 17 ElementType Front(Queue Q);
 18 void Dequeue(Queue Q);
 19 ElementType FrontAndDequeue(Queue Q);
 20 struct QueueRecord{
 21   int Capacity;//隊列包含元素的最大值
 22   int Front;
 23   int Rear;
 24   int Size;//現有隊列的大小
 25   ElementType *Array;    
 26 };  
 27 
 28 int *RandInt4(int total,int i,int j,int order){
 29     int *numberGroup=malloc(total*sizeof(int));//用於返回一個指定大小的數組 
 30     int tempory[j-i+1];//輔助產生隨機數的數組。 
 31     int k;//用於循環遍歷 
 32     int x;//接收產生的隨機變量 
 33     srand(time(NULL));
 34     //初始化輔助數組 
 35     for(k=0;k<=j-i;k++){
 36         tempory[k]=0;
 37     }
 38     for(k=0;k<total;k++){
 39 L:        x=rand()%(j-i+1)+i;//產生從i到j,包括i和j的隨機數
 40         if(tempory[x-i]==0){
 41           tempory[x-i]=1;
 42           //當須要產生的數組是無序的則執行: 
 43           if(order==0){
 44             numberGroup[k]=x;    
 45             }
 46         }else{
 47             goto L;
 48         } 
 49     }
 50     //當須要產生有序的隨機數組時執行: 
 51     int w=0;
 52     if(order!=0){
 53       for(k=0;k<j-i+1;k++){
 54           if(tempory[k]==1){
 55               numberGroup[w++]=k+i;
 56               if(w>=total){
 57                   break;
 58               }
 59           }
 60       }    
 61     }
 62     
 63     return numberGroup; 
 64 }
 65 Queue CreateQueue(int MaxElements){
 66     if(MaxElements<MinQueueSize){
 67         printf("定義的隊列的大小小於5");
 68         MaxElements=MinQueueSize; 
 69     }
 70     Queue Q=malloc(sizeof(struct QueueRecord));
 71     Q->Capacity=MaxElements;
 72     Q->Array=malloc(sizeof(int)*MaxElements);
 73     MakeEmpty(Q);
 74     return Q;
 75 }
 76 void MakeEmpty(Queue Q){
 77     Q->Front=0;//在數組的末尾,下標爲MaxElements-1 
 78     Q->Rear=Q->Capacity-1;//在數組的開頭,下標爲0 
 79     Q->Size=0;//
 80 }
 81 //判斷是否Front和Rear是否挨着,只有挨着隊列纔有可能爲空或者滿,當挨着時也有多是兩個元素。但此時size=2; 
 82 int IsFRClosed(Queue Q){
 83     int size=(Q->Rear-Q->Front+1)%Q->Capacity;
 84     if(size<0){
 85         size+=Q->Capacity;
 86     }
 87     if(size>Q->Capacity){
 88         size-=Q->Capacity;
 89     }
 90     //當size==0時兩種狀況,一種是隊列爲空,一種是隊列滿了。 
 91     return size==0;
 92 }
 93 int IsEmpty(Queue Q){
 94     if(IsFRClosed(Q))//這裏這樣作,只是更加不容易出錯!
 95           return Q->Size==0;
 96     else
 97         return 0;
 98 }
 99 int IsFull(Queue Q){
100     if(IsFRClosed(Q)){  
101           return Q->Size==Q->Capacity;
102     }else
103         return 0;
104 }
105 void Enqueue(int element,Queue Q){
106     if(!IsFull(Q)){
107         Q->Size++;
108         Q->Rear+=1;
109         if(Q->Rear==Q->Capacity){
110             Q->Rear=0;
111         }
112         Q->Array[Q->Rear]=element; 
113     }else{
114         printf("  :沒法將%2d插入隊列,隊列已滿!\n",element);
115     }
116 } 
117 void Dequeue(Queue Q){
118     if(!IsEmpty(Q)){
119         Q->Size--;
120         Q->Front++;
121         if(Q->Front==Q->Capacity    ){
122             Q->Front=0;
123         } 
124     }
125 } 
126 int FrontAndDequeue(Queue Q){
127     int tempFront=Q->Front;
128     //printf("Front=%4d\n",Q->Front);
129     Dequeue(Q);
130     return Q->Array[tempFront]; 
131 }
132 int Front(Queue Q){
133     return Q->Array[Q->Front];
134 }
135 int main(){
136     int *tempGroup=RandInt4(40,0,100,0);
137     int *tempGroup2=RandInt4(30,0,100,0);
138     int i;
139     Queue Q=CreateQueue(50);
140     printf("1.入隊40個元素!\n");
141     for(i=0;i<40;i++){
142       printf("%4d",tempGroup[i]);
143       Enqueue(tempGroup[i],Q);
144       if((i+1)%20==0){
145           printf("\n");
146         }    
147     }
148     printf("2.出隊10個元素!\n");
149     for(i=0;i<10;i++){
150         printf("%4d",Front(Q));
151         Dequeue(Q);
152         if((i+1)%10==0){
153             printf("\n");
154         }
155     }
156     printf("3.再入隊30個元素!\n");
157     for(i=0;i<30;i++){
158       printf("%4d",tempGroup[i]);
159       Enqueue(tempGroup2[i],Q);
160       if((i+1)%20==0){
161           printf("\n");
162         }    
163     }
164     printf("4.顯示此隊列中的全部出隊結果!\n"); 
165     int size=Q->Size; 
166     for(i=0;i<size;i++){
167           printf("%4d",FrontAndDequeue(Q));
168         if((i+1)%20==0){
169             printf("\n");
170           }    
171     }
172     printf("\n5.Front和Rear的位置是:\n");
173     printf("Front=%d,Rear=%d",Q->Front,Q->Rear); 
174 }

 

    3.3隊列的應用:

      有幾種使用隊列給出提升運行效率的算法,咱們將在第九章的圖論算法中討論他們。如今先給出某些應用隊列的例子:

      1)看成業送交給一臺打印機,他們就按照到達的順序被排列起來。所以被送往行式打印機的做業基本是被放到一個隊列中。

      2)實際生活中的每次排隊都應該是一個隊列。

      3)在計算機網絡中,有許多種PC機的網絡設置,其中磁盤是放在一臺叫作文件服務器上的。使用其餘計算機的用戶是按照先到先使用的原則來訪問文件的。所以其數據結構是一個隊列。

  

    3.4排隊論

      處理用機率的方法計算用戶排隊等待時間、等待服務器的隊列可以排多長,以及其餘諸如此類的問題將用到被稱爲排隊論(queueing theory)的整個數學分支。問題的答案依賴於用戶加入隊列的頻率以及一旦用戶獲得服務處理時處理服務所花費的時間。這兩個參數做爲機率分佈函數給出。

 

    3.5隊列的應用實例:

      迷宮問題:迷宮實驗是取自心理學的一個古典實驗。在該實驗中,把一隻老鼠從一個無頂大盒子的門放入,在盒中設置了許多牆,對行進方向造成了多處阻擋。盒子僅有一個出口,在出口處放置一塊奶酪,吸引老鼠在迷宮中尋找道路以到達出口。對同一只老鼠重複進行上述實驗,一直到老鼠從入口到出口,而不走錯一步。老鼠經屢次試驗終於獲得它學習走迷宮的路線。

      設計一個計算機程序對任意設定的迷宮,求出一條從入口到出口的通路,或得出沒有通路的結論。

      1)第一種方法:用棧實現:

      解題思路:從起始結點開始,尋找當前結點的下一個有效的結點(找下一個結點的順序依照「右下左上」),若是下一個結點是可經過的'-',則壓入棧中,並標誌其爲*,表明已經走過,將此結點做爲當前結點再次重複操做。若是下一個結點不能經過,則按照找結點的順序(右下左上)找下一個。若是四個方向的都不行。則將當前結點從棧中彈出。執行上一次壓入棧中的那個結點的找結點過程。直到遍歷全部能到達的結點或者找到出口爲止。

  1 //迷宮問題的棧的解法 
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<time.h>
  5 //在棧中存地圖上區塊的位置信息
  6 #define mapSize (10) 
  7 struct BlockNode{
  8     int row;
  9     int column;
 10     int direction;//用於指示下一個區塊相對於當前區塊的位置,依序右下左上,值爲1234. 
 11     struct BlockNode *Next;
 12 };//用來構成棧的元素結點 
 13 struct PositionNode{
 14   int x;
 15   int y;    
 16 };
 17 struct MazNode{
 18     char mapStatus[mapSize][mapSize];//存迷宮指定位置的狀態 
 19     struct PositionNode start;//起始位置 
 20     struct PositionNode end;//結束位置 
 21 };
 22 typedef struct MazNode *Map; 
 23 typedef struct BlockNode *BlockStack;
 24 typedef struct BlockNode *Block;
 25 typedef struct PositionNode *Position;
 26 void initMap(Map map){
 27   srand(time(NULL));
 28   int i,j;int x,y;
 29   for(i=0;i<10;i++){
 30     for(j=0;j<10;j++){
 31         map->mapStatus[i][j]='#';
 32     }
 33   }//創建圍牆
 34   for(i=0;i<50;i++){
 35       x=rand()%8+1;
 36       y=rand()%8+1;
 37       map->mapStatus[x][y]='-';
 38   }
 39   map->start.x=1;map->start.y=1;
 40   map->end.x=8;map->end.y=8;
 41   map->mapStatus[1][1]='m';//mouse表明入口 
 42   map->mapStatus[8][8]='c';//cat表明出口 
 43 }
 44 void printMap(Map map){
 45   int i,j;
 46   for(i=0;i<10;i++){
 47       for(j=0;j<10;j++){
 48       printf("%c",map->mapStatus[i][j]);       
 49     }
 50     printf("\n");
 51   }    
 52 } 
 53 BlockStack createStack(){
 54     BlockStack L=malloc(sizeof(struct BlockNode));
 55     L->Next=NULL;
 56     return L;
 57 }
 58 Block Top(BlockStack stack){
 59     return stack->Next;
 60 }
 61 void Pop(BlockStack    stack){
 62     stack->Next=stack->Next->Next;
 63 }
 64 void Push(Block    temp,BlockStack    stack){
 65     temp->Next=stack->Next;
 66     stack->Next=temp;
 67 }
 68 int IsEmpty(BlockStack stack){
 69   return stack->Next==NULL;    
 70 }
 71 Position FindNextPosition(Block tempBlock){
 72     Position p=malloc(sizeof(struct PositionNode));
 73     switch(tempBlock->direction)
 74     {
 75         case 1://
 76                p->x=tempBlock->row;
 77                p->y=tempBlock->column+1;
 78                break;
 79         case 2://
 80                 p->x=tempBlock->row+1;
 81                p->y=tempBlock->column;
 82                break;
 83         case 3://
 84                p->x=tempBlock->row;
 85                p->y=tempBlock->column-1;
 86                break;
 87         case 4://
 88                p->x=tempBlock->row-1;
 89                p->y=tempBlock->column;
 90                break; 
 91         default:printf("error!\n");
 92     }
 93     return p;
 94 }
 95 int Pass(Position p,Map map){
 96     //printf("地圖中的是%c\n",map->mapStatus[p->x][p->y]);
 97     if(map->mapStatus[p->x][p->y]=='-'||map->mapStatus[p->x][p->y]=='c')
 98         return 1; 
 99     else
100         return 0;
101 } 
102 void makeFoot(Position p,Map map){
103     map->mapStatus[p->x][p->y]='*';
104 }
105 void printRoute(BlockStack stack){
106   Block temp;
107   while(stack->Next!=NULL){
108       temp=Top(stack);
109     printf("<%d,%d>",temp->row,temp->column);
110     Pop(stack);
111   }
112 }
113 void printStack(BlockStack    stack){
114     BlockStack ptr=stack->Next;
115     while(ptr!=NULL){
116           printf("<%d,%d>",ptr->row,ptr->column);
117           ptr=ptr->Next;    
118     }
119     printf("\n");
120 }
121 BlockStack FindRoute(Map map){
122     BlockStack stack=createStack();
123     Block currentBlock;
124     Block temp=malloc(sizeof(struct BlockNode));
125     temp->row=map->start.x;
126     temp->column=map->start.y;
127     temp->direction=1;
128     Push(temp,stack);
129     //printStack(stack); 
130     //當棧不爲空時,取棧頂元素爲當前元素 
131     while(!IsEmpty(stack)){
132         currentBlock=Top(stack);
133         //噹噹前結點的四個方向的結點沒有視察完時,逐個視察 
134         while(currentBlock->direction<=4){
135           Position nextAvaliable=FindNextPosition(currentBlock);
136           //printf("結點<%d,%d>的下%d個有效的位置是<%d,%d>\n",currentBlock->row,currentBlock->column,currentBlock->direction,nextAvaliable->x,nextAvaliable->y);
137           //printf("%c",map->mapStatus[nextAvaliable->x][nextAvaliable->y]);
138           if(Pass(nextAvaliable,map)){
139               makeFoot(nextAvaliable,map);
140               //printMap(map);printf("\n");
141             temp=malloc(sizeof(struct BlockNode));
142             temp->row=nextAvaliable->x;
143             temp->column=nextAvaliable->y;
144             temp->direction=1;
145             Push(temp,stack);
146             //printStack(stack);
147             currentBlock=temp;
148             //若是當前結點是末尾結點 
149             if(currentBlock->row==map->end.x&&currentBlock->column==map->end.y){
150                 return stack;
151             }            
152           }else{
153             currentBlock->direction++; 
154           }    
155         }
156         Block ord=Top(stack);
157         map->mapStatus[ord->row][ord->column]='@';//將已經訪問過的點而且從棧中彈出的設爲「@」。
158         Pop(stack);
159         //printStack(stack);
160     }
161     return NULL;
162 }
163 
164 int main(){
165     Map map=malloc(sizeof(struct MazNode));     
166     initMap(map);//初始化迷宮地圖 
167     printMap(map);
168     printf("\n");
169     BlockStack routeStack=FindRoute(map);//start爲起始點,end爲終點
170     if(routeStack==NULL){
171         printf("沒有路徑從起始點(%d,%d)通往(%d,%d)",map->start.x,map->start.y,map->end.x,map->end.y);
172     }else{
173         printf("從起始點(%d,%d)通往(%d,%d)的路徑爲:\n",map->start.x,map->start.y,map->end.x,map->end.y);
174         printMap(map);
175         printRoute(routeStack);//倒序輸出
176     } 
177 }//這裏註釋掉的語句都是調試用的。

 

    本題的地圖是隨機生成的,你能夠在initMap裏隨意更改地圖的大小,但相應的printMap函數也要求更改。

    若是把註釋掉的第140行代碼取消掉,你能清晰的看到結點遍歷的過程。

    2)第二種方法:用隊列實現:

    解題思路:隊列的解決方案與棧的解決方案殊途同歸。從入口開始,依序(右下左上)四個方向遍歷,若是下個結點是可經過的,則加入隊列。當前結點的四個方向的結點在同一層。所以,當從隊列的開頭順序查看隊列的結點時,只要是到達了出口,此路徑確定是最短的。由於後面的即便還有到達出口的路徑但層級數確定大於第一個出現的路徑。所以這種方法求出的是最小短路徑。

  1 //用隊列找到最短路徑的問題
  2  
  3 #define MapSize (10+2)
  4 #include<stdio.h>
  5 #include<stdlib.h>
  6 #include<time.h> 
  7 struct PositionNode{
  8   int x;
  9   int y;    
 10 };
 11 struct MapNode{
 12     char mapStatus[MapSize][MapSize];//存迷宮指定位置的狀態 
 13     struct PositionNode start;//起始位置 
 14     struct PositionNode end;//結束位置 
 15 };
 16 struct BoxNode{
 17   int row; 
 18   int column;
 19   int pre;//指向前一個元素的下標    
 20 };//隊列中的元素類型 
 21 struct QueueNode{
 22   struct BoxNode *BoxBlock; 
 23   int Front;
 24   int Rear;    
 25 };
 26 typedef struct PositionNode Position;
 27 typedef struct MapNode *Map;
 28 typedef struct QueueNode *Queue;
 29 void initMap(Map map){
 30   //srand(time(NULL));
 31   int i,j;int x,y;
 32   for(i=0;i<12;i++){
 33     for(j=0;j<12;j++){
 34         map->mapStatus[i][j]='#';
 35     }
 36   }
 37   for(i=0;i<80;i++){
 38     x=rand()%10+1;
 39     y=rand()%10+1;    
 40       map->mapStatus[x][y]='-';
 41   }
 42   map->mapStatus[1][1]='M';
 43   map->mapStatus[10][10]='C';
 44   map->start.x=1;map->start.y=1;
 45   map->end.x=10;map->end.y=10;
 46 }
 47 void printMap(Map map){
 48     int i;int j;
 49     for(i=0;i<12;i++){
 50         for(j=0;j<12;j++){
 51             if(map->mapStatus[i][j]=='#'){
 52                 printf("%c%c",161,246);//白的看成牆                 
 53             }else if(map->mapStatus[i][j]=='-'){
 54                 printf("%c%c",161,245);//黑的看成有效的通道 
 55             }else if(map->mapStatus[i][j]=='*'){
 56                 printf("%c%c",161,242);//圓的表明路徑     
 57             }else{
 58                 printf(" %c",map->mapStatus[i][j]);//其他的表明進出口 
 59             }
 60         }
 61         printf("\n");
 62     }
 63 } 
 64 void initQueue(Queue queue){
 65   queue->Front=-1;
 66   queue->Rear=-1;
 67   queue->BoxBlock=malloc(sizeof(struct BoxNode)*100);
 68 }
 69 Queue FindRoute(Map map){
 70   int Find=0;//表示沒有找到最短路徑
 71   int row,column;//從隊列的開頭開始處理的結點的座標
 72   int direction;//表示當前結點的方向(四個值) 
 73   Queue queue=malloc(sizeof(struct QueueNode));
 74   initQueue(queue);
 75   queue->Rear++;
 76   queue->BoxBlock[queue->Rear].row=map->start.x;
 77   queue->BoxBlock[queue->Rear].column=map->start.y;
 78   queue->BoxBlock[queue->Rear].pre=-1;
 79   while(queue->Front<=queue->Rear&&!Find){
 80     queue->Front++;
 81     row=queue->BoxBlock[queue->Front].row;
 82     column=queue->BoxBlock[queue->Front].column;
 83     //printf("當前處理的結點是:<%d,%d>\n",row,column);
 84     if(row==map->end.x&&column==map->end.y){
 85         Find=1;//表示此結點是出口。路徑已經找到
 86         return queue; 
 87     }
 88     for(direction=1;direction<5;direction++){
 89         switch(direction){
 90             case 1:
 91                    row=queue->BoxBlock[queue->Front].row;
 92                    column=queue->BoxBlock[queue->Front].column+1;
 93                    break;
 94             case 2:
 95                    row=queue->BoxBlock[queue->Front].row+1;
 96                    column=queue->BoxBlock[queue->Front].column;
 97                    break;
 98             case 3:
 99                    row=queue->BoxBlock[queue->Front].row;
100                    column=queue->BoxBlock[queue->Front].column-1;
101                    break;
102             case 4:
103                    row=queue->BoxBlock[queue->Front].row-1;
104                    column=queue->BoxBlock[queue->Front].column;
105                    break;
106                default:printf("error!\n");
107         }
108         if(map->mapStatus[row][column]=='-'||map->mapStatus[row][column]=='C'){
109             queue->Rear++;
110             //printf("結點<%d,%d>加入隊列!\n",row,column);
111             //printMap(map);
112             queue->BoxBlock[queue->Rear].row=row;
113             queue->BoxBlock[queue->Rear].column=column;
114             queue->BoxBlock[queue->Rear].pre=queue->Front;
115                  if(map->mapStatus[row][column]!='C'){
116                 map->mapStatus[row][column]='@';//代表此結點已經訪問過。
117                 }    
118         }
119     }    
120   }
121  return NULL;    
122 }
123 void printRoute(Queue queue,Map map){
124     int k=queue->Front;
125     int row,column;
126     k=queue->BoxBlock[k].pre;
127     while(k>0){
128       row=queue->BoxBlock[k].row;
129       column=queue->BoxBlock[k].column;
130       map->mapStatus[row][column]='*';//從Front開始,將結點的途徑之地的map對應值設爲'*'。 
131       k=queue->BoxBlock[k].pre;//指向Front位置元素的前一個
132     }
133 }
134 int main(){
135   Map map=malloc(sizeof(struct MapNode));
136   initMap(map);
137   printf("原始地圖爲:\n"); 
138   printMap(map);
139   Queue queue=FindRoute(map);
140   if(queue!=NULL){
141         printRoute(queue,map);  
142         printf("最短路徑爲:\n");
143       printMap(map);
144   }else{
145         printf("沒有路徑從起點<%d,%d>通向<%d,%d>,隊列遍歷的結點有:\n",map->start.x,map->start.y,map->end.x,map->end.y);
146         printMap(map);
147   }    
148 }
//這裏註釋掉的語句都是調試用的。

      將第30行代碼取消註釋,將隨機產生地圖。將110行和111行取消註釋,你將看到詳細的結點遍歷過程。

      其實,隊列也能夠求解全部路徑,還能夠用四叉樹求解全部路徑,在此先不作探討。

      後續會專門寫一篇解決迷宮問題的文檔,包括迷宮生成算法,和找出迷宮的全部路徑和最短路徑問題,結合openGL動態繪製結點的遍歷過程。相似下面的連接那種:

http://www.2cto.com/kf/201411/349889.html(結點的動態遍歷)

http://bbs.9ria.com/thread-156150-1-1.html(三種迷宮生成算法)

http://wenku.baidu.com/link?url=AgRCE5ddoGdA-rW1nyyYD2Qhny5xPEjAlH_DkFgIB2wBFvyu0HijO7774gp-eP_bRa2OlrENBlZbE7zaFCjS_Ami2L7JGF8BUE5jXjr0pu3(迷宮問題鏈表實現的詳解)

相關文章
相關標籤/搜索