剑指offer——反转链表

题目:定义一个函数,输入链表的头结点,反转该链表并输出反转后链表的头结点,链表结点结构定义如下:

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

解决与链表相关的问题总是有大量的指针操作,而指针操作的代码总是很容易出错。很多面试官喜欢出链表相关的问题,就是想通过指针操作来考察应聘者的编码功底。为了避免出错,我们最好先进行全面的分析,在实际软件开发周期中,设计的时间总不会比编码的时间短。在面试的时候我们不要急于动手写代码,而是一开始仔细分析和设计,这将会给面试官留下很好的印象。与其很快的写出一段漏洞百出的代码,倒不如仔细分析再写出鲁棒的代码。

为了正确的反转一个链表,需要调整链表中指针的方向。为了将调整指针的这个复杂过程分析清楚,我们可以借助画图来直观的分析,具体图如下:

反转前:所示的链表 H、I、J 是三个相邻的结点。

反转中:经过若干操作,我们已经把结点 H 之前的指针调整完毕,这些节点的next都指向前面一个结点。

我们可以看到,上图所示的链表 I 结点的next指向 H ,此时的链表结构为结点 I 和 J 之间发生断裂。

不难注意到,由于结点 I 的next指向了它的前一个结点,导致我们无法在链表中遍历到结点 J ,为了避免链表在结点 I 处断裂,我们需要在调整结点 I 的next之前,把结点 J 保存下来。

也就是说我们在调整结点 I 的next指针时,除了需要知道结点 I 本身,还要知道结点 I 的前一个结点 H ,因为我们需要把结点 I 的next指向结点 H 。同时,我们还需要保存 I 的下一个节点 J ,以防止链表断裂。

为此,我们需要定义三个指针,分别指向当前遍历的结点、它的前一个结点、它的后一个结点。

最后我们试着找到反转链表的头结点。不难分析出,反转之后的链表的头结点为原始链表的尾节点。

为此,我们给出代码如下:

  ListNode* ReverseList(ListNode* pHead) {
        ListNode* ReversepHead = NULL;
        ListNode* pNode = pHead;
        ListNode* pPrev = NULL;
        while(pHead != NULL)
        {
            ListNode* pNext = pHead->next;
            if(pHead->next == NULL)
                ReversepHead = pHead;
            pHead->next = pPrev;
            pPrev = pHead;
            pHead = pNext;
        }
        return ReversepHead;
    }

猜你喜欢

转载自blog.csdn.net/ypt523/article/details/79679630