今天群里大佬给我抛出了一个问题,单链表反转。
非常仁慈的给了我10分钟的时间,结果我连链表的数据结构都没写完,果然我还是太菜了。

虽说我也是看过数据结构的,但是一,时间有点久了;二,当时看的时候就没怎么写代码。

所以欠的债要还,硬着头皮也要写。

最开始我就冒出了一个想法,及其幼稚,思路就是从链表中取值,然后把所有值在外部排序完,再放回链表中,但是我一看这根本就是离题了啊!可是暂时没有什么别的想法,想着写写试试吧,结果发现这么写好像也挺麻烦的,就放弃了。

然后也想过递归方式实现,但是我还是太年轻了,对于递归理解的不是很到位,当时认为使用递归的话,不好找前一个节点,这样就没办法设置当前节点的下一个节点。

总之,我还是百度了,看了下思路。

两种方法:递归遍历

下面的方法参考了文章:点这里

递归

首先是递归

public static SingleLinkedListNode reversal(SingleLinkedListNode node){
        if (node == null || node.next == null){
            return node;
        }else {
            SingleLinkedListNode headNode = reversal(node.next);
            node.next.next = node;
            node.next = null;
            return headNode;
        }
    }

public static SingleLinkedListNode reversal(SingleLinkedListNode node){
        if (node == null || node.next == null){
            return node;
        }else {
            SingleLinkedListNode headNode = reversal(node.next);
            node.next.next = node;
            node.next = null;
            return headNode;
        }
    }

思路就是从最后一个节点开始,向前反转。
这里有一个比较关键的点,也是我之前以为递归行不通的症结就是:递归会入栈,而栈中保存了节点所有信息,并且不是设置当前节点的下一节点为前一节点,而是设置当前节点的下一节点的next为当前节点。

遍历

接着是遍历法

public static SingleLinkedListNode reversal2(SingleLinkedListNode node){
        SingleLinkedListNode previousNode = null;
        SingleLinkedListNode currentNode = node;
        SingleLinkedListNode headNode = null;

        while (currentNode != null){
            SingleLinkedListNode nextNode = currentNode.next;
            if (nextNode == null){
                headNode = currentNode;
            }
            currentNode.next = previousNode;
            previousNode = currentNode;
            currentNode = nextNode;
        }
        return headNode;
    }

public static SingleLinkedListNode reversal2(SingleLinkedListNode node){
        SingleLinkedListNode previousNode = null;
        SingleLinkedListNode currentNode = node;
        SingleLinkedListNode headNode = null;

        while (currentNode != null){
            SingleLinkedListNode nextNode = currentNode.next;
            if (nextNode == null){
                headNode = currentNode;
            }
            currentNode.next = previousNode;
            previousNode = currentNode;
            currentNode = nextNode;
        }
        return headNode;
    }

这里的思路是从前往后反转,每经过一个节点,就将当前节点的next进行反转,指向之前的节点。

遍历另一版

我这里自己思考实现了另一版,但是没有上面那个优雅,且考虑的不够全面

public static SingleLinkedListNode reversal3(SingleLinkedListNode node){
        SingleLinkedListNode previousNode = null;
        SingleLinkedListNode currentNode = node;
        SingleLinkedListNode nextNode = null;

        while (currentNode.next != null){
            nextNode = currentNode.next;
            currentNode.next = previousNode;
            previousNode = currentNode;
            currentNode = nextNode;
        }
        currentNode.next = previousNode;
        return currentNode;
    }

public static SingleLinkedListNode reversal3(SingleLinkedListNode node){
        SingleLinkedListNode previousNode = null;
        SingleLinkedListNode currentNode = node;
        SingleLinkedListNode nextNode = null;

        while (currentNode.next != null){
            nextNode = currentNode.next;
            currentNode.next = previousNode;
            previousNode = currentNode;
            currentNode = nextNode;
        }
        currentNode.next = previousNode;
        return currentNode;
    }

虽然运行起来的时候没什么问题,但是我在考虑的时候确实忽略了入参链表为空的情况的。

完整代码

完整代码如下

/**
 * @Auther: yubt
 * @Description: 单链表反转
 * @Date: Created in 11:04 2018/9/27
 * @Modified By:
 */
public class Reversal_linkedList {

    private static class SingleLinkedListNode {
        private int data;
        private SingleLinkedListNode next;
        
        public int getData() {
            return data;
        }

        public void setData(int data) {
            this.data = data;
        }

        public SingleLinkedListNode getNext() {
            return next;
        }

        public void setNext(SingleLinkedListNode next) {
            this.next = next;
        }

        @Override
        public String toString() {
            return "SingleLinkedListNode{" +
                    "data=" + data +
                    ", next=" + next +
                    '}';
        }
    }

