反转链表

52 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

自定义链表结构

public class ListNode{

    /**
     * 节点数据
     */
    public int value;
    /**
     * 下一个节点对象,在Java中没有指针
     */
    public ListNode next;
    /**
     * 构造函数
     */
    public ListNode(int value) {
        this.value = value;
    }

}

对链表的crud


public static ListNode addNode(){

    // 声明一个变量在移动过程中指向当前节点
    ListNode nextNode;
    // 创建首节点
    ListNode head = new ListNode (1);
    // 指向首节点
    nextNode = head;
    for (int i = 10; i < 15; i++) {
        // 创建一个新节点,并连接这个
        nextNode.next = new ListNode (i);
        // 当前节点往后移动
        nextNode = nextNode.next;
    }
    // 重新賦值指向首节点
    nextNode = head;
    print(nextNode);
    return head;
}

public static void print(ListNode node){
    while (node.next != null){
        System.out.println(node.value);
        node = node.next;
    }
}

递归调用反转

public static ListNode 递归(ListNode node) {
    // 终止条件和终止方法
    if (node == null || node.next == null) {
        return node;
    }
    // 把node替换为node.next继续向下寻找
    ListNode new_node = 递归(node.next);
    // 反转指针:每一个节点都执行此操作
    // node.next指向newNode,所以修改后回同步改变
    node.next.next = node;
    // 不用担心断开,因为后续步骤都会为node.next赋值,当前步骤保持为null就好
    node.next = null;
    return new_node;

}

原地逆置

image.png

  1. 遍历整个链表,当链表不为空时,取链表的第一个node为当前节点,
  2. 修改当前node的指针,
  3. 通过指针操作进行链表节点的原地逆置。
public static ListNode 迭代逆置(ListNode current) {
    ListNode previous = null;

    ListNode next;

    while (current != null) {
        // 保存后置节点
        next = current.next;
        // 把当前节点断开拼接上前驱节点
        current.next = previous;
        // 把当前已断开的节点数据保存为前驱节点
        previous = current;
        // 原后置节点的值改为当前节点
        current = next;

    }
    return previous;
}

头插法

public static ListNode 头插法(ListNode head) {
    if (head.next == null || head.next.next == null) {
        return null;
    }
    ListNode temp = new ListNode(-1);
    // 保持原链表
    temp.next = head;
    // 前驱节点
    ListNode previous = temp.next;
    // 当前节点
    ListNode current = previous.next;
    while (current != null) {
        // 往前移动一格
        previous.next = current.next;
        current.next = temp.next;
        temp.next = current;
        current = previous.next;
    }
    return temp.next;
}

头插法和原地逆置代码非常相似,区别在于头插法引入了一个临时头节点

测试

这三种方法时间复杂度和空间复杂度都在O(n)