对于单链表而言,假设要交换的节点为A和B,那么在交换之前,建议先保存要交换节点的前后两个节点,可以减少错误率。(即分别保存A和B的直接前驱和直接后继节点--一般是4个节点)
需要注意的特殊情况:
<1> 当A和B相邻时(假设A在前,B在后),此时需要做特殊处理,并且只需保存A的直接前驱节点和B的直接后继节点即可(共2个节点);
<2> 如果A和B元素相同或A和B是同一个节点,就没有必要交换;
<3> 如果A和B节点中有一个是表头,也不交换。
具体实现如下:
#include <iostream>
typedef struct node
{
int data;
struct node *next;
} NODE;
NODE *create_end(int arr[], int len)
{
NODE *head = (NODE *)malloc(sizeof(NODE *));
head->next = NULL;
NODE *end = head;
for (int i = 0; i < len; i++) {
NODE *p = (NODE *)malloc(sizeof(NODE *)); // 也可用 new NODE();
p->data = arr[i];
end->next = p;
end = p;
}
end->next = NULL;
return head;
}
// 此方法适用于不带头节点的单链表的打印,对于带头节点的单链表要稍作处理。
void print(NODE *head)
{
if (head == NULL) return;
while (head != NULL) {
printf("%d ",head->data);
head = head->next;
}
}
// 返回前驱节点
NODE *FindPre(NODE *head, NODE *p)
{
NODE *q = head;
while (q)
{
if (q->next == p)
return q;
else
q = q->next;
}
return NULL;
}
// 交换单链表中任意两个元素(不包括表头)
NODE *Swap(NODE *head, NODE *p, NODE *q)
{
if (head == NULL || p == NULL || q == NULL)
return head;
if (p->data == q->data || p == q) // 若p和q的元素相同 或 p和q是同一节点,则不用交换。
return head;
if (p->next == q) // p和q相邻时,p的下一个节点是q。
{
NODE *pre_p = FindPre(head, p);
NODE *aft_q = q->next;
pre_p->next = q;
p->next = aft_q;
q->next = p;
}
else if (q->next == p) // p和q相邻时,q的下一个节点是p。
{
NODE *pre_q = FindPre(head, q);
NODE *aft_p = p->next;
pre_q->next = p;
q->next = aft_p;
p->next = q;
}
else
{
NODE *pre_p = FindPre(head, p);
NODE *pre_q = FindPre(head, q);
NODE *aft_p = p->next;
NODE *aft_q = q->next; // 改变某个节点的位置前,一定要先具体标注出该节点前后的两个节点,可以减少错误率。
pre_p->next = q;
q->next = aft_p;
pre_q->next = p;
p->next = aft_q;
}
return head;
}
int main(int argc, const char * argv[]) {
int arr[] = {6,2,5,4,3,7,1};
int len = sizeof(arr)/sizeof(int);
NODE *head = create_end(arr, len);
// 交换前
print(head->next);
printf("\n");
NODE *p, *q;
p = head->next; // 链表的第1个节点
q = head->next->next->next; // 链表的第3个节点
Swap(head, p, q);
// 交换后
print(head->next);
printf("\n");
return 0;
}
输出如下: