1

I have to make a function which swaps the neighbor nodes in a linked list with sentinel. Something like this: 1-2-3-4-5 -> 2-1-4-3-5, but I don't know how to do that. Can somebody help me?

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

typedef struct _listelem {
    int a;
    struct _listelem* next;
} listelem;

void reverse_pairs(listelem* a)
{
    listelem* head = NULL;
    listelem* tail = NULL;
    head = a->next;
    tail = a->next;
    while (head->next != NULL)
    {
        head = head->next->next;
        tail = head;
    }
    return head;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335

2 Answers2

2

You did not show how the list with a sentinel node is built.

I suppose that the sentinel node is the first node in the list pointed to by the pointer head.

In this case the function can look the following way.

void reverse_pairs( listelem *head )
{
    if (head)
    {
        for (; head->next && head->next->next; head = head->next->next)
        {
            listelem *tmp = head->next;
            head->next = head->next->next;

            tmp->next = head->next->next;
            head->next->next = tmp;
        }
    }
}

As for your function implementation then it is incorrect at least because a function with the return type void may not have a statement like this

return head;

Also within this while loop

while (head->next != NULL)
{
    head = head->next->next;
    tail = head;
}

you are changing the local variables head and tail. Such changes do not influence on the original list.

If you have a circular list when the data member next of the last node points to the head (sentinel) node then the function can look the following way.

void reverse_pairs( listelem *head )
{
    if (head)
    {
        for ( listelem *current = head; 
              current->next != head && current->next->next != head; 
              current = current->next->next)
        {
            listelem *tmp = current->next;
            current->next = current->next->next;

            tmp->next = current->next->next;
            current->next->next = tmp;
        }
    }
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Yes, without a return or an additional level of indirection in the parameter, swapping the first and second nodes will be disappointing `:)`, – David C. Rankin Nov 18 '20 at 20:21
  • Thank you, your code works, except for lists with odd elements S-->1-->2-->3-->S=>S-->2-->1-->S! – Csaba Bársics Nov 18 '20 at 21:38
  • @CsabaBársics Do you have a circular list? From your question this is unclear. – Vlad from Moscow Nov 18 '20 at 21:53
  • No I don't have circular list, only a single linked list with sentinel nodes like this: S-->1-->2-->3-->S – Csaba Bársics Nov 18 '20 at 22:14
  • @CsabaBársics As I said you have to show how the list is created. – Vlad from Moscow Nov 18 '20 at 22:22
  • I am afraid, but I can't it is a generated list by a tester program, if I could I would show you, but I don't know how it is built but it isn't a circular list :/ – Csaba Bársics Nov 18 '20 at 22:32
  • @CsabaBársics, it would be sufficient to write a demonstration function that generates a list such as the tester presents to your function. The issue here is we are uncertain which of several alternatives you mean by a "linked list with sentinel", and it makes a difference to the implementation of the wanted function. – John Bollinger Nov 19 '20 at 02:32
0

While the answer from @VladFromMoscow shows the proper approach for swapping nodes in the list to accomplish your objective, if you are stuck passing a single pointer, and the function return type is fixed at void, then there is another way to go about it.

Instead of swapping nodes, you simply swap the int member value between nodes. Approaching the problem that way, the address of the first node never changes, so there is no need to pass the address of the list as a parameter.

The approach is simple. Take the current node, swap the integer value between the current and next node and advance past the nodes holding the swapped integers. To do so, you advance from the current node to the next and check if the node that follows next is NULL (marking the end of the list). If it is NULL, you are done. If it is not NULL, advance again and repeat. You can write the function either with a while() loop, e.g.

void reverse_pairs (listelem *head)
{
    while (head && head->next) {
        int tmp = head->a;
        head->a = head->next->a;
        head->next->a = tmp;
        
        head = head->next;
        if (head->next)
            head = head->next;
    }
}

Or, slightly less readable, using a for() loop and a ternary, e.g.

void reverse_pairs (listelem *head)
{
    for (; head && head->next;
            head = head->next->next ? head->next->next : NULL) {
        int tmp = head->a;
        head->a = head->next->a;
        head->next->a = tmp;
    }
}

Example Use/Output

With a normal list where the last pointer is NULL, your output printing the original list, calling reverse_pairs(), and then outputting the modified list would look as follows:

$ ./bin/lls_revpairs
 1 2 3 4 5
 2 1 4 3 5

Complete Test Code

The complete test code is included below. Compiling as normal will use the for() loop above, or adding the define -DUSEWHILE, to your compile string will cause the while() loop form of the function to be used:

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

typedef struct _listelem {
    int a;
    struct _listelem* next;
} listelem;

/** add node at end of list, update tail to end */
listelem *add (listelem **head, int v)
{
    listelem **ppn = head,                      /* pointer to pointer to head */
               *pn = *head,                     /* pointer to head */
             *node = malloc (sizeof *node);     /* allocate new node */
 
    if (!node) {                                /* validate allocation */
        perror ("malloc-node");
        return NULL;
    }
    node->a = v;                                /* initialize members values */
    node->next = NULL;
 
    while (pn) {
        ppn = &pn->next;
        pn = pn->next;
    }
 
    return *ppn = node;    /* add & return new node */
}

#ifdef USEWHILE
/** reverse node pairs in list - while loop */
void reverse_pairs (listelem *head)
{
    while (head && head->next) {
        int tmp = head->a;
        head->a = head->next->a;
        head->next->a = tmp;
        
        head = head->next;
        if (head->next)
            head = head->next;
    }
}
#else
/** reverse node pairs in list - for loop + ternary */
void reverse_pairs (listelem *head)
{
    for (; head && head->next;
            head = head->next->next ? head->next->next : NULL) {
        int tmp = head->a;
        head->a = head->next->a;
        head->next->a = tmp;
    }
}
#endif

/** print all nodes in list */
void prn_list (listelem *l)
{
    if (!l) {
        puts ("list-empty");
        return;
    }
    size_t i = 0;
    for (listelem *n = l; n && i < 10; n = n->next, i++)
        printf (" %d", n->a);
    putchar ('\n');
}

int main (void) {
    
    listelem *list = NULL;
    
    for (int i = 1; i <= 5; i++)
        add (&list, i);
    
    prn_list (list);
    reverse_pairs (list);
    prn_list (list);
}
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85