题目描述:给定一个链表,翻转该链表从m到n的位置。要求:直接翻转而非申请新的空间;
如:给定1–>2–>3–>4–>5,m=2,n=4;m,n满足1<=m<=n<=链表长度;
返回1–>4–>3–>2–>5
算法思路:根据 m 和 n 的值,找到并使 head 指向待翻转链表起始位置的前一个结点,pre 指向起始位置结点保持不变,cur 指向 pre 的 next 结点,每次循环使得 cur 所指结点采用头插法插入到 head 所指结点的后面,cur 和 next 向后指向下一个结点,直到循环结束;
根据 reverse() 函数的传入值,也可以实现翻转链表前半部分或者后半部分;需要获取链表的长度;
流程如下图所示,画的有点粗糙,若是动图能更好的演示这个过程;
代码如下所示:
// 链表结点的结构
public class Node {
public int value; // 结点值
public Node next; // 结点的next
public Node() {}
public Node(int value) {
this.value = value;
}
}
import java.util.Random;
import java.util.Scanner;
public class ReverseLink {
public static void main(String[] args) {
int m, n; // 输入要改变部分的链表起始位置和结束位置
int len = 0;
int mid = 0; // 若是从中间翻转,需先求出中间结点的位置
// 生成0~100内的随机数
Random random = new Random(100);
// 初始化一个单链表,头结点为空
Node head = new Node();
Node pre = head;
for (int i = 0; i < 20; i++) {
Node node = new Node(random.nextInt(100));
pre.next = node; // 尾插法构建链表
pre = node;
}
System.out.print("原链表:");
print(head.next);
len = getLinkedLength(head);
if(len % 2 == 1) {
mid = (1 + len) / 2;
} else {
mid = len / 2;
}
System.out.println("翻转链表的范围m和n:");
Scanner sc = new Scanner(System.in);
m = sc.nextInt();
n = sc.nextInt();
System.out.println("m = " + m + " n = " + n);
// 翻转链表
reverse(head, m, n);
// 若是想翻转链表的前半部分或者后半部分,由mid值传入合适参数即可
// reverse(head, mid+1, len);
System.out.print("翻转之后的链表:");
print(head.next);
}
/**
* 打印输出链表的结点值
*/
public static void print(Node head) {
while (head != null) {
System.out.print(head.value + " ");
head = head.next;
}
System.out.println();
}
/**
* 获取链表的长度
*/
public static int getLinkedLength(Node head) {
int len = 0;
while(head.next != null) {
len++;
head = head.next;
}
return len;
}
/**
* 翻转链表的从结点m到结点n的部分
*
* @param head 连标点额头结点
* @param m 翻转的开始位置
* @param n 翻转的结束位置
* @return 翻转后的新链表
*/
public static void reverse(Node head, int from, int to) {
if (from >= to) return;
Node cur = head.next;
int i;
for (i = 0; i < from - 1; i++) {
head = cur;
cur = cur.next;
}
Node pre = cur;
cur = cur.next;
to--;
Node next;
for (; i < to; i++) {
next = cur.next;
cur.next = head.next; // 采用头插法
head.next = cur;
pre.next = next;
cur = next;
}
}
}
运行示例:
若是翻转链表的前半部分或者后半部分,可以根据mid参数的值,给 reverse() 传入合适的参数,即可实现翻转链表的前半部分或者后半部分;
翻转链表前半部分运行示例:
翻转链表后半部分运行示例: