单链表反转以及对象作为参数的问题

69 阅读2分钟

链表的局部反转题目

  1. 题目描述:给定一个单链表,和指定的长度 k,将链表内 k 长度的节点进行反转;
  2. 节点类
public class Node {
    public int value;
    public Node next;

    public Node(int value) {
        this.value = value;
    }
}
  1. 主方法
public static Node reverseGroup(Node head, int k){
    if(head==null){
        return head;
    }
    // 先单独处理第一次反转,获取k个长度后的末尾节点
    Node end = getKLength(head, k);
    if(end==null){
        return head;
    }
    Node start = head;
    // 第一次反转,是为了获取反转后,新的头结点
    reverse(start,end);
    head = end;
    Node lastListNode = start;
    while(lastListNode.next!=null){
        start = lastListNode.next;
        end = getKLength(start,k);
        if(end==null){
            return head;
        }
        reverse(start,end);
        lastListNode.next = end;
        lastListNode = start;
    }
    return head;
}

通过一些图辅助说明

第一次反转.png

image.png 4. 辅助方法:获取 k 长度内的最末尾节点

// 比如1-3-5-7-9 k=3,那么返回的是5这个节点
public static Node getKLength(Node start, int k){
    while(--k!=0 && start!=null){
        start = start.next;
    }
    return start;
}
  1. 辅助方法:给定局部链表的头节点和尾节点,进行反转
/**
  实现功能:反转局部单链表,以及将反转后的单链表,链接上后面的节点
 1,2,3,4,5,6,7 原始顺序,k=3
 3,2,1,4,5,6,7 第一次反转后的顺序
 3,2,1,6,5,4,7 第二次反转后的顺序
*/
public static void reverse(Node start, Node end){
    end = end.next;
    Node cur = start;
    Node pre = null;
    Node next = null;
    while(cur!=end){
        next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = next;
    }
    // 将反转后的新尾节点,链到主链表剩余节点的第一个节点上
    start.next = end;
}
  1. 为什么reverse 方法中执行end = end.next ,在主方法中,还可以将end作为头结点呢?

逻辑应该是这样的,对象被创建后是存在于堆区的,而方法的参数是在虚拟机栈中的某个栈帧的局部变量表中,所以在方法中的end其实是一个引用,它指向堆区的对象;当执行end = end.next 只是表示end这个变量指向新的目标,并未修改原对象。我们在平常业务开发中,很少遇到类似的场景,所以下意识的认为end = end.next 改变了原始end对象。