数据结构与算法——实现单链表反转

如何实现单链表反转

方法一:就地逆序

在遍历链表的时候,修改当前结点的指针域的指向,让其指向它的前驱结点。为此需要用一个指针变量保存前驱结点的地址。此外,为了在调整当前结点指针域的指向后还能找到后继结点,还需要另外一个指针变量来保存后继结点的地址。除此之外,还需要特别注意对链表首尾结点的特殊处理

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) {}
};

void Reverse(ListNode* head)
{
    if (head == NULL || head->next == NULL)
    {
        return;
    }

    ListNode* pre = NULL; //前驱结点
    ListNode* cur = NULL; //当前结点
    ListNode* next = NULL; //后继结点

    //把链表首结点变为尾结点
    cur = head->next;
    next = cur->next;
    cur->next = NULL;
    pre = cur;
    cur = next;

    //使当前遍历到的结点cur指向其前驱结点
    while (cur->next != NULL)
    {
        next = cur->next;
        cur->next = pre;
        pre = cur;
        cur = cur->next;
        cur = next;
    }

    //最后一个结点指向倒数第二个结点
    cur->next = pre;
    //链表头结点指向原来链表的尾结点
    head->next = cur;
}

这种方法只需要对链表进行一次遍历,因此时间复杂度为O(n),空间复杂度为O(1)

方法二:递归法

对不带头结点的单链表进行逆序
//first是指向链表第一个结点的指针的指针
void RecursiveReverse(ListNode** first)
{
    if (first == NULL || *first == NULL)
    {
        return;
    }

    ListNode* cur;
    ListNode* rest;
    cur = *first;
    rest = cur->next;
    if (rest == NULL)
    {
        return;
    }

    //逆序rest
    RecursiveReverse(&rest);
    //把第一个结点添加到尾结点
    cur->next->next = cur;
    cur->next = NULL;

    //更新逆序后链表第一个结点的指向
    *first = rest;
}
对带头结点的单链表进行逆序
//head是指向链表头结点指针的指针
void Reverse(ListNode** head)
{
    if(*head == NULL || (*head)->next == NULL)
    {
        return;
    }

    //获取第一个结点
    ListNode* firstNode = (*head)->next;
    //对链表进行逆序
    RecursiveReverse(&firstNode);
    //头结点指向逆序后链表的第一个结点
    (*head)->next = firstNode;
}

递归算法也只需要对链表进行一次遍历,因此算法的时间复杂度为O(n),但需要额外的压栈和弹栈操作

方法三:插入法

从链表第二个结点开始,把遍历到的结点插入到头结点的后面,直到遍历结束

void Reverse(ListNode* head)
{
    if (head == NULL || head->next == NULL)
    {
        return;
    }

    ListNode* cur = NULL; //当前结点
    ListNode* next = NULL; //后继结点
    cur = head->next->next;
    //设置链表第一个结点为尾结点
    head->next->next = NULL;
    //把遍历到结点插入到头结点后面
    while (cur != NULL)
    {
        next = cur->next;
        cur->next = head->next;
        head->next = cur;
        cur = next;
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值