简体   繁体   中英

Swapping nodes in double linked list

I'm trying to implement a function that swap two nodes of my double linked list, in order to sort the content of the current directory. But my function seems to 'delete' some elements of my list, here is the code :

void node_swap(struct s_node *left, struct s_node *right)
{
  struct s_node *tmp;

  tmp = left->prev;
  if (tmp)
   {
      tmp->next = right;
      right->prev = tmp;
   }
  else
      right->prev = NULL;

  left->prev = right;
  left->next = right->next;
  right->next = left;
  right->next->prev = left->prev;
}

I can't see what's wrong in this ?

Say this is your initial structure TMP -> L -> R -> X You are not updating the X->prev correctly. In your last line right->next->prev = left->prev; right->next is left. So you are updating the prev of left which is wrong. Instead you should do

if(left->next != null)
   left->next(which is X)->prev = left

So, I think this will work

void node_swap(struct s_node *left, struct s_node *right)
{
  struct s_node *tmp;

  tmp = left->prev;
  if (tmp)
      tmp->next = right;
  right->prev = tmp;

  left->prev = right;
  left->next = right->next;
  right->next = left;
  if(left->next != null)
     left->next(which is X)->prev = left
}

From the code posted in your question, I am deducing that your function is assuming that you are swapping adjacent nodes.

Try the following:

if ( left->prev )
    left->prev->next = right;

if ( right->next )
    right->next->prev = left;

left->next  = right->next;
right->prev = left->prev;

right->next = left;
left->prev = right;

EDIT: Following your comment in the original question, it is much faster to do the following:

char* tmpName = right->name;
right->name = left->name;
left->name = tmpName;

If you write down what you want to do, you can realize a really simple and straightforward solution.

[[working code is at the end of the answer]]

For example, if you have two nodes you want to swap (say A and B) , there are two possibilites according to the position of the nodes. They could be adjacent or not.

Adjacent case

In the adjacent case, you can write:

[X] - [A] - [B] - [Y]

A->prev = X;
A->next = B;
B->prev = A;
B->next = Y;

If you swap A with B, you will end up this:

[X] - [B] - [A] - [Y]

A->prev = B;
A->next = Y;
B->prev = X;
B->next = A;

This is what you want to get. You have to rearrange the pointers to swap the two nodes A and B.

If you use a matrix form the rule will be more intuitive:

     A B               A B 
prev X A    =>    prev B X
next B Y          next Y A

Or just write the matrices alone:

X A   --\   B X
B Y   --/   Y A

Notice, that the swapping matrix rotates 90 degrees clockwise. If you index the elements in the matrix, you can make up an assotiation table:

0 1  --\  2 0
2 3  --/  3 1

So, if you store the pointers in an array, you can easily rearrange them:

0,1,2,3 -> 2,0,3,1

Not adjacent case

You can make up a similar rule for the not adjacent case as well:

[W] - [A] - [X] - ... - [Y] - [B] - [Z]

A->prev = W;
A->next = X;
B->prev = Y;
B->next = Z;

Swap A with B:

[W] - [B] - [X] - ... - [Y] - [A] - [Z]

A->prev = Y;
A->next = Z;
B->prev = W;
B->next = X;

     A B               A B 
prev W Y    =>    prev Y W
next X Z          next Z X

W Y   --\   Y W
X Z   --/   Z X

0 1  --\  1 0
2 3  --/  3 2

0,1,2,3 -> 1,0,3,2

Pointers towards the nodes

Because we are dealing with linked lists, it is not enough to change the pointers in the particular nodes. We have to update the pointers that points to our nodes that we want to swap. This pointers are located in the neighbourhood of the swapable objects.

Notice, that the pointers that are located in the nodes that our pointers points to are always pointing to ourselves.

A->prev->next = A
A->next->prev = A

So after you update the pointers according to the association rule, you only have to point the outer pointers to the given node, and you are done! Just make sure, that the neighbour exists of course.

You need to also check if node A is linked before node B. If not, you need to swap the two parameters. Thanks kralyk for the heads up.

This is enough information to write the necessary functions that do the swapping.

Swapping function and its helper functions

int areTheyNeighbours(Node A,Node B) {
    return ( A->next == B && B->prev == A ) || ( A->prev == B && B->next == A );
}

void refreshOuterPointers(Node A) {
    if (A->prev != NULL)
        A->prev->next = A;

    if (A->next != NULL)
        A->next->prev = A;
}

