两两交换相邻节点

文章介绍了如何在C++中实现链表的两两节点交换,通过设置虚拟头节点解决首节点特殊性,使用迭代方式遍历链表,每次交换相邻两个节点,并通过临时变量保存断开的连接,确保正确拼接。最后返回虚拟头节点的下一个节点作为新的头节点,避免丢失第一个节点的数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

注意:是进行节点的交换,不是单纯地交换节点中的值

比如链表为1->2->3->4,交换后变成2->1->4->3。

首先链表定义:

 struct ListNode {

      int val;

      ListNode *next;

     ListNode() : val(0), next(nullptr) {}

      ListNode(int x) : val(x), next(nullptr) {}

     ListNode(int x, ListNode *next) : val(x), next(next) {}

  };

分析:首先需要设置一个虚拟头节点,因为交换两个节点的时候,需要操作两个节点前的节点。由于第一个节点前面没有节点,所以需要设置虚拟头节点。

ListNode *dummyhead=new ListNode(0);

dummyhead->next=head;

操作步骤:

 首先定义一个动态的节点ListNode *cur=dummyhead。该节点意义为交换两个节点的前一个节点,通过对这个节点进行操作来交换后面两个节点。

所以循环停止的条件有两个:

1、如果链表长度为偶数时,最终cur会落到最后一个节点,此时的终止条件是cur->next!=nullptr

 2、如果链表长度为奇数时,最终cur会落到倒数第二个节点,此时的终止条件是cur->next->next!=nullptr,最后一个元素不用管。

来看一次交换中的步骤:

dummyhead->1->2->3->4需要变成dummyhead->2->1>3>4

step1:将dummyhead指向2,此时链接1处断开了

step2:将2指向1,此时链接3断开了

此时,在第一步中,由于链接1断开了,无法指向1,所以要提前保存1的位置。

step3:将1指向3,此时2断开了

此时,在第二步中,由于链接3断开了,无法指向3,所以需要提前保存3的位置

ListNode *tmp1=cur->next->next->next;//保存3的位置

 ListNode *tmp2=cur->next;//保存1的位置

总结:怎么看提前保存哪些?画图来看,连一个,断一个,如果后续需要再用的话,就提前保存。

注意:cur的后面的节点在过程中是不断变化的,因为连一个断一个,后续都在发生变化。

step1:cur->next=cur->next->next;

step2:此时2是连接在cur的下一个的。所以步骤2应该为cur->next->next=tmp2;而不是cur->next->next->next=tmp2。cur->next->next->next=tmp2是没有进行步骤1的写法。

step3:此时dummyhead后面是连接的2和1。所以1代表的是cur->next->next。1要连接3的话是cur->next->next->next=tmp1。

进行了这三步后,链表就变成了 dummyhead->2->1->3->4。

为了进行后续的交换,把cur移动到3的位置。即cur=cur->next->next。

最终循环结束,返回虚拟头节点的下一个节点。为什么不返回head?因为head交换到第二个位置去了。如果返回head,那结果就为交换后第二个节点到最后,会损失交换后第一个节点的数据。比如,原链表为1->2->3->4,返回head就为1->4->3,head只要不在代码中进行修改,指的就是数值为1的那个节点。所以要返回虚拟头结点的下一个节点。

完整代码如下:

最后一行的代码修改为return dummyhead->next。

### 单链表节点两两交换算法 #### 迭代方法 通过引入一个虚拟头节点 `dummy` 来简化边界情况处理。定义指针 `prev` 初始指向虚拟头节点,随后进入循环逐步交换每一对相邻节点并更新指针关系。 以下是基于 C 和 Python 的实现: ```c // C 实现 struct ListNode { int val; struct ListNode *next; }; struct ListNode* swapPairs(struct ListNode* head) { struct ListNode dummy = {0, head}; // 创建虚拟头节点 struct ListNode *prev = &dummy; while (head && head->next) { struct ListNode *first = head; // 当前节点 struct ListNode *second = head->next; // 下一节点 // 更新 prev 节点next 指针到 second prev->next = second; // 交换 first 和 second 的位置 first->next = second->next; second->next = first; // 移动 prev 和 head 指针 prev = first; head = first->next; } return dummy.next; } ``` ```python # Python 实现 class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def swapPairs(head: ListNode) -> ListNode: dummy = ListNode(0) # 创建虚拟头节点 dummy.next = head prev = dummy while head and head.next: first_node = head # 当前节点 second_node = head.next # 下一节点 # 更新 prev 节点next 指针到第二节点 prev.next = second_node # 交换第一和第二节点的位置 first_node.next = second_node.next second_node.next = first_node # 移动 prev 和 head 指针 prev = first_node head = first_node.next return dummy.next ``` 上述代码实现了单链表节点两两交换操作[^1]。对于输入 `[1,2,3,4]`,输出结果为 `[2,1,4,3]`[^2]。 --- #### 递归方法 递归方法的核心在于将问题分解成更小的部分解决。如果链表为空或仅有一个节点,则无需交换直接返回原链表。否则先交换前两个节点,并对剩余部分递归调用函数完成后续节点交换。 下面是递归版本的实现: ```c // C 实现 struct ListNode* swapPairsRecursive(struct ListNode* head) { if (!head || !head->next) return head; struct ListNode* newHead = head->next; // 新的头结点 head->next = swapPairsRecursive(newHead->next); newHead->next = head; // 完成交换 return newHead; } ``` ```python # Python 实现 def swapPairsRecursive(head: ListNode) -> ListNode: if not head or not head.next: return head new_head = head.next # 新的头结点 head.next = swapPairsRecursive(new_head.next) new_head.next = head # 完成交换 return new_head ``` 此递归逻辑同样适用于任意长度的有效链表[^3]。需要注意的是,在实际应用中应谨慎对待递归可能引发的栈溢出风险[^4]。 --- ### 性能分析 - **时间复杂度**: O(n),其中 n 是链表中的节点数。无论是迭代还是递归都需要访问每一个节点一次。 - **空间复杂度**: - 对于迭代方法,其空间复杂度为 O(1),因为只使用了常量额外存储; - 对于递归方法,由于存在隐式的调用堆栈开销,最坏情况下空间复杂度可达 O(n/2)=O(n)[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值