链表基础知识 参考代码随想录 (programmercarl.com)
链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。链表的入口节点称为链表的头结点也就是head。
链表的类型:
单链表(如上图所示):单链表中的指针域只能指向节点的下一个节点。
双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。既可以向前查询也可以向后查询。
循环链表:链表首尾相连,可以用来解决约瑟夫环问题。
数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。各个节点分布在内存的不同地址空间上,通过指针串联在一起。
基本定义方式:
public class ListNode {
// 结点的值
int val;
// 下一个结点
ListNode next;
// 节点的构造函数(无参)
public ListNode() {
}
// 节点的构造函数(有一个参数)
public ListNode(int val) {
this.val = val;
}
// 节点的构造函数(有两个参数)
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
203移除链表元素
关键点:因为移除头节点和其他节点的方式有些区别,因此通过引入虚拟头节点,将原链表的所有节点按照统一的方式进行移除
遍历条件是 cur
不为 null
,即还没有遍历到链表末尾
- 检查当前节点
cur
的值是否等于目标值val
。 - 如果是,则跳过当前节点,将
pre
的next
指向cur
的下一个节点cur.next
,相当于删除了当前节点cur
。 - 如果当前节点的值不等于
val
,则前一个节点pre
向前移动,变为当前节点cur
,继续向下遍历。 cur
指针始终向后移动,遍历链表的下一个节点。
当遍历完成后,返回虚拟头节点 dummy
的 next
,即处理后的链表头节点(可能与原始 head
相同或不同,取决于是否移除了头节点)。
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummy = new ListNode(-1,head);
ListNode pre = dummy;
ListNode cur =head;
while(cur!=null){
if(cur.val == val){
pre.next = cur.next;
} else {
pre =cur;
}
cur = cur.next;
}
return dummy.next;
}
}
707 设计链表 比较麻烦
设计链表的五个接口:
- 获取链表第index个节点的数值
- 在链表的最前面插入一个节点
- 在链表的最后面插入一个节点
- 在链表第index个节点前面插入一个节点
- 删除链表的第index个节点
class MyLinkedList {
int size;
ListNode head;
public MyLinkedList() {
size = 0;
head = new ListNode(0);
}
public int get(int index) {
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);
}
public void addAtIndex(int index, int val) {
if(index>size){
return;
}
if(index<0){
index=0;
}
ListNode pred = head;
for(int i=0; i<index; i++){
pred = pred.next;
}
ListNode add = new ListNode(val);
add.next = pred.next;
pred.next = add;
size++;
}
public void deleteAtIndex(int index) {
if(index<0 || index>= size){
return;
}
ListNode pred = head;
for(int i=0; i<index; i++){
pred = pred.next;
}
pred.next = pred.next.next;
size--;
}
}
206 反转链表 高频考点
递归法或双指针法
递归法
class Solution {
public ListNode reverseList(ListNode head) {
return reverse(null, head);
}
private ListNode reverse(ListNode prev, ListNode cur){
if(cur == null){
return prev;
}
ListNode temp = null;
temp = cur.next;
cur.next = prev;
return reverse(cur, temp); //递归法,这句的位置要对
}
}
双指针法(更巧妙)
class Solution {
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode cur = head;
ListNode temp = null;
while (cur != null) {
temp = cur.next;// 保存下一个节点
cur.next = prev;
prev = cur;
cur = temp;
}
return prev;
}
}