为什么要用进行cur=vrNode赋值且返回的是vrNode.next?
因为进行操作完,链表已经发生改变且cur值在进行操作已经发生改变,而vrNode.next一直是头节点
为什么要用虚拟头节点?
这样方便处理删除实际头结点的逻辑
什么时候用虚拟头节点?
虚拟头节点一般用于删除元素用的,用来处理头节点删除逻辑
203.移除链表元素
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head == null)return head;
//设置一个虚拟头节点来处理第一位头节点 就无需处理头节点是目标值以及头节点后面连续是目标值 虚拟头节点不动永远指向头节点,pre代替虚拟节点进行遍历
ListNode vrNode = new ListNode(0);
vrNode.next = head;
ListNode pre = vrNode;
ListNode cur = head;
//遍历头节点找出等于目标值节点跳过
while(cur != null){
if(cur.val == val){
pre.next = cur.next;
}else{
//前置节点前进
pre = cur;
}
cur = cur.next;
}
return vrNode.next;
}
}
206.反转链表
双指针 pre cur temp
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* temp; // 保存cur的下一个节点
ListNode* cur = head;
ListNode* pre = NULL;
while(cur) {
temp = cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next
cur->next = pre; // 翻转操作
// 更新pre 和 cur指针
pre = cur;
cur = temp;
}
return pre;
}
};
707.设计链表
//单链表 链表节点类
class ListNode{
int val;
ListNode next;
ListNode(){};
ListNode(int val){
this.val = val;
}
}
class MyLinkedList {
//size链表中存储节点个数
int size;
//虚拟头节点
ListNode head;
//初始化链表
public MyLinkedList() {
size = 0;
head = new ListNode(0);
}
public int get(int index) {
//如果index违法 返回-1
if(index < 0 || index >= size){
return -1;
}
ListNode cur = head;
for(int i =0;i <= index;i++){
cur = cur.next;
}
return cur.val;
}
public void addAtHead(int val) {
addAtIndex(0,val);
}
public void addAtTail(int val) {
addAtIndex(size,val);
}
// 在第 index 个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
// 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点
// 如果 index 大于链表的长度,则返回空
public void addAtIndex(int index, int val) {
if(index > size) return;
if(index < 0){
index = 0;
}
size++;
ListNode pre = head;
//找到要插入节点的前驱
for(int i=0;i< index;i++){
pre = pre.next;
}
//创建插入节点
ListNode addNode = new ListNode(val);
addNode.next = pre.next; //先将后驱节点重新赋值
pre.next = addNode;
}
public void deleteAtIndex(int index) {
//index == size 越界
if(index < 0 || index >= size)return;
size--;
//如果index = 0 表示删除头节点
if(index == 0){
head = head.next;
return;
}
ListNode pre = head;
//找到删除位置的前驱节点
for(int i=0;i<index; i++){
pre = pre.next;
}
pre.next = pre.next.next;
}
}