介紹隊列的相關知識: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&¤tBlock->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(迷宮問題鏈表實現的詳解)