歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C語言數組實現約瑟夫環問題,以及對其進行時間復雜度分析

C語言數組實現約瑟夫環問題,以及對其進行時間復雜度分析

日期:2017/3/1 9:16:19   编辑:Linux編程

嘗試表達

本人試著去表達約瑟夫環問題:一群人圍成一個圈,作這樣的一個游戲,選定一個人作起點以及數數的方向,這個人先數1,到下一個人數2,直到數到游戲規則約定那個數的人,比如是3,數到3的那個人就離開這個游戲;按這樣的規則,剩下一個人,游戲就結束,這個人就為贏家。(讀者可以試著表達,不認同,直接忽略)

抽象分析

這個人就是一個數據個體,數據結點,數據元素。上面產生的數據結構為:單方向循環的鏈。可以用鏈表實現,也可以用數組來實現。

鏈表到數組的遷移

人(數據元素、

數據結點、數據個體)

結點關系

(結構關系

結點移動)

范型“指針”定義

:能夠定位到下一個結點(變)

“指針“

移到下一個結點

拿到下一個結點的”指針“即可,一般都有作“移動”變量,移動變量變,就相當於移動。

刪除結點

數組

連續的數組元素(基本數據類型,機構體)

數組元素裡面保存有下個結點元素的數組元素下標position。

arrayname固定的,只要給出position,就可以算是定位到數組元素

≈poisiton

[]

move =array[move]

元素內容 = -1

(數組的大小固定)

鏈表

離散的鏈表結點(結構體)

結構體裡面保存有下一個結點的指針 node* next

poiter直接定位到結點,在結合常員變量,就可以拿到數據

=poiter

->

move = move -> next

銷毀

畫圖分析:

代碼實現:

#include<stdio.h>
#include<stdlib.h>

/*Function:遍歷數組實現的約瑟夫環。traverse_joseph_circle_array
 *param:int[] array,int tail
 *return: void
 * 假設是用數組實現的約瑟夫環鏈一定存在。
 * */
void traverse_joseph_circle_array (int array[], int  tail ){
//數組保存的是下個結點的“指針”,只不過這個指針要通過array才能夠拿到結點的元素,因為array是固定的,只要變換指針就能夠變換結點。
    int move= array [tail] ;//從頭開始遍歷
    do{
        printf ("%d ;",move) ;//數組的元素位置(下標號)就代表這個結點,鏈表是通過結點裡面的元素,
        move = array[move];
    }while ( move != array [tail]);
    printf("\n");
}
 /*Function:約瑟夫環問題的數組實現。eliminate_array
 *param:int[]array,int tail,  int step
 *return: void
 * */
void eliminate_array1 (int array[], int tail ,int step ){
    int move = tail ; 
    int save_previous = move ;
    int count = 0 ;
    while(move != array[move]){
        save_previous = move ;
        move = array [move];
        if(++ count == step){ //數數
            array[save_previous] = array[move] ;//重構鏈
        if( tail == move) tail =  save_previous;//銷毀前,判斷要不要更新新約瑟夫環    
        printf("當前要刪除的結點:%d \n",move);//銷毀前告知用戶
        array[move]=  -1 ;//銷毀 
        printf("當前的約瑟夫環為:\n") ;
        traverse_joseph_circle_array (array,tail);
        count = 0 ;
        move = save_previous ;

         }
    }
}
 /*Function:約瑟夫環問題的數組實現。eliminate_array
 *param:int[]array,int tail,  int step
 *return: void
 * */
void eliminate_array2 (int array[], int tail ,int step ){
    int move = tail ; 
    int save_previous = move ;
    int count = 0 ;
    //每執行一此循環,刪除一個結點。
    while (move != array[move]){
        
        save_previous = move ;
        move = array[move];
        


        // 移動到要刪除的結點
        for (count = 0 ; count < step -1 ; count++){
            move = array[move] ;
        }
        //刪除結點,重構約瑟夫環,更新tail
        array[save_previous] = array[move] ;//重構鏈
            if( tail == move) tail =  save_previous;//update tail      
            printf("當前要刪除的結點:%d \n",move);//銷毀前告知用戶
            array[move]=  -1 ;//銷毀 
            printf("當前的約瑟夫環為:\n") ;
            traverse_joseph_circle_array (array,tail);
        
        //移動回消除結點的上一個結點,回到初態,即將進行下一輪的游戲。
        count = 0 ;
            move = save_previous ;

        
    }    

}
int main(){
    //創建有6個結點的約瑟夫環int array[6];
    int array[20];
    int length = sizeof(array)/sizeof(int);
    int ctl ;
    for (ctl = 0 ; ctl < length -1 ;ctl ++){
        array[ctl] = ctl + 1;
    }    
    array [length -1]  = 0 ;
    traverse_joseph_circle_array(array,length-1);
    int tail = length -1;
    //eliminate_array1(array ,tail ,3) ;
    eliminate_array2(array ,tail ,3) ;
    return 0 ;
}

結果:

0 ;1 ;2 ;3 ;4 ;5 ;6 ;7 ;8 ;9 ;10 ;11 ;12 ;13 ;14 ;15 ;16 ;17 ;18 ;19 ;
當前要刪除的結點:2 
當前的約瑟夫環為:
3 ;4 ;5 ;6 ;7 ;8 ;9 ;10 ;11 ;12 ;13 ;14 ;15 ;16 ;17 ;18 ;19 ;
當前要刪除的結點:5 
當前的約瑟夫環為:
6 ;7 ;8 ;9 ;10 ;11 ;12 ;13 ;14 ;15 ;16 ;17 ;18 ;19 ;
當前要刪除的結點:8 
當前的約瑟夫環為:
9 ;10 ;11 ;12 ;13 ;14 ;15 ;16 ;17 ;18 ;19 ;
當前要刪除的結點:11 
當前的約瑟夫環為:
12 ;13 ;14 ;15 ;16 ;17 ;18 ;19 ;
當前要刪除的結點:14 
當前的約瑟夫環為:
15 ;16 ;17 ;18 ;19 ;
當前要刪除的結點:17 
當前的約瑟夫環為:
18 ;19 ;
當前要刪除的結點:18 
當前的約瑟夫環為:
19 ;

時間復雜度分析:

本人推薦使用第二種算法來作,對於時間復雜度,要通過邏輯思考,要刪除(n-1)個結點,循環執行(n-1)次,內循環執行k=step 次,這個k可能很大;還有在外循環,與內循環無關的,必須執行的某些語句,執行次數為c,表達式為:(n-1)(k+c)=nk +nc -k -c ,表達為:n*k - c0 * n - c1 *k ,大O表達為:O(nk)

Copyright © Linux教程網 All Rights Reserved