1. 程式人生 > >佇列基礎及其約瑟夫問題應用

佇列基礎及其約瑟夫問題應用

佇列是一種特殊的線性表,是運算受到限制的一種線性表,只允許在表的一端進行插入,而在另一端進行刪除元素的線性表。隊尾(rear)是允許插入的一端。隊頭(front)是允許刪除的一端。空佇列是不含元素的空表。根據這樣的操作。佇列特點是先進先出~

基礎操作程式碼示例:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 5
#define TRUE 1
#define OK 1
#define FALSE 0
#define
OVERFLOW 0 typedef int Status; typedef int QElemType; using namespace std; typedef struct{ QElemType *base; int front; int rear; }SqQueue; Status InitQueue(SqQueue *Q) {//構建一個佇列 Q->base =(QElemType*)malloc(MAX*sizeof(QElemType)); if(!Q->base) exit(OVERFLOW); Q->front=Q->rear=0
; return OK; } Status DestroyQueue(SqQueue *Q) { if(Q->base) free(Q->base); Q->base=NULL; Q->front=Q->rear=0; return OK; } Status ClearQueue(SqQueue *Q) { Q->front=Q->rear=0; return OK; } Status QueueEmpty(SqQueue Q) { if(Q.front==Q.rear)
return TRUE; else return FALSE; } int QueueLenth(SqQueue Q) { return (Q.rear- Q.front+MAX)%MAX; } Status GetHead(SqQueue Q,QElemType *e) {//取頭頂元素 if(Q.front==Q.rear) return FALSE; *e=Q.base[Q.front]; return OK; } Status EnQueue(SqQueue *Q,QElemType e) {//插入元素 if((Q->rear+1)%MAX==Q->front)//滿員 { cout<<"隊滿"<<endl; return FALSE; } Q->base[Q->rear]=e; Q->rear = (Q->rear+1)%MAX; return OK; } Status DeQueue(SqQueue *Q,QElemType *e) {//丟擲元素 if(Q->front==Q->rear) return FALSE; *e = Q->base[Q->front]; Q->front = (Q->front+1)%MAX; return OK; }
約瑟夫問題是個有名的問題:N個人圍成一圈,從第一個開始報數,第M個將被殺掉,最後剩下一個,其餘人都將被殺掉。例如N=6,M=5,被殺掉的順序是:5,4,6,2,3,1。 分析: (1)由於對於每個人只有死和活兩種狀態,因此可以用布朗型陣列標記每個人的狀態,可用true表示死,false表示活。 (2)開始時每個人都是活的,所以陣列初值全部賦為false。 (3)模擬殺人過程,直到所有人都被殺死為止。 注:迴圈入隊時尾指標向前追趕頭指標;出隊時頭指標向前追趕尾指標,造成隊空和隊滿時頭尾指標均相等。因此,無法通過條件front==rear來判別佇列是"空"還是"滿"。可以通過取模來判斷: 完整程式碼:
#include <iostream>
using namespace std;

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int ElemType;
typedef struct
{
    ElemType *base;
    int front;
    int rear;
    int MAXSIZE;
}SqQueue;
 
Status InitQueue(SqQueue& Q,int n)
{
    Q.base = new ElemType[100];
    if(!Q.base)
    {
        cout << "建立佇列失敗!";
        return ERROR;
    }
    Q.front=Q.rear=0;
    Q.MAXSIZE = n+1;//MAXSIZE是總人數+1,是為了留出一個空位置來放置rear
    return OK;
}
 
void QueueTraverse(SqQueue Q)
{
    int i;
    i=Q.front;
    while(i!=Q.rear)
    {
        cout<<Q.base[i]<<"  ";
        i=(i+1)%Q.MAXSIZE;
    }
    cout<<endl;
}
 
 
Status EnQueue(SqQueue& Q,ElemType e)
{
    if((Q.rear+1)%Q.MAXSIZE==Q.front)
    {
        cout << "佇列已滿!";
        return ERROR;
    }
    Q.base[Q.rear] = e;
    Q.rear = (Q.rear+1)%Q.MAXSIZE;
    return OK;
}
 
Status DeQueue(SqQueue& Q,ElemType& e)
{
    if(Q.front==Q.rear)
    {
        cout << "佇列為空!";
        return ERROR;
    }
    e = Q.base[Q.front];
    Q.base[Q.front] = 0;//0代表此位置沒人: 
    Q.front = (Q.front+1)%(Q.MAXSIZE-1);//因為此時的MAXSIZE比總的人數大1,前面rear+1了;
    return OK;
}
int main()
{
    int n,m,i=1;
    SqQueue Q;
    ElemType e;
    cout << "請輸入n個人(n<=100):";
    cin >> n;
    if(n>100 || n<1)
    {
        cout << "輸入人數錯誤!";
        return 0;
    }
    InitQueue(Q,n);
    while(i<=n)//入隊操作
    {
        EnQueue(Q,i);
        i++;
    }
    cout << "\n此時的序列順序為:";
    QueueTraverse(Q);
    cout << "\n請輸入第m個人出隊(1<=m<=n):";
    cin >> m;
    if(m>n || m<1)
    {
        cout << "m輸入錯誤!";
        return 0;
    }
    cout << endl;
    int Count = n;//用來記錄剩下的人數
    while(Count != 1)
    {
        i = 1;//i用來控制是第幾個人報數
        while(i != m)//當i的值不等於m的值時
        {
            Q.front = (Q.front+1)%(Q.MAXSIZE-1);//因為此時的MAXSIZE比總的人數大1,所以需要減去1,前面rear+1了;
            if(Q.base[Q.front] != 0)//當此時不為0的話,i++用來控制第幾個人,0代表此位置沒人: 
            {
                i++;
            }
        }
        DeQueue(Q,e);
        while(Q.base[Q.front] == 0)//當此時為0的時候,迴圈找到下一個不為0的位置
        {
            Q.front = (Q.front+1)%(Q.MAXSIZE-1);
        }
        cout << "序號:" << e << "出局!\n";
        Count--;
    }
    DeQueue(Q,e);
    cout << "最後一個是:" << e << endl;
    return 0;
}