void swap(Node A,Node B) {
    Node swapperVector[4];
    Node temp;

    if (A == B) return;

    if (B->next == A) {
        temp = A;
        A = B;
        B = temp;
    }

    swapperVector[0] = A->prev;
    swapperVector[1] = B->prev;
    swapperVector[2] = A->next;
    swapperVector[3] = B->next;

    if (areTheyNeighbours(A,B)) {
        A->prev = swapperVector[2];
        B->prev = swapperVector[0];
        A->next = swapperVector[3];
        B->next = swapperVector[1];
    } else {
        A->prev = swapperVector[1];
        B->prev = swapperVector[0];
        A->next = swapperVector[3];
        B->next = swapperVector[2];
    }

    refreshOuterPointers(A);
    refreshOuterPointers(B);
}

Working program for presentation

The optput of the following program:

Initial state:   [1]-[2]-[3]-[4]
--------------------------------
[1] <-> [2]:     [2]-[1]-[3]-[4]
[1] <-> [2]:     [1]-[2]-[3]-[4]
[2] <-> [1]:     [2]-[1]-[3]-[4]
[2] <-> [1]:     [1]-[2]-[3]-[4]
--------------------------------
[1] <-> [3]:     [3]-[2]-[1]-[4]
[1] <-> [3]:     [1]-[2]-[3]-[4]
[3] <-> [1]:     [3]-[2]-[1]-[4]
[3] <-> [1]:     [1]-[2]-[3]-[4]
--------------------------------
[1] <-> [4]:     [4]-[2]-[3]-[1]
[1] <-> [4]:     [1]-[2]-[3]-[4]
[4] <-> [1]:     [4]-[2]-[3]-[1]
[4] <-> [1]:     [1]-[2]-[3]-[4]
--------------------------------
[2] <-> [3]:     [1]-[3]-[2]-[4]
[2] <-> [3]:     [1]-[2]-[3]-[4]
[3] <-> [2]:     [1]-[3]-[2]-[4]
[3] <-> [2]:     [1]-[2]-[3]-[4]
--------------------------------
[2] <-> [4]:     [1]-[4]-[3]-[2]
[2] <-> [4]:     [1]-[2]-[3]-[4]
[4] <-> [2]:     [1]-[4]-[3]-[2]
[4] <-> [2]:     [1]-[2]-[3]-[4]
--------------------------------
[3] <-> [4]:     [1]-[2]-[4]-[3]
[3] <-> [4]:     [1]-[2]-[3]-[4]
[4] <-> [3]:     [1]-[2]-[4]-[3]
[4] <-> [3]:     [1]-[2]-[3]-[4]

You can run the code in a second, by following this link: http://codepad.org/UHcmmag1

Updated link with the corrected swapping function: http://codepad.org/LbRYjvPr

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

typedef struct node_v {
    int id;
    struct node_v* prev;
    struct node_v* next;
} Node_v;

typedef Node_v* Node;

void print(Node node) {
    while (node->prev != NULL)
        node = node->prev;

    printf("   [%d]",node->id);

    while (node->next != NULL) {
        node = node->next;
        printf("-[%d]",node->id);
    }

    printf("\n");
}

void connect(Node first,Node second) {
    first->next = second;
    second->prev = first;
}

Node createNode(int id) {
    Node node = (Node)malloc(sizeof(Node_v));
    node->id = id;
    node->prev = NULL;
    node->next = NULL;
    return node;
}

int areTheyNeighbours(Node A,Node B) {
    return ( A->next == B && B->prev == A ) || ( A->prev == B && B->next == A );
}

void refreshOuterPointers(Node A) {
    if (A->prev != NULL)
        A->prev->next = A;

    if (A->next != NULL)
        A->next->prev = A;
}

void swap(Node A,Node B) {
    Node swapperVector[4];
    Node temp;

    if (A == B) return;

    if (B->next == A) {
        temp = A;
        A = B;
        B = temp;
    }

    swapperVector[0] = A->prev;
    swapperVector[1] = B->prev;
    swapperVector[2] = A->next;
    swapperVector[3] = B->next;

    if (areTheyNeighbours(A,B)) {
        A->prev = swapperVector[2];
        B->prev = swapperVector[0];
        A->next = swapperVector[3];
        B->next = swapperVector[1];
    } else {
        A->prev = swapperVector[1];
        B->prev = swapperVector[0];
        A->next = swapperVector[3];
        B->next = swapperVector[2];
    }

    refreshOuterPointers(A);
    refreshOuterPointers(B);
}

