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

    1.什么是链表的反转?


    当我在床上辗转反侧难以入睡的时候,我反过来翻过去的睡不着,想学习,于是想起了最近在看的反转链表问题,这个还是需要一些思考哈。
    首先当我们在聊到链表反转的时候,一定说的都是单链表,双链表本身就具有前驱指针 Prev 和后续指针 next,无需进行反转哈。
    单链表反转,反转后的效果如下:

    看起来很简单,只需要将单链表所有结点的 next 指向,指向它的前驱节点即可。

    2.使用栈进行链表的反转

    引入一个栈结构(或者数组),就可以实现。只是需要额外的空间,数组的比较简单,就是遍历这个链表,将数据data用数组存起来,再反向遍历组成结点连接起来即可,这样的话时间和空间复杂度均为n.
    这里以栈为例,在原本链表的数据结构之外,引入一个栈(数组也可),将单链表循环遍历,将所有结点入栈,最后再从栈中循环出栈,记住出栈的顺序,得到的就是反转后的单链表。

    但是这样实现,有一个问题,它会额外消耗一个栈的内存空间,此时空间复杂度就变成了 O(n)。并且,栈会遇到的问题,使用此种方式都会遇到,例如比较常见的,栈的深度问题。

    2.原地反转链表,空间复杂度降低

    在排序算法中,有一个概念叫原地排序,指的是不需要引入额外的存储空间,在原数据结构的基础上进行排序。这种排序算法的空间复杂度是 O(1)。例如我们常见的冒泡排序、插入排序都是原地排序算法。

    这里,我们也可以在原单链表的数据结构上,进行单链表反转。容易出错的点在于,指针丢失,造成断链。在转换结点指针的时候,所需结点和指针反转顺序,都很重要,一不小心,就会丢掉原本的后续指针 next,导致链表断裂。

    在前面的学习中我们知道删除链表某个结点时,需要知道前后的两个结点,加上被删除结点,共计三个结点,单链表反转时也是这样的。
    当我们要对一个结点进行指针翻转的时候,我们也需要知道三个结点。

    • 待反转的结点。
    • 待反转结点的前驱结点 prev。
    • 待反转结点的后续结点 next。
      整个代码如下,可以直接复制运行。此处以头指针为参数,反转之后返回值为反转后的单链表头指针指向的结点。
    public class Test {
        static Node reverseByLoop(Node head) {
            //如果头指针为空(表示链表为空)或者头指针的next结点为空(代表仅有一个结点),这样的话直接返回即可。
            //注意这个条件仅在进入这个方法的时候判断一次,后续while循环遍历的时候不会进行head.next == null这个判断,
            //不然最后一个结点不能反转
            if (head == null || head.next == null) {
                return head;
            }
    
            Node preNode = null;
            Node nextNode = null;
            // 先记录待反转结点的后一个结点位置,避免断链,然后进行反转操作,将头结点的下一个结点设置为null,同时将当前结点和 
            //前一个结点向后移动一位
            while (head != null) {
                nextNode = head.next;
                head.next = preNode;
                preNode = head;
                head = nextNode;
            }
            return preNode;
        }
    
        public static void main(String[] args) {
            // 1、构建单链表
            Node head = new Node(0);
            Node node1 = new Node(1);
            Node node2 = new Node(2);
            Node node3 = new Node(3);
            Node node4 = new Node(4);
            Node node5 = new Node(5);
            Node node6 = new Node(6);
            head.next = node1;
            node1.next = node2;
            node2.next = node3;
            node3.next = node4;
            node4.next = node5;
            node5.next = node6;
            Node node = reverseByLoop(head);
            while (node.next!=null){
                System.out.println(node.data);
                node = node.next;
            }
    
        }
    }
    
    class Node {
        int data;
        Node next;
    
        Node(int data) {
            this.data = data;
        }
    }
    

    3.递归实现单链表反转

    递归还是在借助函数调用栈的思想,其实本质上也是一个栈。没什么好说的,直接上代码。

    static Node reverseByRecursion(Node head){
        if(head == null || head.next == null){
            return head;
        }
    
        Node newHead = reverseByRecursion(head.next);
    
        head.next.next = head;
        head.next = null;
        return newHead;
    }
    
  • 相关阅读:
    POJ 3278 Catch That Cow(BFS)
    POJ 2488 A Knight's Journey(DFS)
    POJ 2386 Lake Counting(DFS)
    迷宫问题(BFS)
    两点(DFS)
    POJ 1001 Exponentiation(大数运算)
    Java IO流01-总叙
    hdu 2065 "红色病毒"问题(快速幂求模)
    POJ 2251 Dungeon Master(BFS)
    POJ 1321 棋盘问题(DFS)
  • 原文地址:https://www.cnblogs.com/lovelywcc/p/14203827.html
Copyright © 2011-2022 走看看