Reputation: 301
Function swapNode
swaps 2 nodes in list. The function create node* temp
to store temporary data then swaps the data of node* A
and node* B
. I can not understand why it does not work. Below here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
struct node;
struct list;
typedef struct node node;
typedef struct list list;
struct node
{
int point;
char name[30];
node *next;
node *prev;
};
struct list
{
node *head;
node *tail;
int count;
};
node *allocateNewNode(int point, char name[30], node *prev, node *next);
list *createList();
bool insertHead(list *listNode, int point, char name[30]);
bool compareName(char a[30], char b[30]);
bool swapNode(list *listNode, char nameA[30], char nameB[30]);
int main()
{
list *listNode = createList();
insertHead(listNode, 10, "abc def");
insertHead(listNode, 9, "qwe rty");
insertHead(listNode, 8, "ui op");
insertHead(listNode, 30, "fgh jkl");
insertHead(listNode, 1234, "akaka");
swapNode(listNode, "ui op", "abc def");
node *temp = listNode->head;
while (temp != NULL)
{
printf("%-20s%d\n", temp->name, temp->point);
temp = temp->next;
}
free(temp);
printf("\n%d", listNode->count);
return 0;
}
node *allocateNewNode(int point, char name[30], node *prev, node *next)
{
node *newNode = (node *)malloc(sizeof(node));
newNode->point = point;
strcpy(newNode->name, name);
newNode->next = next;
newNode->prev = prev;
return newNode;
}
list *createList()
{
list *listNode = (list *)malloc(sizeof(list));
listNode->count = 0;
listNode->head = NULL;
listNode->tail = NULL;
return listNode;
}
bool insertHead(list *listNode, int point, char name[30])
{
node *newNode = allocateNewNode(point, name, NULL, listNode->head);
if (listNode->head)
listNode->head->prev = newNode;
listNode->head = newNode;
if (listNode->tail == NULL)
listNode->tail = newNode;
++listNode->count;
return true;
}
bool compareName(char a[30], char b[30])
{
for (int i = 0; i < 31; i++)
{
if (a[i] != b[i])
return false;
if (a[i] == '\0')
break;
}
return true;
}
bool swapNode(list *listNode, char nameA[30], char nameB[30])
{
node *A = NULL, *B = NULL;
node *temp = listNode->head;
for (int i = 0; i < listNode->count - 1; i++)
{
if (compareName(temp->name, nameA))
A = temp;
else if (compareName(temp->name, nameB))
B = temp;
temp = temp->next;
if (A || B)
break;
}
if (!A || !B)
return false;
else if (A == B)
return false;
*temp = *A;
*A = *B;
*B = *temp;
if (A->prev)
A->prev->next = A;
if (A->next)
A->next->prev = A;
if (A->prev)
A->prev->next = A;
if (A->next)
A->next->prev = A;
free(temp);
return true;
}
tks for your help
Upvotes: 0
Views: 63
Reputation: 17403
In swapNode
, A
and B
are initially NULL
. The loop that searches for the two matching nodes terminates early when either node is found:
if (A || B)
break;
At most one of A
and B
will be non-NULL when the loop terminates so at least one of A
and B
will be NULL. This causes the function to return false
:
if (!A || !B)
return false;
To avoid that, you should change the loop to break when both A
and B
are non-NULL:
if (A && B)
break;
Also, the loop is only checking count - 1
elements of the list, so it ignores the final element:
for (int i = 0; i < listNode->count - 1; i++)
To check all elements, you need to change that to:
for (int i = 0; i < listNode->count; i++)
Alternatively, you could ignore listNode->count
and check the temp
pointer instead:
while (temp != NULL)
That will work because temp
is initialized to listNode->head
, which will be NULL
for an empty list, and for a non-empty list, the next
member of the final element on the list is NULL
, so temp = temp->next;
will set temp
to NULL
when the final element has been checked.
There are other problems in swapNode
related to the actual swapping of the nodes after they have been found. The original code to do that looks totally wrong:
*temp = *A;
*A = *B;
*B = *temp;
The temp
pointer will either be NULL
or will point to a node after the A
and B
nodes.
if (A->prev)
A->prev->next = A;
if (A->next)
A->next->prev = A;
if (A->prev)
A->prev->next = A;
if (A->next)
A->next->prev = A;
The code does not alter listNode->head
or listNode->tail
when A
or B
is at the head or tail of the list.
free(temp);
Why is it freeing temp
here when all the function is supposed to be doing is swapping nodes?
The code to swap the nodes A
and B
needs to be able to deal with neither, either or both nodes being at the end(s) of the list, and with A
and B
being adjacent nodes in either order. Here is a sequence to handle all that:
/* update list head pointer */
if (listNode->head == A)
listNode->head = B;
else if (listNode->head == B)
listNode->head = A;
/* update list tail pointer */
if (listNode->tail == A)
listNode->tail = B;
else if (listNode->tail == B)
listNode->tail = A;
/* update ->prev->next pointers */
if (A->prev != NULL && A->prev != B)
A->prev->next = B;
if (B->prev != NULL && B->prev != A)
B->prev->next = A;
/* update ->next->prev pointers */
if (A->next != NULL && A->next != B)
A->next->prev = B;
if (B->next != NULL && B->next != A)
B->next->prev = A;
/* update A->prev and B->prev pointers */
if (A->prev == B)
{
A->prev = B->prev;
B->prev = A;
}
else if (B->prev == A)
{
B->prev = A->prev;
A->prev = B;
}
else
{
temp = A->prev;
A->prev = B->prev;
B->prev = temp;
}
/* update A->next and B->next pointers */
if (A->next == B)
{
A->next = B->next;
B->next = A;
}
else if (B->next == A)
{
B->next = A->next;
A->next = B;
}
else
{
temp = A->next;
A->next = B->next;
B->next = temp;
}
Upvotes: 3
Reputation: 9855
Using a debugger you would see that function swapNode
returns at
if (!A || !B)
return false;
If you would step through the for
loop you could see that you break
from the loop when at least one of A
and B
is set, i.e. when the first matching node is found.
if (A || B)
break;
Change this to
if (A && B)
break;
Upvotes: 1