单链表交换两结点

该博客主要探讨了如何通过键盘随机输入非零整数建立单链表,然后实现根据给定索引交换链表中节点的功能。程序包括新建、交换、打印和释放链表的函数,确保了索引有效性和不同情况下的节点交换逻辑。

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

题目描述:请填写缺失代码完成程序,实现如下功能:首先根据键盘随机输入,以0结束的若干非零整数建立单链表;然后根据输入的两个索引位置交换链表上的两个结点(链表首元素索引为1,

#include <stdio.h>

#include <malloc.h>

struct cell {//单链表结点结构体定义

    int x;

    struct cell* next;

};

struct cell* build(void) {//新建单链表,并将建好的单链表首结点地址返回

    struct cell* head, * tmp, * p;

    head = tmp = p = NULL;

    int n;



    head = (cell*)malloc(sizeof(cell));

    head->next = NULL;

    tmp = head;



    while (head != NULL) {

        scanf("%d", &n);

        if (n == 0)break;

        p = (cell*)malloc(sizeof(cell));

        p->x = n;

        tmp->next = p;

        p->next = NULL;

        tmp = p;

    }

    if (head->next == NULL) {

        free(head);

        head = NULL;

    }

    return head;//返回单链表头

}

struct cell* swap(struct cell* head, int m, int n) {//交换索引为m和n的两个结点,head是单链表首结点指针

    if (head == NULL) return NULL;

    struct cell* pm = head, * pn = head;

    struct cell* pm0 = NULL, * pn0 = NULL;

    struct cell* tmp;

    int i;



    for (i = 1; i < m && pm != NULL; i++) {

        pm0 = pm;

        pm = pm->next;

    }



    for (i = 1; i < n && pn != NULL; i++) {

        pn0 = pn;

        pn = pn->next;

    }



    if (pm != NULL && pn != NULL && m != n) {//索引为m,n的结点位于链表中间

        int temp;

        if (pm0 != NULL && pn0 != NULL) {//中间

            temp = pm->next->x; 

            pm->next->x = pn->next->x;

            pn->next->x = temp;

        }



        if (pm0 == NULL && pn0 != NULL) {  //pm0为头部 n>m

            temp = head->next->x;

            head->next->x = pn->next->x;

            pn->next->x = temp;

        }



        if (pm0 != NULL && pn0 == NULL) {  //pn0尾部  m>n

            temp = head->next->x;

            head->next->x = pm->next->x;

            pm->next->x = temp;

        }

    }

    return head;

}

void print(struct cell* head) {//打印整个单链表,head是单链表首结点指针

    struct cell* tmp, * p;

    tmp = head->next;

    while (tmp != NULL) {

        printf("%d", tmp->x);

        if (tmp->next != NULL)printf(" ");

        tmp = tmp->next;

    }

}

void release(struct cell* head) {//释放单链表空间,head是单链表首结点指针

    struct cell* temp, * p;

    temp = head;

    while (temp != NULL) {

        p = temp;

        temp = temp->next;

        free(p);

    }

}

int main(void) {

    struct cell* head;

    int m, n;

    head = build();

    scanf("%d %d", &m, &n);

    head = swap(head, m, n);

    if (head != NULL)

        print(head);

    else

        printf("NULL");

    release(head);

}

<think>好的,我现在需要解释单链表中如何交换个相邻结点的问题。首先,我得回忆单链表的基本结构。单链表每个结点包含数据域和指向下一个结点的指针。交换个相邻结点需要考虑它们的前后连接关系,尤其是前驱结点的指针调整。 假设用户可能不太了解链表操作,我需要从基础讲起。先画个示意图可能会有帮助。比如有结点A和B,A指向B,B指向C。现在要交换A和B,变成B指向A,A指向C。这时候,需要考虑是否有头结点,以及如何调整前驱结点的next指针。 接下来,我需要分步骤解释。首先,找到要交换结点的前驱结点。比如如果交换的是第二个和第三个结点,那么前驱结点是第一个结点。如果没有前驱结点(即交换的是头结点),处理方式会不同。这时候需要改变头指针的指向。 然后,具体指针的调整步骤。例如,假设前驱结点是prev,当前结点是curr,下一个结点是next_node。交换curr和next_node需要让prev的next指向next_node,然后curr的next指向next_node的next,最后next_node的next指向curr。这样完成交换。 需要注意边界情况,比如链表为空、只有一个结点、或者要交换结点中有一个是尾结点等情况。这时候需要特别处理,避免出现空指针异常。 接下来,可能需要用代码示例来说明这个过程。比如在C语言中,定义一个链表结构体,然后编写交换函数。要确保指针操作正确,特别是顺序问题,比如保存临时变,防止指针丢失。 例如,伪代码可能如下: prev->next = next_node; curr->next = next_node->next; next_node->next = curr; 这样三步完成交换。但如果是头结点,没有prev,就需要直接调整头指针。 最后,总结交换的步骤,并提醒注意检查边界条件。可能还需要讨论时间复杂度,比如O(n)的时间复杂度,因为可能需要遍历链表找到要交换结点。</think>单链表交换个相邻结点需要调整指针的指向,确保链表不断开。以下是详细步骤和说明: --- ### **一、单链表结构回顾** - **结点定义**:每个结点包含数据域 `data` 和指向下一个结点的指针 `next`。 - **示例链表**: $$A \rightarrow B \rightarrow C \rightarrow D$$ 假设要交换结点 $B$ 和 $C$。 --- ### **二、交换相邻结点的步骤** 1. **定位相关结点**: - 找到待交换结点(如 $B$ 和 $C$)及其前驱结点(如 $A$)。 - 若交换的是头结点,前驱结点为 `NULL`。 2. **调整指针顺序**(以交换 $B$ 和 $C$ 为例): - **步骤 1**:前驱结点 $A$ 的 `next` 指向 $C$。 - **步骤 2**:$B$ 的 `next` 指向 $C$ 的原本下一个结点 $D$。 - **步骤 3**:$C$ 的 `next` 指向 $B$。 **交换后的链表**: $$A \rightarrow C \rightarrow B \rightarrow D$$ 3. **特殊情况处理**: - **交换结点**:直接修改头指针,指向第二个结点。 - **其中一个结点是尾结点**:无需调整后续指针。 --- ### **三、代码实现(C语言示例)** ```c struct ListNode { int data; struct ListNode *next; }; void swapPairs(struct ListNode **head) { // 处理空链表或单结点链表 if (*head == NULL || (*head)->next == NULL) return; struct ListNode *prev = NULL; struct ListNode *curr = *head; struct ListNode *next_node = curr->next; // 交换结点 if (prev == NULL) { *head = next_node; // 更新头指针 curr->next = next_node->next; next_node->next = curr; } else { // 一般情况 prev->next = next_node; curr->next = next_node->next; next_node->next = curr; } } // 若需要交换整个链表的相邻结点,可遍历链表重复此操作 ``` --- ### **四、关键注意事项** 1. **边界条件**: - 链表为空或只有一个结点时,直接返回。 - 处理尾结点时避免访问空指针。 2. **指针操作顺序**: - 必须先保存原指针(如 `next_node->next`),防止丢失后续结点。 3. **时间复杂度**: - 单次交换为 $O(1)$,遍历整个链表交换所有相邻结点为 $O(n)$。 --- ### **五、总结** 交换单链表中的相邻结点需通过调整指针重新建立连接关系,重点在于正确处理前驱结点和边界情况。通过分步操作和临时变保存指针,可避免链表断裂或内存访问错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值