作为Java程序员,扎实的数据结构算法能力是必须的
LinkedList理解的最好方式是,自己手动实现它
ArrayList和LinkedList是顺序存储结构和链式存储结构的表在java语言中的实现.
ArrayList提供了一种可增长数组的实现,使用ArrayList,因为内部使用数组实现,所以,它的优点是,对于get和set操作调用花费常数时间.缺点是插入元素和删除元素会付出昂贵的代价.因为这个操作会导致后面的元素都要发生变动,除非操作发生在集合的末端.
鉴于这个缺点,如果需要对表结构的前端频繁进行插入,删除操作,那么数组就不是一个好的实现,为此就需要使用另一种结构,链表,而LinkedList就是基于一种双链表的实现,使用它的优点就是,对于元素的插入,删除操作开销比较小,无论是在表的前端还是后端.但是缺点也显而易见,对于get操作,它需要从表的一端一个一个的进行查找,因此对get的调用花费的代价也是很昂贵的.
理解这集合最好的方式就是自己去实现它,下面我们通过代码来实现自己的LinkedList.
注意点:在学习数据结构的双向链表,会学习头结点和尾结点,加上头结点和尾结点,操作其他结点可以保持同一个动作,但是在JDK实现双向链表代码中,没有加头结点和尾结点,下面看LinkedList实现的简易版
public class LinkedList<E> implements Iterable<E> {
private int size;
private Node first;
private Node last;
//静态内部类
private static class Node<E>{
private E data;
private Node prev;
private Node next;
public Node(E data, Node prev, Node next) {
super();
this.data = data;
this.prev = prev;
this.next = next;
}
}
//不添加头结点和尾结点
public void add(int index,E e){
testIndex(index);
//根据index位置,选择不同的方式添加结点
if(index == size){
lastNode(e);
}else
//使用node()方法,查找到当前index位置的node结点
beforeNode(node(index),e);
}
//根据索引,插入结点,参数node为插入前,需要插入位置的node
private void beforeNode(Node<E> node, E e) {
final Node<E> pnode = node.prev;
final Node<E> nnode = node;
final Node<E> newNode = new Node<E>(e, pnode,nnode );
//为插入的两边结点分别添加前后指针域
pnode.next = newNode;
nnode.prev = newNode;
size++;
}
//默认直接在链表尾部添加结点
public void add(E e){
this.add(size,e);
}
//根据索引值,在链表中查找到当前位置结点
private Node<E> node(int index) {
if(index<size>>1){
Node<E> node = first;
for(int i = 0;i<index;i++)
{
node = node.next;
}
return node;
}else{
Node<E> node = last;
for(int i= size-1;i>index;i--){
node = node.prev;
}
return node;
}
}
//在jdk源码中,只有根据索引值来取值
public E get(int index){
Node<E> node = (Node) node(index);
return node.data;
}
//在双向链表的最后添加元素,由于没有头结点和尾结点
private void lastNode( E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<E>(e,l,null);
last = newNode;
if(l == null){
first = newNode;
}else{
l.next = last;
}
size++;
}
private void testIndex(int index) {
//抛出运行时异常,是非检查异常,所以不要trycatch,index >= 0 && index <= size;
if(!(index>=0&&index<=size)){
throw new ArrayOutOfBoundsException("位置信息初始化错误,大于size");
}
}
public int size(){
return size;
}
public boolean isEmpty(){
return size == 0;
}
@Override
public Iterator<E> iterator() {
return new ListIterator();
}
//使用内部类,编写遍历集合逻辑
public class ListIterator implements Iterator<E>{
private Node<E> node = first;
@Override
public boolean hasNext() {
// node = node.next;
return node != null;
}
@Override
public E next() {
E val = node.data;
node = node.next;
return val;
}
}
}
下面是测试自己手写LinkedList代码
public class TestLinkedList {
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
// System.out.println(list.size());
list.add(111);
list.add(1554);
list.add(333);
list.add(88888);
list.add(262511);
System.out.println(list.size());
Integer ai = list.get(2);
System.out.println(ai);
list.add(1, 66669);
// System.out.println(list.size());
System.out.println(list.get(1));
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
System.out.print(it.next()+" ");
}
}
}
测试结果
个人理解:理解源码和数据结构的最好方式,单步调试初步理解,自己重新手写