    // 递归法
    // 运行正常,debug会栈溢出,因为toString()方法
    public static SingleLinkedListNode reversal(SingleLinkedListNode node){
        if (node == null || node.next == null){
            return node;
        }else {
            SingleLinkedListNode headNode = reversal(node.next);
            node.next.next = node;
            node.next = null;
            return headNode;
        }
    }

    // 遍历法
    public static SingleLinkedListNode reversal2(SingleLinkedListNode node){
        SingleLinkedListNode previousNode = null;
        SingleLinkedListNode currentNode = node;
        SingleLinkedListNode headNode = null;

        while (currentNode != null){
            SingleLinkedListNode nextNode = currentNode.next;
            if (nextNode == null){
                headNode = currentNode;
            }
            currentNode.next = previousNode;
            previousNode = currentNode;
            currentNode = nextNode;
        }
        return headNode;
    }

    public static SingleLinkedListNode reversal3(SingleLinkedListNode node){
        SingleLinkedListNode previousNode = null;
        SingleLinkedListNode currentNode = node;
        SingleLinkedListNode nextNode = null;

        while (currentNode.next != null){
            nextNode = currentNode.next;
            currentNode.next = previousNode;
            previousNode = currentNode;
            currentNode = nextNode;
        }
        currentNode.next = previousNode;
        return currentNode;
    }

    public static void main(String[] args) {
        SingleLinkedListNode node1 = new SingleLinkedListNode();
        node1.setData(1);
        SingleLinkedListNode node2 = new SingleLinkedListNode();
        node2.setData(2);
        SingleLinkedListNode node3 = new SingleLinkedListNode();
        node3.setData(3);
        SingleLinkedListNode node4 = new SingleLinkedListNode();
        node4.setData(4);
        SingleLinkedListNode node5 = new SingleLinkedListNode();
        node5.setData(5);

        node1.setNext(node2);
        node2.setNext(node3);
        node3.setNext(node4);
        node4.setNext(node5);

//        System.out.println(node1);

//        SingleLinkedListNode reversalNode = reversal(node1);
//        System.out.println(reversalNode);

//        SingleLinkedListNode reversalNode2 = reversal2(node1);
//        System.out.println(reversalNode2);

        SingleLinkedListNode reversalNode3 = reversal3(node1);
        System.out.println(reversalNode3);
    }
}


/**
 * @Auther: yubt
 * @Description: 单链表反转
 * @Date: Created in 11:04 2018/9/27
 * @Modified By:
 */
public class Reversal_linkedList {

    private static class SingleLinkedListNode {
        private int data;
        private SingleLinkedListNode next;
        
        public int getData() {
            return data;
        }

        public void setData(int data) {
            this.data = data;
        }

        public SingleLinkedListNode getNext() {
            return next;
        }

        public void setNext(SingleLinkedListNode next) {
            this.next = next;
        }

        @Override
        public String toString() {
            return "SingleLinkedListNode{" +
                    "data=" + data +
                    ", next=" + next +
                    '}';
        }
    }

    // 递归法
    // 运行正常,debug会栈溢出,因为toString()方法
    public static SingleLinkedListNode reversal(SingleLinkedListNode node){
        if (node == null || node.next == null){
            return node;
        }else {
            SingleLinkedListNode headNode = reversal(node.next);
            node.next.next = node;
            node.next = null;
            return headNode;
        }
    }

    // 遍历法
    public static SingleLinkedListNode reversal2(SingleLinkedListNode node){
        SingleLinkedListNode previousNode = null;
        SingleLinkedListNode currentNode = node;
        SingleLinkedListNode headNode = null;

        while (currentNode != null){
            SingleLinkedListNode nextNode = currentNode.next;
            if (nextNode == null){
                headNode = currentNode;
            }
            currentNode.next = previousNode;
            previousNode = currentNode;
            currentNode = nextNode;
        }
        return headNode;
    }

    public static SingleLinkedListNode reversal3(SingleLinkedListNode node){
        SingleLinkedListNode previousNode = null;
        SingleLinkedListNode currentNode = node;
        SingleLinkedListNode nextNode = null;

        while (currentNode.next != null){
            nextNode = currentNode.next;
            currentNode.next = previousNode;
            previousNode = currentNode;
            currentNode = nextNode;
        }
        currentNode.next = previousNode;
        return currentNode;
    }