int main() {
    Node n1 = createNode(1);
    Node n2 = createNode(2);
    Node n3 = createNode(3);
    Node n4 = createNode(4);

    connect(n1,n2);
    connect(n2,n3);
    connect(n3,n4);

    printf("\nInitial state:");
    print(n2);

    printf("--------------------------------\n");

    printf("[1] <-> [2]:  ");
    swap(n1, n2);
    print(n1);

    printf("[1] <-> [2]:  ");
    swap(n1, n2);
    print(n1);

    printf("[2] <-> [1]:  ");
    swap(n2, n1);
    print(n1);

    printf("[2] <-> [1]:  ");
    swap(n2, n1);
    print(n1);

    printf("--------------------------------\n");

    printf("[1] <-> [3]:  ");
    swap(n1, n3);
    print(n2);

    printf("[1] <-> [3]:  ");
    swap(n1, n3);
    print(n2);

    printf("[3] <-> [1]:  ");
    swap(n3, n1);
    print(n2);

    printf("[3] <-> [1]:  ");
    swap(n3, n1);
    print(n2);

    printf("--------------------------------\n");

    printf("[1] <-> [4]:  ");
    swap(n1, n4);
    print(n3);

    printf("[1] <-> [4]:  ");
    swap(n1, n4);
    print(n3);

    printf("[4] <-> [1]:  ");
    swap(n4, n1);
    print(n3);

    printf("[4] <-> [1]:  ");
    swap(n4, n1);
    print(n3);

    printf("--------------------------------\n");

    printf("[2] <-> [3]:  ");
    swap(n2, n3);
    print(n3);

    printf("[2] <-> [3]:  ");
    swap(n2, n3);
    print(n3);

    printf("[3] <-> [2]:  ");
    swap(n3, n2);
    print(n3);

    printf("[3] <-> [2]:  ");
    swap(n3, n2);
    print(n3);

    printf("--------------------------------\n");

    printf("[2] <-> [4]:  ");
    swap(n2, n4);
    print(n3);

    printf("[2] <-> [4]:  ");
    swap(n2, n4);
    print(n3);

    printf("[4] <-> [2]:  ");
    swap(n4, n2);
    print(n3);

    printf("[4] <-> [2]:  ");
    swap(n4, n2);
    print(n3);

    printf("--------------------------------\n");

    printf("[3] <-> [4]:  ");
    swap(n3, n4);
    print(n4);

    printf("[3] <-> [4]:  ");
    swap(n3, n4);
    print(n4);

    printf("[4] <-> [3]:  ");
    swap(n4, n3);
    print(n4);

    printf("[4] <-> [3]:  ");
    swap(n4, n3);
    print(n4);

    printf("--------------------------------\n");

    return 0;
}

Very short code that works very efficiently, spent 2 hours on this:

You need to swap both nodes...

But also to make sure that you preserve the links that exist between the 2 swapped nodes and the third and last one, in both directions.

static inline void  swap_list(t_lst **lst)
{
    t_lst   *tmp;

    if ((*lst)->next)   // you need to make sure you have at least 2 items in your list
    {
        tmp = *lst;                 // let's store 1st node's address, that will become the second one after the swap
        *lst = (*lst)->next;        // Reversely our 2nd one will become the 1st one after the swap. It also allows us to set the beginning of our list.
/*
** Now you need to work on the 6 links that exist : between the last elem (that may be the 2nd one)
** and the 1st one you have 2 links (next and prev), same between the 1st one
** and the 2nd one (2 links again) and finally 2 links between the 2nd one
** and the 3d one (that may be the first node)
*/
        tmp->next = (*lst)->next;   // tmp will have second position and needs to point to the third elem. Since *lst is now (*lst)->next, here we refer to the 3rd elem.
        tmp->next->prev = tmp;      // we have then to tell this third elem where stands the second one with this line.
        (*lst)->prev = tmp->prev;   // before destroying the link to last node that tmp contains, we assign it to the future 1st elem of our list
        tmp->prev = *lst;           // now we can safely tell the second node its link to the first.
        (*lst)->next = tmp;         // and reversely tells where is the second elem after the first.
        (*lst)->prev->next = *lst;  // finally we tell the last node where it the first one.
    }
}

I hope it can help.

ps : in case you wonder:

typedef struct      s_lst
{
    void            *data; // or a more specific type if you wish
    struct s_lst    *prev;
    struct s_lst    *next;
}                   t_lst;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM