数据结构
双向数据链结构
//在LinkedList类中的属性只有三个属性
transient int size = 0;//记录节点个数
transient Node<E> first;//记录链表的第一个节点
transient Node<E> last;//记录链表最后一个节点
常用方法
构造方法
源码分析
//无参构造方法,创建一个空链表
public LinkedList() { }
//有参构造,参数必须是Collection的子类,将参数的数据依次放入链表中
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
代码演示
ArrayList<Course> arrayList1 = new ArrayList();
LinkedList<Course> linkedList1 = new LinkedList<>();
// 初始化5个对象
int i = 0;
for (i=0; i < 5; i++) {
arrayList1.add(new Course("arrayList1 "+i));
}
LinkedList<Course> linkedList2 = new LinkedList<>(arrayList1);
for (i=0; i < 3; i++) {
linkedList2.add(new Course("linkedList2 "+i));
}
for(int j=0;j<linkedList2.size();j++){
System.out.println(linkedList2.get(j));
}
//插入的数据的类型可以不一致
ArrayList arrayList1 = new ArrayList();
LinkedList<Course> linkedList1 = new LinkedList<>();
// 初始化5个对象
int i = 0;
for (i=0; i < 5; i++) {
arrayList1.add(i);
}
LinkedList<Course> linkedList2 = new LinkedList<>(arrayList1);
for (i=0; i < 3; i++) {
linkedList2.add(new Course("linkedList2 "+i));
}
for(int j=0;j<linkedList2.size();j++){
System.out.println(linkedList2.get(j));
}
增加
当使用index定位特定位置插入时,会出现IndexOutOfBoundsException(index越界异常index>size或index<0)
add()
有两种方法一种直接插入数据,会自动尾插
一种有index参数,在index位插入数据
源码分析
//都是通过调用封装方法
public boolean add(E e) {
linkLast(e);
return true;
}
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
//两个方法实现了封装的linkLast(e)尾插方法,和 linkBefore(E e, Node<E> succ)定位节点前插方法
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
void linkBefore(E e, Node<E> succ) {
// succ是链表中原index位节点,需要在它之前插入新节点,它作为新节点的next
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
代码演示
ArrayList arrayList1 = new ArrayList();
LinkedList<Course> linkedList1 = new LinkedList<>();
// 初始化5个对象
int i = 0;
for (i=0; i < 5; i++) {
arrayList1.add(i);
}
LinkedList<Course> linkedList2 = new LinkedList<>(arrayList1);
for (i=0; i < 5; i++) {
linkedList2.add(new Course("linkedList2 "+i));
}
linkedList2.add(3,new Course("newCourse "+3));
for(int j=0;j<linkedList2.size();j++){
System.out.println(linkedList2.get(j));
}
addFirst()头增
源码分析
public void addFirst(E e) {
linkFirst(e);
}
//调用的封装的linkFirst(e)方法,
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);//增加prev为null,next为前first的新节点
first = newNode;//将first的地址换位新节点
if (f == null)//修改前first的prev值为现first
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
代码演示
ArrayList arrayList1 = new ArrayList();
LinkedList<Course> linkedList1 = new LinkedList<>();
// 初始化5个对象
int i = 0;
for (i=0; i < 5; i++) {
arrayList1.add(i);
}
LinkedList<Course> linkedList2 = new LinkedList<>(arrayList1);
for (i=0; i < 5; i++) {
linkedList2.addFirst(new Course("linkedList2 "+i));
}
linkedList2.addLast(new Course("LastCourse "+3));
for(int j=0;j<linkedList2.size();j++){
System.out.println(linkedList2.get(j));
}
addLast()尾增
源码分析
public void addLast(E e) {
linkLast(e);
}
//与add(E e)中的封装方法一样,实现尾插
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
代码演示看上节addFirst()中的代码演示
addAll()
源码分析
有两种实现方式一种直接尾插传入参数的所有数据,一种在指定位置插入所有数据,都是实现的下面的代码
//实现过程,将传入Collection子类中的数据转化为Object类数组,将数组中的数据依次创建节点,插入index位,并放好前后节点地址
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
Object[] a = c.toArray();//将c化为Object类数组
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred, succ;
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
代码演示
ArrayList arrayList1 = new ArrayList();
LinkedList<Course> linkedList1 = new LinkedList<>();
// 初始化5个对象
int i = 0;
LinkedList<Course> linkedList2 = new LinkedList<>();
for (i=0; i < 5; i++) {
linkedList2.addFirst(new Course("linkedList2 "+i));
}
for (i=0; i < 5; i++) {
arrayList1.add(i);
}
linkedList2.addAll(arrayList1);
linkedList2.addAll(1,arrayList1);
linkedList2.addLast(new Course("LastCourse "+3));
for(int j=0;j<linkedList2.size();j++){
System.out.println(linkedList2.get(j));
}
删除
当链表中没有数据,但是删除节点时显示NoSuchElementException 错误
代码演示
ArrayList<Course> arrayList1 = new ArrayList();
LinkedList<Course> linkedList1 = new LinkedList<>();
// 初始化5个对象
int i = 0;
LinkedList<Course> linkedList2 = new LinkedList<>();
for (i=0; i < 5; i++) {
linkedList2.addFirst(new Course("linkedList2 "+i));
}
Course course=new Course("特殊course");
linkedList2.add(course);
for (i=0; i < 5; i++) {
arrayList1.add(new Course("arrayList1 "+i));
}
linkedList2.addAll(arrayList1);
linkedList2.addLast(new Course("LastCourse "+3));
for(int j=0;j<linkedList2.size();j++){
System.out.println(linkedList2.get(j)+" ");
}
linkedList2.remove();//删除第一个节点
linkedList2.remove(course);//删除特定对象,只会删除最靠前的那个
linkedList2.remove(3);//删除特定位置节点
linkedList2.removeFirst();//删除头节点
linkedList2.removeLast();//删除尾节点
System.out.println();
for(int j=0;j<linkedList2.size();j++){
System.out.println(linkedList2.get(j)+" ");
}
获取get与indexOf
当链表中没有数据,但是获取节点时显示NoSuchElementException 错误
代码演示
ArrayList<Course> arrayList1 = new ArrayList();
LinkedList<Course> linkedList1 = new LinkedList<>();
// 初始化5个对象
int i = 0;
LinkedList<Course> linkedList2 = new LinkedList<>();
for (i=0; i < 5; i++) {
linkedList2.addFirst(new Course("linkedList2 "+i));
}
Course course=new Course("特殊course");
linkedList2.add(course);
for (i=0; i < 5; i++) {
arrayList1.add(new Course("arrayList1 "+i));
}
linkedList2.add(course);
linkedList2.addAll(arrayList1);
linkedList2.addLast(new Course("LastCourse "+3));
for(int j=0;j<linkedList2.size();j++){
System.out.println(linkedList2.get(j)+" ");
}
System.out.println();
System.out.println(linkedList2.get(5));//获取index为5的节点,index从0开始
System.out.println(linkedList2.getFirst());//获取第一个节点
System.out.println(linkedList2.getLast());//获取最后一个节点
System.out.println(linkedList2.indexOf(course));//通过对象获取index值,没找到返回-1,找到了就是正找第一个的index
System.out.println(linkedList2.lastIndexOf(course));//通过对象获取index值,没找到返回-1,找到了就是反找第一个的index
contains(Object o)
验证o在链表中是否存在,存在返回index,不存在返回-1,底层调用的是indexOf(Object o)方法
set(int index, E element)
将index位置下的数据换成element
peek()
**源码分析:**返回第一个节点的数值
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
与 element() 的区别都是获取头节点的数值,不同的是,peek()可以是头节点为null的情况, element()不行,会报NoSuchElementException错误
poll()
源码分析: 将头节点删除并输出它的值
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
push(E e)
即头增,调用了addFirst(E e) 方法
pop()
即删除头节点,将头节点设为原头节点的next值,调用了removeFirst()头删方法