数据结构与算法的学习笔记目录:《恋上数据结构与算法》的学习笔记 目录索引
动态数组有个明显的缺点,可能会造成内存空间的大量浪费;
链表可以做到用多少就申请多少内存!
一、链表
链表是一种 链式存储 的线性表,所有元素的内存地址不一定是连续的。
二、链表的设计
- 创建类 LinkedList ,用来管理链表数据,其中的 size 属性记录存储数据的数量,first 属性引用链表的第0个元素
- 创建私有类Node ,其中的 element 属性用于存储元素, next 属性用于指向链表中的下一个节点。
public class LinkedList<E> {
private int size;
private Node<E> first;
// 私有类,链表中的节点
private class Node<E>{
E element;
Node<E> next;
// 构造方法
public Node(E element, Node<E> next){
this.element = element;
this.next = next;
}
}
}
三、链表的接口设计
- 与动态数组一样,链表也是需要提供增删改查
// 元素的数量
int size();
// 是否为空
boolean isEmpty();
// 是否包含某个元素
boolean contains(E element);
// 添加元素到最后面
void add(E element);
// 返回index位置对应的元素
E get(int index);
// 设置index位置的元素
E set(int index, E element);
// 往index位置添加元素
void add(int index, E element);
// 删除index位置对应的元素
E remove(int index);
// 查看元素的位置
int indexOf(E element);
// 清除所有元素
void clear();
四、链表接口的实现
1. 索引越界的判断
- 在操作链表数据时,需要防止索引越界,防止出现程序异常的问题
- 当查找和删除数据时,需要检查索引的范围是 0 到 size-1 之间,所以方法如下:
// 索引越界判断
private void rangCheck(int index){
if(index < 0 || index >= size){
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
}
- 当插入数据时,因为可以将数据加到所有数据的最后,所以需要检查索引的范围是 0 到 size 之间
private void rangCheckForAdd(int index){
if(index < 0 || index > size){
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
}
2. 根据索引查找指定节点
- 因为链表中的数据都存在节点中,所以操作数据时 需要找到对应的节点
- 我们可以实现一个根据索引,来查找指定节点的方法
private Node<E> node(int index){
rangCheck(index);
// 头节点,就是first指向的那个节点
Node<E> node = first;
// 根据索引遍历,查找对应的节点
for(int i = 0; i < index; i++){
node = node.next;
}
return node;
}
3. 添加数据
- 添加数据时,需要创建一个节点存储数据,并将该节点拼接到最后节点的后面,然后 size 加 1;
- 两种情况:
- 第一种:当前链表没有数据,新节点拼接到first
- 第二种:当前链表有数据,新节点拼接到最后的节点
public void add(E element){
// 当first等于null时,说明此时没有节点,所以first引用新节点
if(first == null){
first = new Node<>(element