1. 链表特点:
2. 时间复杂度:
随机访问性能
根据 index 查找,时间复杂度 O(n)
插入或删除性能
-
起始位置:O(1)
-
结束位置:如果已知 tail 尾节点是 O(1),不知道 tail 尾节点是 O(n)
-
中间位置:根据 index 查找时间 + O(1)
3. 单链表实现容器:
package com.nami.algorithm.study.day04;
import java.io.Serializable;
import java.util.Iterator;
import java.util.function.Consumer;
/**
* 单向链表
* 非线程安全
* beyond u self and trust u self.
*
* @Author: lbc
* @Date: 2023-09-01 9:07
* @email: [email protected]
* @Description: keep coding
*/
public class SinglyLinkedList<E> implements Serializable, Iterable<E>, Cloneable {
/**
* 容器已添加的元素
*/
private int size;
/**
* 头指针
*/
private Node head;
/**
* 向链表添加数据
*
* @param element 添加的元素
*/
public void addFirst(E element) {
this.head = new Node(element, this.head);
++this.size;
}
/**
* 向链表尾部添加数据
*
* @param element
*/
public void addLast(E element) {
Node last = getLast();
if (last == null) {
addFirst(element);
return;
}
last.next = new Node(element, null);
++this.size;
}
public Node getNode(int index) {
if (index > size) {
throw new IndexOutOfBoundsException("元素不存在");
}
Node p = this.head;
for (int i = 0; i != index; i++) {
p = p.next;
}
return p;
}
/**
* 获取容器指定位置的值
*
* @param index
* @return
*/
public E get(int index) {
if (index > size) {
throw new IndexOutOfBoundsException("元素不存在");
}
Node node = getNode(index);
if (null == node) {
throw new NullPointerException("元素不存在");
}
return (E) node.value;
}
/**
* 向指定位置插入节点
* 写的比较冗余
* 弃用
* @param index
* @param e
*/
@Deprecated
public void add0(int index, E e) {
if (index == 0) {
addFirst(e);
}
if (index > size) {
throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
}
Node p = this.head;
int i = 0;
while (true) {
if (i == index - 1) {
p.next = new Node(e, p.next);
this.size++;
break;
}
p = p.next;
i++;
}
}
/**
* 向元素指定节点添加值
*
* @param index
* @param e
*/
public void add(int index, E e) {
if (index == 0) {
addFirst(e);
return;
}
if (index > size) {
throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
}
// 获取先前节点
Node prev = getNode(index - 1);
if (prev == null) {
throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
}
prev.next = new Node(e, prev.next);
++this.size;
}
/**
* 移除容器内第一个元素
*/
public void removeFirst() {
if (this.head == null) {
return;
}
this.head = this.head.next;
--this.size;
}
/**
* 移除容器内指定位置元素
*
* @param index
*/
public void remove(int index) {
if (index > size) {
throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
}
if (index == 0) {
removeFirst();
return;
}
Node prev = getNode(index - 1);
if (prev == null) {
throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
}
// 获取index元素的后一个节点,也行。但是需要多找一次
Node node = getNode(index);
if (node == null) {
throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
}
prev.next = node.next;
--this.size;
}
/**
* 获取容器大小
*
* @return
*/
public int size() {
return this.size;
}
/**
* addLast 方法使用
* 获取容器最后节点Node信息
*
* @return
*/
private Node getLast() {
if (this.head == null) {
return null;
}
Node node;
for (node = this.head; node.next != null; node = node.next) {
}
return node;
}
/**
* 迭代器遍历
*
* @return
*/
@Override
public Iterator iterator() {
return new NodeIterator();
}
/**
* 匿名内部类
* 内部类使用到了外部类的成员变量时,不能使用static修饰
*/
private class NodeIterator implements Iterator {
Node node = head;
private int nextIndex;
@Override
public boolean hasNext() {
return nextIndex < SinglyLinkedList.this.size;
}
@Override
public Object next() {
Object value = node.value;
node = node.next;
++this.nextIndex;
return value;
}
}
/**
* while实现
*
* @param consumer
*/
public void forEach(Consumer consumer) {
Node firstNode = this.head;
while (firstNode != null) {
consumer.accept(firstNode.value);
firstNode = firstNode.next;
}
}
/**
* for循环实现
*
* @param consumer
*/
public void forEach2(Consumer consumer) {
for (Node firstNode = this.head; firstNode != null; firstNode = firstNode.next) {
consumer.accept(firstNode.value);
}
}
/**
* Node类型 节点对象
* 二者为组合关系,所以 由外部类变为内部类,对外隐藏实现细节
*/
private static class Node<E> {
/**
* 值
*/
private E value;
/**
* 下一个节点
*/
private Node<E> next;
public Node(E value, Node next) {
this.value = value;
this.next = next;
}
}
}
4. 哨兵链表:
一个不参与数据存储的特殊 Node 作为哨兵,它一般被称为哨兵或哑元,拥有哨兵节点的链表称为带头链表
注:大白话就是容器类的this.head 赋值了一个无意义的Node节点,保持head非空
package com.nami.algorithm.study.day04;
import java.io.Serializable;
import java.util.Iterator;
import java.util.function.Consumer;
/**
* 单向哨兵链表
* 非线程安全
* beyond u self and trust u self.
*
* @Author: lbc
* @Date: 2023-09-01 9:07
* @email: [email protected]
* @Description: keep coding
*/
public class SentinelLinkedList<E> implements Serializable, Iterable<E>, Cloneable {
/**
* 容器已添加的元素
*/
private int size = 1;
/**
* 头指针
* 哨兵节点: head 赋值一个头节点
*/
private Node head = new Node("sentinelNode", null);
/**
* 向链表添加数据
*
* @param element 添加的元素
*/
public void addFirst(E element) {
// this.head.next = new Node(element, this.head.next);
// ++this.size;
add(0, element);
}
/**
* 向链表尾部添加数据
*
* @param element
*/
public void addLast(E element) {
Node last = getLast();
last.next = new Node(element, null);
++this.size;
}
private Node getNode(int index) {
Node p = this.head;
for (int i = -1; i != index; i++) {
p = p.next;
}
return p;
}
/**
* 获取容器指定位置的值
*
* @param index
* @return
*/
public E get(int index) {
if (index > size) {
throw new IndexOutOfBoundsException("元素不存在");
}
Node node = getNode(index);
return (E) node.value;
}
/**
* 向元素指定节点添加值
*
* @param index
* @param e
*/
public void add(int index, E e) {
if (index > size) {
throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
}
// 获取先前节点
Node prev = getNode(index - 1);
if (prev == null) {
throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
}
prev.next = new Node(e, prev.next);
++this.size;
}
/**
* 移除容器内第一个元素
*/
public void removeFirst() {
remove(0);
}
/**
* 移除容器内指定位置元素
*
* @param index
*/
public void remove(int index) {
if (index > size-1) {
throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
}
// index =0 返回的是哨兵
Node prev = getNode(index - 1);
prev.next = prev.next.next;
--this.size;
}
/**
* 获取容器大小
*
* @return
*/
public int size() {
return this.size - 1;
}
/**
* addLast 方法使用
* 获取容器最后节点Node信息
*
* @return
*/
private Node getLast() {
Node node;
for (node = this.head; node.next != null; node = node.next) {
}
return node;
}
/**
* 迭代器遍历
*
* @return
*/
@Override
public Iterator iterator() {
return new NodeIterator();
}
/**
* 匿名内部类
* 内部类使用到了外部类的成员变量时,不能使用static修饰
*/
private class NodeIterator implements Iterator {
Node node = head.next;
private int nextIndex;
@Override
public boolean hasNext() {
return nextIndex < SentinelLinkedList.this.size-1;
}
@Override
public Object next() {
Object value = node.value;
node = node.next;
++this.nextIndex;
return value;
}
}
/**
* while实现
*
* @param consumer
*/
public void forEach(Consumer consumer) {
Node firstNode = this.head.next;
while (firstNode != null) {
consumer.accept(firstNode.value);
firstNode = firstNode.next;
}
}
/**
* for循环实现
*
* @param consumer
*/
public void forEach2(Consumer consumer) {
for (Node firstNode = this.head.next; firstNode != null; firstNode = firstNode.next) {
consumer.accept(firstNode.value);
}
}
/**
* Node类型 节点对象
* 二者为组合关系,所以 由外部类变为内部类,对外隐藏实现细节
*/
private static class Node<E> {
/**
* 值
*/
private E value;
/**
* 下一个节点
*/
private Node<E> next;
public Node(E value, Node next) {
this.value = value;
this.next = next;
}
}
}
5. 如测试出现问题,请联系我更正