    public static void main(String[] args) {
        SingleLinkedListNode node1 = new SingleLinkedListNode();
        node1.setData(1);
        SingleLinkedListNode node2 = new SingleLinkedListNode();
        node2.setData(2);
        SingleLinkedListNode node3 = new SingleLinkedListNode();
        node3.setData(3);
        SingleLinkedListNode node4 = new SingleLinkedListNode();
        node4.setData(4);
        SingleLinkedListNode node5 = new SingleLinkedListNode();
        node5.setData(5);

        node1.setNext(node2);
        node2.setNext(node3);
        node3.setNext(node4);
        node4.setNext(node5);

//        System.out.println(node1);

//        SingleLinkedListNode reversalNode = reversal(node1);
//        System.out.println(reversalNode);

//        SingleLinkedListNode reversalNode2 = reversal2(node1);
//        System.out.println(reversalNode2);

        SingleLinkedListNode reversalNode3 = reversal3(node1);
        System.out.println(reversalNode3);
    }
}

所以这些基础的东西还是要时不时就回顾一下,不会就赶紧补,有遗忘就复习,总之要夯实基础,虽然工作中不太可能用的上,但是只会业务逻辑,天天增删改查也太low了吧。。。

附加题

结果大佬又提了一个问题,存心搞我。

说存在 0 <= m < n <= ll为链表长度,然后要反转mn之间的部分。

吭呲瘪肚一下午,写了一坨勉强能用的吧

// m,n 从0起
    public static SingleLinkedListNode specialReversal(SingleLinkedListNode node, int m, int n){
        SingleLinkedListNode headNode = node;
        SingleLinkedListNode beforeM = node;
        SingleLinkedListNode afterM = null;
        SingleLinkedListNode mBetweenN = null;
        SingleLinkedListNode afterN = null;
        if (m == 0){
            beforeM = null;
            afterM = node;
        }else {
            // 截断m处的节点
            for (int i = 0; node != null; i++) {
                // 操作next节点偏移量+1
                if (i + 1 == m) {
                    afterM = node.next;
                    node.next = null;
                }
                node = node.next;
            }
        }
        // 截断n处节点,并获得m和n之间的链表
        mBetweenN = afterM;
        for (int j = 0; j < n - m; j++){
            afterM = afterM.next;
        }
        afterN = afterM.next;
        afterM.next = null;
        // 对m和n间的链表进行反转
        SingleLinkedListNode reversalMN = reversal2(mBetweenN);
        // 将n之后的链表连接回来
        SingleLinkedListNode tmp = reversalMN;
        while (reversalMN.next != null){
            reversalMN = reversalMN.next;
        }
        reversalMN.next = afterN;
        if (m != 0) {
            // 将m之前的链表连接回来
            while (beforeM.next != null) {
                beforeM = beforeM.next;
            }
            beforeM.next = tmp;
        }else {
            // 由于m为0,无链表,所以直接替换头部节点
            headNode = tmp;
        }
        // 返回头部节点
        return headNode;
    }

// m,n 从0起
    public static SingleLinkedListNode specialReversal(SingleLinkedListNode node, int m, int n){
        SingleLinkedListNode headNode = node;
        SingleLinkedListNode beforeM = node;
        SingleLinkedListNode afterM = null;
        SingleLinkedListNode mBetweenN = null;
        SingleLinkedListNode afterN = null;
        if (m == 0){
            beforeM = null;
            afterM = node;
        }else {
            // 截断m处的节点
            for (int i = 0; node != null; i++) {
                // 操作next节点偏移量+1
                if (i + 1 == m) {
                    afterM = node.next;
                    node.next = null;
                }
                node = node.next;
            }
        }
        // 截断n处节点,并获得m和n之间的链表
        mBetweenN = afterM;
        for (int j = 0; j < n - m; j++){
            afterM = afterM.next;
        }
        afterN = afterM.next;
        afterM.next = null;
        // 对m和n间的链表进行反转
        SingleLinkedListNode reversalMN = reversal2(mBetweenN);
        // 将n之后的链表连接回来
        SingleLinkedListNode tmp = reversalMN;
        while (reversalMN.next != null){
            reversalMN = reversalMN.next;
        }
        reversalMN.next = afterN;
        if (m != 0) {
            // 将m之前的链表连接回来
            while (beforeM.next != null) {
                beforeM = beforeM.next;
            }
            beforeM.next = tmp;
        }else {
            // 由于m为0,无链表,所以直接替换头部节点
            headNode = tmp;
        }
        // 返回头部节点
        return headNode;
    }

我的思路是把mn之间的链表截断出来,然后反转之后再接回去。

大佬的思路呢,是直接对mn之间的节点进行交换,比我这个简单

把他的代码贴出来把

val dummy = new ListNode(0)
    dummy.next = head
    var pre = dummy
    for (_ <- 0 until m - 1)
      pre = pre.next
    val start = pre.next
    var tail = start.next
    for (_ <- 0 until n - m) {
      start.next = tail.next
      tail.next = pre.next
      pre.next = tail
      tail = start.next
    }
    dummy.next

先这样吧。