zoukankan      html  css  js  c++  java
  • 反转链表

    反转一个单链表

    输入: 1->2->3->4->5->NULL
    输出: 5->4->3->2->1->NULL

    思路:利用一趟遍历
    需要的条件:1、当前节点 2、当前节点的前驱节点 3、当前节点的后继节点
    -----------------------------python实现------------------------------
    class NodeList():
      def __init__(self,x):
        self.value= x
        self.next = null

    class Demo():
      def reverseList(self,head):
        """
        @prev :单前节点的前驱节点
        @cur:当前节点
        当前节点后继几点,可表示为cur.next
        """
        prev,cur = null,head
        while(cur){
          // 本语句利用了python的语法糖,一条语句完成了 同时赋值
         // 将当前节点cur,存储为下一个节点的prev,在下一次循环中使用
          // 将当前节点的后继节点cur.next ,存储为下一个节点的当前节点
          // 将当前节点的前驱节点,变成后继节点,完成反转
          prev,cur,cur,next = cur,cur.next,prev
        }
        // 遍历到最后一个节点时,最终是由prev存储这个节点的,注意这点不要写成cur,这时cur存储的是null
        ruturn prev

    -----------------------------java实现-------------------------
    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Demo{
        public ListNode reverseList(ListNode head) {
            ListNode cur = head;
            ListNode prev = null;
            while(cur!=null){
           /*
            java语言没有类似python中一同赋值的语法糖,所以这里要注意一些细节,也就是赋值操作的执行顺序
            1、首先将当前节点的后继节点缓存起来
            2、将前驱节点prev 赋值给后继节点
            3、将当前节点保存为下一个待遍历节点的前驱节点
            4、更新当前节点,继续下一次遍历
            以上4步可以看出,只有第2步真正的完成当前节点指针的指向,第1,3,4步骤是在为下一个节点作准备工作
           */
                ListNode temp = cur.next; // 缓存当前节点的后继节点
                cur.next = prev; // 改变当前节点指针的方向
                prev = cur; // 更新前驱节点(当前操作的节点,是下一个节点的前驱节点),为下一次遍历做准备
                cur = temp; // 更新cur,为下一次遍历做准备
            }
            return prev; //这里放回的是prev,遍历最后一个节点时,该节点被赋值给了prev, 而cur被赋值为null

        }
    }
     
    遍历解法复杂度:
     
        时间负杂度:O(n)
        空间复杂度:O(1)
     
    --------------------------------递归实现(java)-----------------------------------------------------------------
    class Demo(){
      public ListNode reverseList(ListNode head){
      /*
        1.递归的结束条件:碰到最后一个节点,即head.next ==null,结束递归
        2.有效的反转动作:代码(1)不断的把当前节点 赋值给 其后继节点的next指针
        3、反转后,末尾节点要指向null:代码(2)不断的把当前节点的next指针指向null
        4、 反转后链表的头节点,通过last变量,在最后一次递归迭代时被赋值;然后,按照递归的层次,一层层的返回,知道递归完成。
        所以,需要考虑的只有4各方面———— 1、递归结束条件/2、反转动作/3、获得反转后的头结点/4、反转后 末尾节点 要指向null
     
        另外,在递归过程中,不断的进行入栈操作,所有遍历过的节点在栈中都有保存
      */
        if(head == null){
          return head;    
        }
        ListNode headAfterReverse = reverseList(head.next);
        head.next.next = head;//(1)
        head.next = null; //(2) 链表的结尾要执行null
        return last;  
      }
    }
     
    递归解法复杂度:
     
        时间负杂度:O(n)
        空间复杂度:O(n),堆栈内需要存储遍历过的所有节点
     

     
    思考:
     
    如果反转链表前N个节点呢?会发生哪些细微的变化?
     
     
    1、递归结束条件,变成 n==1
    2、反转后的尾节点要指向 第n+1个节点,所以需要一个额外的变量存贮这个节点;
    class Demo(){
      ListNode temp = null;
      public ListNode reverseListN(head,n){
        if(n==1){
          temp = head.next;
          return head;      
        }
        ListNode headAfterReverse = reverseListN(head.next,n-1);
        head.next.next = head;
        head.next = temp;
      }
    }
     

     
    思考:
     
    如果反转链表的一部分呢,有哪些细节需要考虑?
     
     
    题目;
    反转从位置 m 到 n 的链表,1 ≤ m ≤ n ≤ 链表长度

    输入: 1->2->3->4->5->NULL, m = 2, n = 4
    输出: 1->4->3->2->5->NULL
    使用一趟扫描完成反转
    解法:递归
    在反转链表前N个元素的基础上,进一步递归
    1、递归结束条件 m==1
    2、第m-1个节点的指针,要指向反转部分的头节点
    3、在前m-2个个节点的递归中,都是返回当前节点;在第m-1个节点的递归中,返回的是反转链表部分的头结点;
    class Demo(){
      
      public ListNode reverseListBetween(head,m,n){
        if(m==1){
          return reverseListN(head,n);
        }
        // 一直到反转的起始节点(第m节点),触发 reverseListN
        head.next = reverseListBetween(head.next,m-1,n-1);
        return head;
     
    }
    }

     
     
     
     
     
     
     
     
  • 相关阅读:
    服务器(Ubuntu 12.04 LTS)上编译基于OpenCV的项目遇到的问题及解决方案
    ubuntu 16.04 LTS 降级安装gcc 4.8
    C#程序中获取电脑硬件配置信息的一种方法
    C#程序将对象保存为json文件的方法
    C#中运用事件实现异步调用
    Redis实现分布式锁 php
    CI框架整合UEditor编辑器上传功能
    PHP给图片加水印具体实现
    检测网站是否被和谐!
    vue的双向绑定和依赖收集
  • 原文地址:https://www.cnblogs.com/wl413911/p/12918689.html
Copyright © 2011-2022 走看看