Why circular list doesn't solve Josephus problem?

86 Views Asked by At

I am working on the program which solves Josephus problem on C. I have to use circular linked lists here. Currently I have this code to create list:

void create_list(int N, struct node* head){
    int i, j, k;
    for(i = 2; i <= N; i++){
        struct node* tmp_node = (struct node*)malloc(sizeof(struct node));
        tmp_node -> number = i;
        tmp_node -> next = NULL;
        tmp_node -> next = head -> next;
        head -> next = tmp_node;
        head = tmp_node;
    }
  }

Now I am working on finding last element to remin after Josephus permutations. I have this:

int find_last(int M, struct node* head){
    int i, j = 1;

    if(head -> next == NULL){
        return head -> number;
    }
    else {
        struct node* current = head;
        while(current -> next != NULL){
            while(current -> next -> number != j){
                current = current -> next;
                j++;
            }
            if (j % M == 0){
                struct node* delete_node;
                delete_node = current -> next;
                current -> next = delete_node -> next;
                free(delete_node);
                j = 1;
            }
        }
        return current -> number;
    }
}

And this is my main:

int main(){
    int M, N, i, j, res;
    struct node* head = (struct node*)malloc(sizeof(struct node));
    head -> number = 1;
    head -> next = NULL;
    read_numbers(&N, &M);
    create_list(N, head);
    res = find_last(M, head);
    printf("%d\n", res);
    
    return 0;
}

The problem occurs in int find_last function. Please, tell me the errors and what I can do to solve the problem, thanks for your time.

EDIT.

I have drawn the algorithm and updated my function but it still doesn't work. Here it is:

int find_last(int M, int N, struct node* head){
    int i = 0, j = 1;

    if(head -> next == NULL){
        return head -> number;
    }
    else {
        struct node* current = head;
        while(i != N){
            while(j % M != 0){
                current = current -> next;
                j++;
            }
            struct node* delete;
            delete = current -> next;
            delete -> next = current -> next;
            free(delete);
            i++;
        }
        return current -> number;
    }
}
1

There are 1 best solutions below

3
On BEST ANSWER

create_list() does NOT create a circular LL. You'll have to examine the code to see your own mistake there. The shortest explanation would take longer to relate than merely fixing the code.

Shorter (working!) code to study:

typedef struct n { // typedef reduces verbiage
    int no; // simple, short and sweet name for variables
    struct n *next;
} node;

node *create( int N ) { // simple function name
    node *pHead = NULL, *pTail = NULL; // track head & tail of LL

    for( int i = 1; i <= N; i++ ) { // make N nodes
        node *pn = malloc( sizeof *pn ); // no casting, and sizeof tied to variable, not type
        // Omitting verification for brevity
        pn->no = i; // assign the value

        if( !pTail )
            pHead = pTail = pn; // first node
        else
            pTail = pTail->next = pn; // linking onto end
    }
    return pTail->next = pHead; // May the circle be unbroken!!
}

int killOff( int M, node *pn ) { // NB: function name tells all

    while( pn->next != pn ) { // until only "self" remains
        for( int i = M; --i; ) pn = pn->next; // skip M nodes around circle
        node *del = pn->next;
        pn->next = del->next; // dead man walking in exile now
        free( del ); // bye bye
    }
    return pn->no; // survivors ID
}

int main( void ) {
    int M = 3, N = 17; // constants

    node *head = create( N ); // simple, right?

    printf( "Survivor: %d\n", killOff( M, head ) ); // simpler, too!

    free( head ); // kill off the last of them

    return 0; // and good night
}

You can get yourself tied up in knots with verbiage and without planning.

Caveat: M down count may be off-by-one. Change --i to i-- to suit your interpretation of how far to travel around the shrinking ring of nodes.

EDIT
After closer examination, I believe the following is a better version. (No changes to create() shown above.)

int killOff( int M, node *pn ) {
    // the previous "victim" is #0 at the start of each iteration
    // So, the first iteration begins with 1; subsequent iterations with 0
    for( int i = 1; pn->next != pn; i = 0 ) {
        while( ++i < M ) pn = pn->next;
        node *del = pn->next;
        pn->next = pn->next->next;
        free( del );
    }
    int survivorID = pn->no;
    free( pn ); // Last "survivor" is free'd here, remembered only by "name."
    return survivorID;
}

int main( void ) {
    printf( "Survivor: %d\n", killOff( 3, create( 17 ) ) );

    return 0;
}