简体   繁体   中英

Swap items in a doubly linked list

I am studying for my Algorithms exam and I have an exercise where I need to swap two items of a doubly linked list if a condition is true. (Language: C) More specifically, I have a list of this kind:

H <-> |prev|Frequency1|VALUE1|next| <-> |prev|Frequency2|VALUE2|next| <-> ... <-> NULL

The frequency field increases every time I search for the relative value. The list must be ordered according to the frequency (in decreasing order, so at the very top there is the most searched item)

The problem is, I am not very good in exchanging pointers, I tried many times to do it but I have no clue. I guess that the problem I am facing is that I don't know how to use a temp item to keep track of what I am doing without loosing data.

I think that the case I have to consider are:

  • First item of the list
  • Last item of the list
  • Item is in the middle of the list.

My attempt, certainly wrong is:

int Search(int x, list* head) {

    int contapos = 0;
    list* i;
    list* aus;

    for (i=head; i!=NULL; i = i->next, contapos++)
    {

        if (i->key == x)
        {
            i->freq++; // Increase frequency

            aus = i->prev;

            while ((i->freq > aus->freq))
            { // Keep ordered the frequencies

                if (i->next != NULL)
                {
                    i->next->prev = aus;
                }

                if (aus->prev != NULL)
                {
                    aus->prev->next = i;
                }

                aus->next = i->next;
                i->prev = aus->prev;
                aus->prev = i;
                i->next = aus;

            }

            /* Return counter */
            return contapos;

        }

    }

    return -1; // In case the item i am searching is not there
}

Thank you in advance for everything!

Edit: as requested, I am adding the main (and the whole code just to be sure) of the program at the moment

typedef struct _list {
int key;
int freq;
struct _list *next;
struct _list *prev;
} list;

list* head;
list* tail;

void swap(list *lhs, list *rhs) {
list *temp;

temp = lhs->prev;
lhs->prev = rhs->prev;
rhs->prev = temp;

temp = lhs->next;
lhs->next = rhs->next;
rhs->next = temp;
}


void InsertAtTail(int value) {
list *newNode;
newNode = (list*)malloc(sizeof(list));
newNode->key = value;

if(head == NULL)
{
    head = newNode;
}
else
{
    tail->next = newNode;
    newNode->prev = tail;
}

tail = newNode;
tail->next = NULL;
}

int SearchAndIncrement(int x, list** head) {
int contapos = 0;
list* i;

// Let's find the element with the matching key
for (i = *head; i != NULL; i = i->next, contapos++)
    if (i->key == x)
        break;

// If we did not find the node, return -1 to denote failure.
if (i == NULL)
    return -1;

// Increase frequency
i->freq++;

// Move this node forward while the frequency is not in the correct position.
while (i->next && i->prev && (i->freq > i->prev->freq))
    swap(i, i->prev);

// The head might have been moved.
while ((*head)->prev != NULL)
    (*head) = (*head)->prev;

// Return the original position
return contapos;
}


int main () {

int N;
scanf("%d", &N);

head = NULL;
tail = NULL;

int i, value;
for (i=0; i<N; i++) {
    scanf("%d", &value);
    InsertAtTail(value);
}

/* Initializing frequencies */
list* aus;
for (aus=head; aus; aus = aus ->next) {
    aus->freq = 0;
}

int x, pos;
do {
    scanf("%d", &x);
    pos = SearchAndIncrement(x, &head);
    printf("%d ", pos);
    printf("[");
    aus = head;
    while (aus!=NULL) {
        printf("%d ", aus->key);
        aus = aus->next;
    }
    printf("]\n");

} while (pos != -1);

return 0;


}

Let's simplify the problem. The complicated pointer portion is when we are trying to move a node forward in the list. So let's create some functions just for that.

void RemoveNode(list *node) {
    if (node->prev)
        node->prev->next = node->next;
    if (node->next)
        node->next->prev = node->prev;
}

void InsertNodeBetween(list *lhs, list *node, list *rhs) {
    if (lhs) assert(lhs->next == rhs);
    if (rhs) assert(rhs->prev == lhs);

    if (lhs) lhs->next = node;
    if (rhs) rhs->prev = node;

    node->prev = lhs;
    node->next = rhs;
}

Once we've done that, then we can more easily talk about the operation that you want to do.

int SearchAndIncrement(int x, list** head) {
    int contapos = 0;
    list* i;

    // Let's find the element with the matching key
    for (i = *head; i != NULL; i = i->next, contapos++)
        if (i->key == x)
            break;

    // If we did not find the node, return -1 to denote failure.
    if (i == NULL)
        return -1;

    // Increase frequency
    i->freq++;

    // Move this node forward while the frequency is not in the correct position.
    while (i->next && (i->freq > i->next->freq)) {
        list *prev = i->next;
        list *next = i->next->next;
        RemoveNode(i);
        InsertNodeBetween(prev, i, next);
    }

    // The head might have been moved.
    while ((*head)->prev != NULL)
        (*head) = (*head)->prev;

    // Return the original position
    return contapos;
}

Some commentary:

The important thing to note here is that we have the ability to create multiple functions . And we can use those functions to make the amount of the problem that we need to keep in our head at any one time smaller.

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