前提
链表是多个不一定连续的内存块(节点),通过节点保存的后置指针或前置指针串联起来的一种数据结构;
链表不支持随机访问;
下面的反转链表没有特别提示的都是带头链表(引入了哨兵的链表),用java实现,节点类如下:
/**
* @Author Haoqi
* @Description 链表节点
**/
Class Node{
int data;
Node next;
/**
* 构造哨兵节点
**/
public Node() {
this.data = -1;
this.next = null;
}
//其他构造方法
//...
}
两种实现
原地反转
通过指针的变化,在链表自身进行反转,不会产生另外一个新链表;
public static Node reverseLinkList(Node head){
if(head.next == null){
return head;
}
Node prev = head.next;
Node pcur = prev.next;
while(pcur != null){
prev.next = pcur.next;
pcur.next = head.next;
head.next = pcur;
pcur = prev.next;
}
return head;
}
- head节点是哨兵节点,不存数据只是,只是为了简化代码;
- 第一个判断看链表是否为空链表,即除了哨兵没有其他数据节点;
- 实现需要两个指针,一个前置指针 prev ,一个移动指针pcur;
- 循环结束条件是移动指针为null;
- 注意指针操作顺序防止指针丢失,这里可以逐步画图演示,辅助理解;
- pcur指针指向的是下次循环结束后的第一个数据节点 head.next = pcur;
- 最后pcur向后移动,但每次循环开始结束prev一直是pcur的前置节点;
- 时间复杂度O(n)
头插法反转
顾名思义,遍历旧链表,反复向新链表的第一个节点位置插入,产生的新链表就是旧链表的反转;
public static Node reverseLinkList(Node head){
if(head.next == null){
return head;
}
Node newHead = new Node();
Node pcur = head.next;
Node curNextTmp = null;
while(pcur != null){
curNextTmp = pcur.next;
pcur.next = newHead.next;
newHead.next = pcur;
pcur = curNextTmp;
}
return newHead;
}
- head节点是哨兵节点,不存数据只是,只是为了简化代码;
- 第一个判断看链表是否为空链表,即除了哨兵没有其他数据节点;
- 实现需要新建一个带头空链表newHead,一个移动指针pcur和一个缓存curNextTmp;
- 循环结束条件是移动指针为null;
- 每次循环,先将pcur的后续节点缓存起来,然后再向新链表第一个数据节点处插入pcur(头插),最后将pcur移到缓存的后续节点;
- 时间复杂度为O(n)
熄灯
怎么写出正确的链表?画图理解记忆,再多默写几次就行。
本文深入讲解链表数据结构,探讨两种链表反转方法:原地反转与头插法。通过Java代码实现,详细解析每种方法的工作原理及指针操作技巧。
749

被折叠的 条评论
为什么被折叠?



