链表反转

224 阅读2分钟

简介

链表反转是一种常用的操作。在JDK7的hashMap扩容中就是用到了头插法链表反转,本文主要是记录实现代码,有不理解其转换过程的请移步搜索,查看相关动画插图,帮助其理解。

代码实现

package com.pinet.rest.modular.controller.deductionCard;

/**
 * @author Y2M
 * @createTime 2021/8/4
 * @comment
 */
public class Link {

    static class Node {

        private String name;

        private Node next;

        public Node(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

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

        public Node getNext() {
            return next;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "name='" + name + ''' +
                    '}';
        }
    }

    private Node root;

    public void setRoot(Node root) {
        this.root = root;
    }

    public Node getRoot() {
        return root;
    }
}
package com.pinet.rest.modular.controller.deductionCard;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Y2M
 * @createTime 2021/8/4
 * @comment
 */
public class Test {

    private static Link link = new Link();

    //链表初始化
    static {
        Link.Node node1 = new Link.Node("1");
        Link.Node node2 = new Link.Node("2");
        Link.Node node3 = new Link.Node("3");
        Link.Node node4 = new Link.Node("4");
        Link.Node node5 = new Link.Node("5");
        node1.setNext(node2);
        node2.setNext(node3);
        node3.setNext(node4);
        node4.setNext(node5);
        link.setRoot(node1);
    }

    public static void main(String[] args) {
        //链表翻转
        flipFive(link);
        //遍历
        LinkSout(link);
    }

    //链表反转 方法一 使用额外空间
    public static void flipOne(Link link){
        if (link == null || link.getRoot().getNext() == null){
            return;
        }
        List<Link.Node> nodeList = new ArrayList<>();
        Link.Node node = link.getRoot();
        while (node!=null){
            nodeList.add(node);
            node = node.getNext();
        }
        for (int i = nodeList.size()-1; i >= 0; i--) {
            //设置头结点
            if (i == nodeList.size() - 1){
                link.setRoot(nodeList.get(i));
            }
            if (i != 0){
                nodeList.get(i).setNext(nodeList.get(i-1));
            }else {
                nodeList.get(i).setNext(null);
            }
        }
    }

    //链表反转 方法二 迭代反转链表
    public static void flipSec(Link link){
        if (link == null || link.getRoot().getNext() == null){
            return;
        }
        Link.Node beg = null;
        Link.Node mid = link.getRoot();
        Link.Node end = link.getRoot().getNext();
        while (true){
            mid.setNext(beg);
            if (end == null){
                break;
            }
            beg = mid;
            mid = end;
            end = end.getNext();
        }
        link.setRoot(mid);
    }

    //链表反转 方法三 递归反转链表
    public static Link.Node flipThird(Link.Node node){
        //递归出口
        if (node == null || node.getNext() == null){
            return node;
        }
        Link.Node cur = flipThird(node.getNext());
        node.getNext().setNext(node);
        node.setNext(null);
        return cur;
    }

    //链表反转 方法四 头插法 JDK7 hashmap 扩容就是用的这种方法
    public static void flipForth(Link link){
        Link newLink = new Link();
        while (link.getRoot() != null){
            Link.Node rootRel = link.getRoot();
            Link.Node next = rootRel.getNext();
            Link.Node root = newLink.getRoot();
            Link.Node linkRoot = link.getRoot();
            linkRoot.setNext(root);
            newLink.setRoot(linkRoot);
            link.setRoot(next);
        }
        link.setRoot(newLink.getRoot());
    }

    //链表反转 方法五 就地内置法 和头插法思想一样 区别在于 头插法是新建一个链表实现的 而就地内置则是对原数据直接进行改造
    public static void flipFive(Link link){
        if (link.getRoot() == null || link.getRoot().getNext() == null){
            return;
        }
        Link.Node beg = null;
        Link.Node end = null;
        beg = link.getRoot();
        end = link.getRoot().getNext();
        while (end!=null){
            //把end从链表摘除
            beg.setNext(end.getNext());
            //将end移动至链表头
            end.setNext(link.getRoot());
            link.setRoot(end);
            //调整 end 的指向,另其指向 beg 后的一个节点,为反转下一个节点做准备
            end = beg.getNext();
        }
    }

    public static void LinkSout(Link link){
        Link.Node root = link.getRoot();
        while (root!=null){
            System.out.println(root.toString());
            root = root.getNext();
        }
    }

}