链表
LinkedList
Collections中的链表
- 不能随机访问
- 在内存中的存储空间不是连续的
- 线程不安全
LinkedList常用方法
LinkedList
是 Java 中的一个双向链表实现,它实现了 List
和 Deque
接口,因此它既可以作为一个列表使用,也可以作为一个双端队列使用。以下是一些 LinkedList
的常用方法:
- 添加元素:
add(E e)
: 在链表末尾添加一个元素。add(int index, E element)
: 在指定位置插入一个元素。addFirst(E e)
: 在链表头部添加一个元素。addLast(E e)
: 在链表末尾添加一个元素(与add(E e)
相同)。
- 获取元素:
get(int index)
: 返回指定位置的元素。getFirst()
: 返回链表头部的元素。getLast()
: 返回链表尾部的元素。
- 删除元素:
remove(Object o)
: 移除列表中第一次出现的指定元素。remove(int index)
: 移除指定位置的元素并返回它。removeFirst()
: 移除并返回链表头部的元素。removeLast()
: 移除并返回链表尾部的元素。
- 修改元素:
set(int index, E element)
: 用指定元素替换列表中指定位置的元素。
- 查找位置:
indexOf(Object o)
: 返回列表中第一次出现的指定元素的索引。lastIndexOf(Object o)
: 返回列表中最后一次出现的指定元素的索引。
- 大小和容量:
size()
: 返回列表中的元素个数。
- 队列操作(因为实现了
Deque
接口):offer(E e)
: 在队列末尾添加一个元素。offerFirst(E e)
: 在队列头部添加一个元素。offerLast(E e)
: 在队列末尾添加一个元素(与offer(E e)
相同)。poll()
: 移除并返回队列头部的元素。pollFirst()
: 移除并返回队列头部的元素(与poll()
相同)。pollLast()
: 移除并返回队列尾部的元素。peek()
: 返回队列头部的元素但不移除它。peekFirst()
: 返回队列头部的元素但不移除它(与peek()
相同)。peekLast()
: 返回队列尾部的元素但不移除它。
- 列表迭代:
listIterator()
: 返回列表迭代器。listIterator(int index)
: 返回从指定位置开始的列表迭代器。
- 克隆和序列化:
clone()
: 返回列表的浅拷贝。toArray()
: 返回包含列表中所有元素的数组。toArray(T[] a)
: 返回包含列表中所有元素的数组,元素类型为数组参数指定的类型。
- 其他:
clear()
: 移除列表中的所有元素。contains(Object o)
: 检查列表是否包含指定元素。isEmpty()
: 检查列表是否为空。
LinkedList
由于其内部实现为链表,因此在进行头部或尾部的添加和删除操作时非常高效。然而,由于需要遍历链表来定位元素,所以随机访问的性能不如基于数组实现的 ArrayList
。因此,在选择使用 LinkedList
还是 ArrayList
时,需要根据实际的应用场景和性能需求来决定。
###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;
ListNode dummy = new ListNode(0,head);
ListNode p = dummy;
ListNode q = head;
while(p != null && p.next != null){
while((q != null && q.val == val)){//先移动指针q到下一个节点值不是val的节点
q = q.next;
}
p.next = q;//移动指针q
p = p.next;
if(q != null)q = q.next;
}
return dummy.next;
}
}
###707. 设计链表
使用Collections
class MyLinkedList {
List<Integer> list;
public MyLinkedList() {
list = new ArrayList<>();
}
public int get(int index) {
if (index < list.size()) {
return list.get(index);
}
return -1;
}
public void addAtHead(int val) {
list.add(0, val);
}
public void addAtTail(int val) {
list.add(val);
}
public void addAtIndex(int index, int val) {
if (index <= list.size()) {
list.add(index, val);
}
}
public void deleteAtIndex(int index) {
if (index < list.size()) {
list.remove(index);
}
}
}
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList obj = new MyLinkedList();
* int param_1 = obj.get(index);
* obj.addAtHead(val);
* obj.addAtTail(val);
* obj.addAtIndex(index,val);
* obj.deleteAtIndex(index);
*/
使用节点
//单链表
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);
}
//获取第index个节点的数值,注意index是从0开始的,第0个节点就是头结点
public int get(int index) {
//如果index非法,返回-1
if (index < 0 || index >= size) {
return -1;
}
ListNode currentNode = head;
//包含一个虚拟头节点,所以查找第 index+1 个节点
for (int i = 0; i <= index; i++) {
currentNode = currentNode.next;
}
return currentNode.val;
}
//在链表最前面插入一个节点,等价于在第0个元素前添加
public void addAtHead(int val) {
addAtIndex(0, val);
}
//在链表的最后插入一个节点,等价于在(末尾+1)个元素前添加
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 pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
ListNode toAdd = new ListNode(val);
toAdd.next = pred.next;
pred.next = toAdd;
}
//删除第index个节点
public void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
size--;
if (index == 0) {
head = head.next;
return;
}
ListNode pred = head;
for (int i = 0; i < index ; i++) {
pred = pred.next;
}
pred.next = pred.next.next;
}
}
206. 反转链表
使用临时节点,暂存 指针反转前的状态。
/**
* 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 reverseList(ListNode head) {
if(head == null || head.next == null) return head;
ListNode cur = head;
ListNode prev = null;
ListNode temp= null;
while(cur != null){
temp = cur.next;
cur.next = prev;
prev = cur;
cur = temp;
}
return prev;
}
}