携手创作,共同成长!这是我参与「掘金日新计划 · 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;
}
原地逆置
- 遍历整个链表,当链表不为空时,取链表的第一个node为当前节点,
- 修改当前node的指针,
- 通过指针操作进行链表节点的原地逆置。
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)