对于链表反转,我自己先想到的就是建立一个栈,因为栈是先进后出的一个数据结构,那我们遍历整个链表,把元素存储在栈当中,然后再创建一个链表放入元素就可以了,但是仔细想想运行内存和速度其实都比较慢,因为先开辟出了两个新的空间。
那对于新学的有很多方法
一、建立虚拟头结点辅助反转
public static ListNode reverseListByDummyNotCreate(ListNode head) {
ListNode ans = new ListNode(-1);
ListNode cur = head;
while (cur != null) {
ListNode next = cur.next;
cur.next = ans.next;
ans.next = cur;
cur = next;
}
return ans.next;
}
虚拟头结点呢,顾名思义就是建立一个虚拟的头结点,作为反转链表的头结点,再将旧链表当中的节点逐个放进新的链表当中。当中我自己最有异议的地方就是为什么要创建一个新的节点next来存放cur.next,实际上cur.next在下面的代码中变换了内容,把头结点的next赋给cur的next,然后将ans的next变为cur,这样就实现的了cur节点插入新的链表,这时要把cur进行移动,如果没有next这个节点,cur没有办法移动,这样我们next节点的作用就实现出来了。
二、直接操作链表实现反转
public static ListNode reverseListSimple(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
直接操作反转链表跟虚拟头结点,我个人认为两者之间的不同不是特别的大,而是用了虚拟头结点之后,代码会非常容易的理解。还是先把curr的next提取出来命名为next,然后把prev赋给curr。next,这里呢prev永远会在插入节点的后一个位置,再把curr赋给prev,这时就插入了第一个节点了,curr这个节点是代指远链表的第一个节点,老头结点走了,那就得赋给新的头结点。
我个人的见解是,虚拟头结点呢,是一直在头结点后面插入节点,对于链表来说这是非常好理解的,因为链表本就是一个有顺序的结构。而直接操作呢,是第一个节点前插入节点,一直在头部插入节点,思维更加的抽象,所以比较难想。