zoukankan      html  css  js  c++  java
  • 翻转链表-迭代和递归双版本

    将一个链表翻转,如 1->2->3->4 变成 4->3->2->1 的链表。这是一个非常著名的面试题,看似非常的简单,但实际上非常的tricky.

    实现方法可以有递归和迭代两种方法,这两个算法也都保证了in-place 和 one-pass. 所以效率还是很高的。这篇文章主要基于http://leetcode.com/2010/04/reversing-linked-list-iteratively-and.html. 他讲解的基本已经比较清楚,我就再从比较菜的角度去分析一下。

    迭代方法:

    首先来看迭代版本的基本思路,先上图:

    上图就是迭代的第一步,基本就是prev, curr, next三个指针跟踪着当前点的情况,然后更新后向前移动,直到移到链表末尾

    看代码后应该更清晰:

     1 void reverse(Node*& head) {
     2   if (!head) return;
     3   Node* prev = NULL;
     4   Node* curr = head;
     5   while (curr) {
     6     Node* next = curr->next;
     7     curr->next = prev;
     8     prev = curr;
     9     curr = next;
    10   }
    11   head = prev;
    12 }

    代码中要注意 Node*&, 毕竟是改变了链表的结构,所以链表的头指针应该传一个引用。

    翻转链表的迭代版本很清晰,且容易实现。而下面的递归方法虽然代码很短,但是比较难理解,且实现起来细节也很多。

    递归版本:

    这个整体过程比较复杂,所以还是先上图:

    然后来看着代码分析:

    void reverse(Node*& p) {
      if (!p) return;
      Node* rest = p->next;
      if (!rest) return;
      reverse(rest);
      p->next->next = p;
      p->next = NULL;
      p = rest;
    }

    递归过程中,首先迅速由递归函数进行至第一幅图的情况(其实下面还有一步,此时rest 指向NULL,返回到第一幅的情况)

    然后将当前节点的下一节点的子节点倒指向其父节点(即当前节点),然后将当前节点指向NULL,即当前我们翻转了从当前节点到末尾节点。

    注意这之后的最后一个语句,将p 赋值为 rest,然后返回。 返回到上一层会发生什么呢? 这就要注意每层调用reverse函数时,传进去的指针式rest, 即修改上一层的rest指针为当前层的rest指针,换句话说,在以后递归的过程中,rest指针将一直指向最后一个节点,即新的链表根节点。

  • 相关阅读:
    670. Maximum Swap
    653. Two Sum IV
    639. Decode Ways II
    636. Exclusive Time of Functions
    621. Task Scheduler
    572. Subtree of Another Tree
    554. Brick Wall
    543. Diameter of Binary Tree
    535. Encode and Decode TinyURL
    博客园自定义背景图片
  • 原文地址:https://www.cnblogs.com/soyscut/p/3801539.html
Copyright © 2011-2022 走看看