Я каким-то образом адаптировал решение @dkamins. Вместо того, чтобы брать указатель на указатель, я возвращаю новый head
. Я также усилил это.
struct Node
{
struct Node *next;
int data;
};
typedef struct Node * NodePtr;
NodePtr swapEveryTwo(NodePtr head)
{
NodePtr newHead = (head && head->next) ? head->next : head;
NodePtr n = head;
while(n && n->next)
{
NodePtr tmp = n; // save (1)
n = n->next; // (1) = (2)
tmp->next = n->next; // point to the 3rd item
n->next = tmp; // (2) = saved (1)
n = tmp->next; // move to item 3
// important if there will be further swaps
if(n && n->next) tmp->next = n->next;
}
// return the new head
return newHead;
}
По сути, новым заголовком списка является либо текущий заголовок, если NULL
, либо длина 1, либо 2-й элемент.
В цикле подкачки tmp
в конечном итоге станет вторым элементом, но изначально это первый элемент. Поэтому нам нужно указать на 3-й элемент, который является целью tmp->next = n->next;
. Я не использую цикл for
, потому что если бы мы это сделали, он был менее интуитивным - выражение переоценки могло бы показаться прыгающим только на 1 узел за итерацию. В конце цикла while
, n = tmp->next;
имеет интуитивный смысл - мы указываем его на элемент после tmp
, 2-го элемента.
Самая важная часть - последняя строка. Поскольку мы делаем это в прямом направлении, мы должны помнить, что 2-й элемент предыдущей итерации почти наверняка будет указывать на возможный элемент 4th текущей итерации, потому что эта итерация поменяет местами 3 и 4. Таким образом, в конце итерации, если мы понимаем, что собираемся снова поменять местами следующую итерацию, мы тихо указываем 2-й элемент на текущий 4-й элемент, зная, что на следующей итерации это будет 3-й элемент, и все в порядке.
Например, если список 2 -> 7 -> 3 -> 5
:
n = 2
tmp = 2
n = 7
tmp->next = 3 (2 -> 3)
n->next = 2 (7 -> 2)
n = 3
7 -> 2 -> 3 -> 5
but then there will be swaps, so the last statement says
7 -> 2 -> 5 3?
Это нормально, потому что n = 3, поэтому мы не потеряли этот узел. Следующая итерация:
n = 3
tmp = 3
n = 5
tmp->next = NULL (3 -> NULL)
n->next = 3 (5 -> 3)
n = NULL
Ведет к окончательному 7 -> 2 -> 5 -> 3
ответу.