1. 程式人生 > 其它 >迴圈列表實現約瑟夫環

迴圈列表實現約瑟夫環

技術標籤:佇列資料結構

迴圈列表實現約瑟夫環

首先我們先上圖幫助理解:(環狀順序佇列)
環狀順序佇列示意圖

top為隊首指標
rear為隊尾指標

  1. 我們需要注意,順序佇列在判斷陣列中資料是否存滿時,會出現下面情況:
  • 當佇列裡面啥也沒有的時候,佇列的頭指標等於佇列的尾指標(top==rear);
  • 而佇列裡面沒有多餘空間儲存資料的時候,佇列的頭指標也等於佇列的尾指標(top==rear);
  1. 由上我們發現:
  • 順序佇列的儲存狀態不同,但是判斷條件相同(top==rear)。
  1. 我們為了區分二者,最簡單的解決辦法是:犧牲掉陣列中的一個儲存空間

  2. 判斷陣列滿員的條件是:尾指標的下一個位置和頭指標相遇,就說明陣列滿了(top==(rear+1)

    )

  3. 迴圈佇列的操作(i. size為順序佇列申請的空間大小 ii.Q[ ]為資料集合)

  • 入隊(移動尾指標rear
    • rear=(rear+1)%size
    • Q[rear]=入隊元素
    • ❗注意:隊滿時不可入隊top=(rear+1)%size
  • 出隊(移動隊首指標top
    • top=(top+1)%size
    • Q[top]=出隊元素
    • ❗注意:隊空不可出隊top==rear
  1. 經上分析,我們可以發現佇列為空時跳出迴圈
    實現:
#include<stdio.h>
#include<stdlib.h>

void JosephusRing(int *Q,int n,int s){
	//為了不影響主方法中所建立的佇列,所以令宣告兩個指向元素並初始化
int top=0,rear=n; int i; while(top-rear){ for(i=0;i<s-1;i++){ //(n+1)--因為填充數值是從 1 開始,所以指向元素移動時,隊尾指向元素的下一個指向為隊首元素的指向,即實際儲存空間大小為 n+1 top=(top+1)%(n+1); rear=(rear+1)%(n+1); Q[rear]=Q[top]; } top=(top+1)%(n+1); printf
("%3d",Q[top]); } } int main(void){ int *Q; int n,s; //輸入儲存個數 printf("please input a num:\n"); scanf("%d",&n); //輸入出隊元素(第幾個) printf("please input s:\n"); scanf("%d",&s); //申請儲存空間 Q=(int *)malloc((n+1)*sizeof(int)); //為了方便我們填充數值為1到n for(int i=1;i<n+1;i++) Q[i]=i; //呼叫方法 JosephusRing(Q,n,s); }

輸出結果展示:
執行結果

  1. 由於上述程式碼實現的時間複雜度為O(n2)
    為了降低時間複雜度,我們可以引入一個計數器cnt
//降低時間複雜度
#include<stdio.h>
#include<stdlib.h>

void JosephusRing(int *Q,int n,int s){
    int top=0,rear=n;
    int cnt=1;
    while(top-rear){
        if(cnt-s){
            top=(top+1)%(n+1);
            rear=(rear+1)%(n+1);
            Q[rear]=Q[top];
            cnt++;
        }else{
        	top=(top+1)%(n+1);
        	printf("%3d",Q[top]);
        	cnt=1;
        }
    }
}

int main(void){
    int *Q;
    int n,s;
    printf("please input a num:\n");
    scanf("%d",&n);
    printf("please input s:\n");
    scanf("%d",&s);
    Q=(int *)malloc((n+1)*sizeof(int));
    for(int i=1;i<n+1;i++)	Q[i]=i;
    JosephusRing(Q,n,s);
}

執行結果同上!