链表
数据分散的存储在物理空间中,通过一根线保持他们之间的逻辑关系,这种存储结构称为链式存储结构。
实际上,就是每一个结点存放一个元素和一个指向下一个结点的引用(c语言里叫做指针)
实现类
public class Main {
public static void main(String[] args) {
/**
* 链表
*/
AbstractList<String> list = new LinkedList<>();
list.add("就你了",0);
list.add("阿狗",1);
System.out.println(list.remove(0));
System.out.println(list.get(0));
System.out.println(list.size());
System.out.println("就你了,阿狗");
}
}
定义抽象类方法
/**
* 线性表抽象类
* @param <E> 存储的元素(Element)类型
*/
public abstract class AbstractList<E> {
/**
*获取表的长度
* @return 线性表的长度
*/
public abstract int size();
/**
*添加一个元素
* @param e 元素
* @param index 要添加的位置(索引)
*/
public abstract void add(E e,int index);
/**
*删除指定的元素
* @param index 元素的位置
* @return 删除的元素
*/
public abstract E remove(int index);
/**
*查到指定的元素
* @param index 元素的位置
* @return 指定位置的元素
*/
public abstract E get(int index);
}
实现类
/**
* 链表
* @param <E>
*/
public class LinkedList<E> extends AbstractList<E>{
//定义头结点
private final Node<E> head = new Node<>(null);
//定义长度
private int size = 0;
@Override
public int size() {
return size;
}
@Override
public void add(E e, int index) {
//判断插入位置是否合法
if (index > size) throw new IllegalArgumentException("非法的插入位置");
//最开始结点为头结点 定义node类型temp
Node<E> node = head,temp;
//插入之后 原本的结点就变成下一个结点
for (int i = 0; i < index; i++) node = node.next;
//temp暂时缓存
temp = node.next;
// e(head) -> e2(node.next)
node.next = new Node<>(e);
//e(head) -> e1(node.next) ->e2(node.next.next)
//原本的e2变成了node.next.next
node.next.next = temp;
size ++;
}
@Override
public E remove(int index) {
//判断删除位置是否合法 抛出异常
if (index > size - 1) throw new IllegalArgumentException("非法的删除位置");
//最开始结点为头结点 定义node类型temp
Node<E> node = head,temp;
for (int i = 0; i < index; i++) node = node.next;
temp = node.next;
//从头结点开始 删除之后 直接指向下下个结点
//e(head) -> e1(node.next) -> e2(node.next.next)
//删除后 e(head) -> e2(node.next.next)
node.next = node.next.next;
size --;
return temp.e;
}
@Override
public E get(int index) {
if (index >= size) throw new IndexOutOfBoundsException("无法访问到下标位置");
Node<E> node = head.next;
for (int i = 0; i < index; i++) node = node.next;
return node.e;
}
private static class Node<E>{
//元素
private E e;
//下一结点
private Node<E> next;
//自定义方法 获取元素
public Node(E e){
this.e = e;
}
}
}
首先要了解链表的原理 明白插入和删除之后结点的指向 以上代码块的注释能够帮助理解
顺序表和链表的优缺点(博主主页有实现顺序表的方法可以比较)
顺序表优缺点
1.访问速度快,随机访问性能高
2.插入和删除的效率低下,极端情况下需要改变整个表
3.不易扩充,需要复制并重新创建数组
链表优缺点
1.插入和删除效率极高,只需要改变连接点的结点就可以
2.动态扩充容量,无需担心容量问题
3.访问元素需要依次寻找,随机访问元素效率低下。