Search code examples
cswapsingly-linked-list

C - Swap first and last element in singly linked list


What i'm trying to do, is swap the first and last elements of a singly linked list. So far i have the following code, where i create a list and add some numbers to it. My problem is at the swapElements1 function.

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

struct node
{
    int number;
    struct node *next;
};

void addNodeSingle(struct node **head, int num, int thesi) //Function to insert new node at the beginning or the end of the list, depending on the value of "thesi"
{
    if (*head == NULL)
    {
        struct node *current;
        current = (struct node*) malloc (1*sizeof(struct node));
        current -> number = num;
        current -> next = NULL;
        *head = current;
    }

    else
    {
        if (thesi == 0)
        {
            struct node *current;
            current = (struct node*) malloc (1*sizeof(struct node));
            current -> number = num;
            current -> next = *head;
            *head = current;
        }

        else
        {
            struct node *current, *temp;
            current = (struct node*) malloc (1*sizeof(struct node));
            current -> number = num;
            temp = *head;
            while (temp -> next != NULL)
                temp = temp -> next;

            temp -> next = current;
            current -> next = NULL;
        }
    }
}

void displayList(struct node **head) //Function to display the list
{
    struct node *current;
    if(*head == NULL)
        printf("I lista einai adeia!\n");

    else
    {
    current= *head ;
        while(current != NULL)
        {
            printf("%d ",current -> number);
            current = current -> next;
        }
    }
}

void swapElements1(struct node **head) //(not working)Function to swap first and last element of the list
{
    struct node *current, *temp;
    current = temp = *head;

    while(current != NULL)
    {
        temp = current;
        current = current -> next;
    }

    *head = (*head)->next;
    *head = temp;
    current = NULL;
}

int main()
{
    struct node *head;
    head = NULL;

    addNodeSingle(&head,5,1);
    addNodeSingle(&head,6,1);
    addNodeSingle(&head,2,0);
    addNodeSingle(&head,7,0);
    addNodeSingle(&head,8,0);

    printf("List is: ");
    displayList(&head);
    swapElements1(&head);
    printf("\nNew list is: ");
    displayList(&head);
}

The output i get is:

List is: 8 7 2 5 6

New list is: 6

What i need is:

List is: 8 7 2 5 6

New list is: 6 7 2 5 8

Here's a demo


Solution

  • This is clearly wrong:

    *head = (*head)->next;
    *head = temp;
    

    That just overwrites the previous value with the value of temp. The first statement may as well not even be there.

    You fundamentally need two swaps (technically one plus an assignment and termination)

    • The pointers pointing to the two nodes
    • The two nodes next pointers

    The latter of these isn't technically needed, but a direct assignment is needed, and the new tail needs to have it's next set to null to terminate the new list.

    A full example is shown below, liberally commented to hopefully give expose the algorithm of what is going on.

    #include <stdio.h>
    #include <stdlib.h>
    
    struct node
    {
        int data;
        struct node *next;
    };
    
    void swapFirstAndLast(struct node **head)
    {
        // don't bother unless we have a list of at least two nodes
        if (!*head || !(*head)->next)
            return;
    
        // start with the head's next pointer (the second node in the list)
        struct node **pp = &(*head)->next;
    
        // walk the pointer-to-pointer down the list, each time grasping
        //  the next node's "next" pointer address until we reach a node
        //  whose 'next' is NULL. When that happens, `pp` will hold the
        //  address of the pointer pointing to the last node in the list
        while (*pp && (*pp)->next)
            pp = &(*pp)->next;
    
        // swap the pointer held in *head with *pp
        struct node *tmp = *head;
        *head = *pp;
        *pp = tmp;
    
        // save new head's next pointer to be the old head's next
        (*head)->next = (*pp)->next;
    
        // and finally, terminate the list.
        (*pp)->next = NULL;
    }
    
    void print_list(const struct node *head)
    {
        while (head)
        {
            printf("%d ", head->data);
            head = head->next;
        }
        fputc('\n', stdout);
    }
    
    int main()
    {
        struct node *head = NULL, **pp = &head;
        for (int i=1; i<=5; ++i)
        {
            *pp = malloc(sizeof **pp);
            (*pp)->data = i;
            pp = &(*pp)->next;
        }
        *pp = NULL;
    
        print_list(head);
    
        swapFirstAndLast(&head);
    
        print_list(head);
    }
    

    Output

    1 2 3 4 5 
    5 2 3 4 1 
    

    I've left the list cleanup for you (no doubt you have such an algorithm already coded). The crux of this is how to use pointers to pointers to manipulate the linked list's pointers; not just a bunch of temp pointers. I strongly encourage you to single-step through the exchange function in a debugger, watching what is happening with each step along the way.