我们都知道ArrayList称为动态数组集合,所谓的动态数组,并不是说数组的大小可以发生改变,我们都知道,在创建数组的时候都需要指定数组的长度,一旦数组创建,数组的长度是不能改变的。
那么ArrayList是如何实现动态数组的方式呢,可以看之前的文章ArrayList源码分析一,概括来说就是调用ArrayList在Add方法进行元素添加的时候,会判断能不能装下新添加的元素,如果能放下就放到数组里面去,如果放不下,ArrayList就会新开辟一个数组,同时将原数组里面的数据拷贝到新数组里面去,同时把添加的元素放到新数组的最后一位。
ArrayList有数组的优点和缺点,优点是有索引,查询比较快。缺点是增删慢和扩容的时候比较浪费内存空间。
LinkedList可以克服这些缺点,LinkedList的内存空间可以用到多少就申请多少以及LinkedList的增删比较快。
链表的分类
单链表、 双链表和循环链表。
链表的概念
链表是由链将每一个Node进行连接,Node里面放的是我们添加的元素。
Node节点里面有2个数据,一个是存放我们存的数据值。另一个是存放下一个节点的内存地址。需要注意的是,Node元素是不连续的,也就是链表的数据结构也不是连续的。每次添加都是new出来的,所以不是连续的。
链表是可以实现用到多少内存空间就申请多少空间的并且又能够提高增删速度。
链表如此优秀,为什么还要用数组这种数据结构呢?
由于链表的内存不连续,没有索引的概念,所以链表的查询比较慢。链表的查询是通过遍历的方式,多以比较慢。
LinkedList本身是个双向链表。
我们先来实现一个单向链表:
/**
* description:将ArrayList和LinkedList里面的共性方法进行抽取
*/
public interface List<E> {
int size();
boolean isEmpty();
boolean contains(E element);
void add(E element);
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);
int indexOf(E element);
void clear();
String toString();
}
/**
* description:实现ArrayList和LinkedList的共性方法
*/
public abstract class AbstractList<E> implements List<E> {
protected int size;
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean contains(E element) {
return indexOf(element) != -1;
}
}
在Node节点里面有2个数据,一个是存放我们存的数据值。另一个是存放下一个节点的内存地址。在LinkedList里面定一个内部类Node来实现这个Node:
private static class Node<E> {
Node<E> next;
E element;
public Node(Node<E> next, E element) {
this.next = next;
this.element = element;
}
}
LinkedList的结构如下:
package com.example.suanfademo;
class MyLinkedList<E> extends AbstractList<E> {
private Node first;
private static class Node<E> {
Node<E> next;
E element;
public Node(Node<E> next, E element) {
this.next = next;
this.element = element;
}
}
@Override
public void add(E element) {
}
@Override
public E get(int index) {
return null;
}
@Override
public E set(int index, E element) {
return null;
}
@Override
public void add(int index, E element) {
}
@Override
public E remove(int index) {
return null;
}
@Override
public int indexOf(E element) {
return 0;
}
@Override
public void clear() {
}
}
实现 LinkedList的get方法:
@Override
public E get(int index) {
checkElementIndex(index);
return node(index).element;
}
private void checkElementIndex(int index) {
if (!isElementIndext(index)) {
throw new IndexOutOfBoundsException("index:" + index + "size:" + size);
}
}
private boolean isElementIndext(int index) {
return index >= 0 && index < size;
}
private Node<E> node(int index) {
Node x = first;
for (int i = 0; i < index; i++) {
x = x.next;
}
return x;
}
实现 LinkedList的set方法:
@Override
public E set(int index, E element) {
checkElementIndex(index);
Node<E> node = node(index);
E oldValue = node.element;
node.element = element;
return oldValue;
}
实现 LinkedList的clear方法:可达性算法:判断一个对象是一个垃圾的标准 选取一个节点作为GC Roots的顶点,其他对象或者引用指向这个GC Roots的顶点,如果这个对象能够到达这个GC Roots顶点的,那么这些对象就不是垃圾,反之就会被认为是null
@Override
public void clear() {
size = 0;
first = null;
}
实现 LinkedList的indexOf方法:
@Override
public int indexOf(E element) {
Node x = this.first;
if (element == null) {
for (int i = 0; i < size; i++) {
if (x.element == null) {
return i;
}
x = x.next;
}
} else {
for (int i = 0; i < size; i++) {
if (element.equals(x.element)) {
return i;
}
x = x.next;
}
}
return -1;
}
实现 LinkedList的add方法:
@Override
public void add(int index, E element) {
checkPositionIndex(index);
//add(0,100)的情况
if(index == 0){
first = new Node<E>(first, element);
}else{
//要获取前一个Node和后一个Node,改变他们的指向
Node<E> pre = node(index - 1);
Node<E> next = pre.next;
Node<E> newNode = new Node<E>(next,element);
pre.next = newNode;
}
size++;
}
实现 LinkedList的toString方法:
@Override
public String toString() {
if (size == 0) {
return "[]";
}
Node x = first;
StringBuilder stringBuilder = new StringBuilder().append("[");
for (int i = 0; i < size; i++) {
if (i != size - 1) {
stringBuilder.append(x.element).append(",").toString();
} else {
stringBuilder.append(x.element).append("]").toString();
}
x = x.next;
}
return stringBuilder.toString();
}
实现 LinkedList的remove方法:
@Override
public E remove(int index) {
checkElementIndex(index);
Node<E> oldValue = first;
if (index == 0) {
oldValue = first;
first = first.next;
} else {
//index的前一个节点
Node<E> pre = node(index - 1);
//index的后一个节点
Node<E> next = pre.next.next;
oldValue = pre.next;
pre.next = next;
}
return oldValue.element;
}
package com.example.suanfademo;
/**
* *******************************************
* Create by Jingjing.Lin2
* 2020/10/20 20:15
* description:
* ******************************************
*/
class MyLinkedList<E> extends AbstractList<E> {
private Node first;//头节点
private static class Node<E> {
Node<E> next;
E element;
public Node(Node<E> next, E element) {
this.next = next;
this.element = element;
}
}
@Override
public void add(E element) {
add(size, element);
}
@Override
public E get(int index) {
checkElementIndex(index);
return node(index).element;
}
private void checkElementIndex(int index) {
if (!isElementIndext(index)) {
throw new IndexOutOfBoundsException("index:" + index + "size:" + size);
}
}
private boolean isElementIndext(int index) {
return index >= 0 && index < size;
}
private Node<E> node(int index) {
Node x = first;
for (int i = 0; i < index; i++) {
x = x.next;
}
return x;
}
@Override
public E set(int index, E element) {
checkElementIndex(index);
Node<E> node = node(index);
E oldValue = node.element;
node.element = element;
return oldValue;
}
@Override
public void add(int index, E element) {
checkPositionIndex(index);
//add(0,100)的情况
if (index == 0) {
first = new Node<E>(first, element);
} else {
//要获取前一个Node和后一个Node,改变他们的指向
Node<E> pre = node(index - 1);
Node<E> next = pre.next;
Node<E> newNode = new Node<E>(next, element);
pre.next = newNode;
}
size++;
}
private void checkPositionIndex(int index) {
if (!isPositionIndex(index)) {
throw new IndexOutOfBoundsException("index:" + index + "size:" + size);
}
}
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
@Override
public E remove(int index) {
checkElementIndex(index);
Node<E> oldValue = first;
if (index == 0) {
oldValue = first;
first = first.next;
} else {
//index的前一个节点
Node<E> pre = node(index - 1);
//index的后一个节点
Node<E> next = pre.next.next;
oldValue = pre.next;
pre.next = next;
}
return oldValue.element;
}
@Override
public int indexOf(E element) {
Node x = this.first;
if (element == null) {
for (int i = 0; i < size; i++) {
if (x.element == null) {
return i;
}
x = x.next;
}
} else {
for (int i = 0; i < size; i++) {
if (element.equals(x.element)) {
return i;
}
x = x.next;
}
}
return -1;
}
/**
* 可达性算法:判断一个对象是一个垃圾的标准
* 选取一个节点作为GC Roots的顶点,其他对象或者引用指向这个GC Roots的顶点,如果这个对象能够到达这个GC Roots顶点的,那么这些对象就不是垃圾,反之就会被认为是null
*/
@Override
public void clear() {
size = 0;
first = null;
}
@Override
public String toString() {
if (size == 0) {
return "[]";
}
Node x = first;
StringBuilder stringBuilder = new StringBuilder().append("[");
for (int i = 0; i < size; i++) {
if (i != size - 1) {
stringBuilder.append(x.element).append(",").toString();
} else {
stringBuilder.append(x.element).append("]").toString();
}
x = x.next;
}
return stringBuilder.toString();
}
}