实现单链表反转——递归版本和迭代版本

首先,关于递归的知识,可以参考我的这篇 递归:汉诺塔

关于单链表的知识可以参考我的这篇 单链表整表创建的两种方法(头插法和尾插法)

本文中链表的结构定义如下:

typedef struct Node{
    int data;
    Node *next;
} Node, *List;

想要反转整个链表,可以考虑一个一个的结点从后往前反转,这就考虑到了递归与回溯,所以可以用递归实现:

  

//递归方式
Node * reverseList(List head)
{
    //如果链表为空或者链表中只有一个元素
    if(head == NULL || head->next == NULL)
    {
        return head;
    }
    else
    {
        //先反转后面的链表,走到链表的末端结点
        Node *newhead = reverseList(head->next); //语句1
        //再将当前节点设置为后面节点的后续节点
        head->next->next = head; //语句2
        head->next = NULL;  //语句3
        
        return newhead;
    }
}

整个递归算法可以用下面的示意图解释,其实跟汉诺塔是一个道理:

上面代码中的语句1是一个不断向后递归的过程,终止条件是if中的判断部分,实际上就是在偷懒,让“别人”先帮我把除了第一个结点以外的其他结点反转过来,我负责最后一个。

语句2语句3就是接下来我要做的工作了(我就捡轻松的活干)

语句2就是下图中我做的第一步,变换一下指针

语句3就是下图中我做的第二步,把最后一个指针指向NULL

最后返回newHead,OK大功告成!

实现单链表反转——递归版本和迭代版本_第1张图片

=============================次次用到的华丽分割线===============================

下面讲一下反转链表的迭代版本:

迭代版本需要注意的问题是,当反转一个结点以后的链表断裂问题。

所以这里我们需要设置3个指针,分别指向当前结点、当前结点的前一结点和当前结点的后一结点。

#include 
using namespace std;

typedef struct Node{
    int data;
    Node *next;
} Node, *List;

Node * reverseList(List head){
    //定义三个指针,保存原来的连接的状态
    //当前结点指针
    Node *pnow = head;
    //当前结点的前驱指针,初始化是 NULL
    Node *pre = NULL;
    //当前结点的后继指针,初始化也是 null
    Node *pnext = NULL;
    //定义尾指针
    Node *tail = NULL;
    //开始遍历链表
    while(pnow != NULL){
        //如果当前结点不是 null,那么初始化 pnext 指针指向当前结点的下一个结点
        pnext = pnow->next;
        //如果找到了尾结点,初始化 tail 指针
        if(NULL == pnext){
            tail = pnow;
        }
        //进行链表的反转,当前结点的 next 指针指向前一个结点,实现链表方向的反转,此时发生了断链
        pnow->next = pre;
        //勿忘断链的情形,需要使用 pre 指针保存状态,pre 等价于是后移一个结点
        pre = pnow;
        //pnow 后移一个结点
        pnow = pnext;
    }
    
    return tail;
}

 

你可能感兴趣的:(数据结构与算法)