zoukankan      html  css  js  c++  java
  • 【反转单链表】一篇就够了

    ·单链表反转

    这次讲单链表反转,main方法:

    public static void main(String[] args) {
        // 新建链表
        LinkNode l = getALinkList(5);
        LinkNode cur;
    
        // 若为带头节点的链表,取消这段注释
        // cur = new LinkNode(-1);
        // cur.next = l;
        // l = cur;
    
        cur = l;
        // 反转前打印
        while (cur != null){
            System.out.print(cur.val+" ");
            cur = cur.next;
        }
        // 反转		
        cur = reverse1(l);
        // 反转后打印
        System.out.println();
        while (cur != null){
            System.out.print(cur.val+" ");
            cur = cur.next;
        }
    }
    

    getALinkList方法:

    // 创建有 len 个节点的链表,val 为0-99随机数
    private static LinkNode getALinkList(int len){
        Random random = new Random();
        LinkNode l = new LinkNode(random.nextInt(99));
        LinkNode cur = l;
        for (int i = 0; i < len - 1 ; i++) {
            cur.next = new LinkNode(random.nextInt(99));
            cur = cur.next;
        }
        return l;
    }
    

    链表节点:

    public class LinkNode {
        public int val;
        public LinkNode next = null;
    
        public LinkNode(int val){
            this.val = val;
        }
    }
    

    链表反转一般有三种方法,原地反转,头插法反转,递归反转。其中递归反转最简单简洁,但是空间复杂度更高。下面分别介绍。

    1. 原地反转

      首先让pre的next指向cur的next;再让cur的next指向头节点的下一个结点;这时已经反转了结点,此时链表第一个结点变成了当前反转的结点;再让头节点的next指向cur;最后移动cur到下一个要反转的结点。重复上述步骤,直到cur为null。此时头节点也指向最后一个节点了。

      带头节点的链表:

      static LinkNode reverse1(LinkNode l){
          if(l.next == null || l.next.next == null){
              return l;
          }
          LinkNode pre = l.next;  // pre 不动, 移动头节点
          LinkNode cur = pre.next;
          while(cur != null){
              pre.next = cur.next;
              cur.next = l.next;
              l.next = cur;
              cur = pre.next;
          }
          return l;
      }
      

      不带头结点的链表:

      一样的做法一个指向pre,一个指向cur。而且比有头节点的更加简单。

      public LinkNode reverse2(LinkNode l){
          LinkNode pre = l;
          LinkNode cur = pre.next;
          while(cur != null){
              LinkNode next = cur.next;
              cur.next = pre;
              pre = cur;
              cur = next;
          }
          l.next = null;  // 记得将最开始的头节点指向null,否则形成环路
          return pre;
      }
      
    2. 利用头插法反转

      新建一个链表,遍历原链表,用头插法插入到新链表中。

      值得注意的是,在遍历开始前,还要断开第一个结点和第二个结点之间的链。初始化工作做完后,从第二个结点开始遍历链表,依次插入新链表中,即实现反转。

      带头节点的链表:

      static LinkNode reverse3(LinkNode l){
          if(l.next == null || l.next.next == null){
              return l;
          }
          LinkNode cur = l.next.next;
          LinkNode next;
          l.next.next = null;
          while (cur != null){
              next = cur.next;
              cur.next = l.next;
              l.next = cur;
              cur = next;
          }
          return l;
      }
      

      不带头结点的链表:

      static LinkNode reverse4(LinkNode l){
          if(l == null || l.next == null){
              return l;
          }
          LinkNode cur = l.next;
          LinkNode next;
          l.next = null;
          while (cur != null){
              next = cur.next;
              cur.next = l;
              l = cur;
              cur = next;
          }
          return l;
      }
      
    3. 递归反转

      直接递归得到最后一个节点,然后每层就是将这个节点的下一个节点指向这个节点,这个节点指向null,最后返回末尾节点。(不带头节点)

      static LinkNode reverse5(LinkNode l){
          if(l == null || l.next == null){
              return l;
          }
          LinkNode p = reverse5(l.next);
          l.next.next = l;
          l.next = null;
          return p;
      }
      
  • 相关阅读:
    java 线程 Lock 锁使用Condition实现线程的等待(await)与通知(signal)
    A计划(三维dfs)
    最少拦截系统(线性dp)
    疯狂的采药(完全背包)
    Modular Inverse (拓展欧几里得求逆元)
    斐波那契数列的3种求法及几种素数筛法
    Magic Odd Square (思维+构造)
    Marlin (思维)
    qdu_组队训练(ABCFIJK)
    2018蓝桥编程题6-9+ 50%的10
  • 原文地址:https://www.cnblogs.com/cpcpp/p/13374900.html
Copyright © 2011-2022 走看看