LinkedList集合
基础概念
可以在任何位置高效插入和删除的一个有序序列,简而言之就是数据结构里的链表。
我们都清楚在链表很容易进行插入和删除,但是我们在使用c/c++的时候需要新建一个链表项的结构体并且需要在里面设置指针,java不需要指针,java在这方面就很好的为程序员消除了这个问题。使用LinkedList类就可以解决问题。
如下代码将实现先添加3个元素,然后将第二个元素删除的操作,方便快捷So easy~
import java.util.*;
public class pred {
public static void main(String[] args) {
LinkedList staff=new LinkedList<String>();
staff.add("Amy");
staff.add("Bob");
staff.add("Carl");
ListIterator<String> it=staff.listIterator();
String first=it.next();
String second=it.next();
it.remove();//remove the element "Bob"
System.out.println(staff);
System.out.println(first+" "+second);
}
}
运行结果如下:
LinkedList.add()是将对象添加到链表的尾部。
ListIterator接口
然而,我们平常经常会将元素添加到集合中间,这个时候我们就要使用迭代器来找到这个中间位置。在List里还有一个ListIterator子接口:
interface ListIterator<E> extends Iterator<E>{
void add(E element);//与Collection.add不同,这个方法不返回boolean类型的值,假定总会成功执行该方法
E previous();//与next相反,previous返回越过的对象
boolean hasPrevious();//与hasNext()一样效果
}
add方法
add方法是在迭代器位置之前添加一个新对象,例如下面就是在第二个元素之前添加“Mike”
import java.util.*;
public class pred {
public static void main(String[] args) {
LinkedList staff=new LinkedList<String>();
staff.add("Amy");
staff.add("Bob");
staff.add("Carl");
ListIterator<String> it=staff.listIterator();
it.next();//skip the first element
it.add("Mike");
System.out.println(staff);
}
}
运行结果:
set置换方法
set可以使用一个新元素替代next和previous方法返回的上一个元素
import java.util.*;
public class pred {
public static void main(String[] args) {
LinkedList staff=new LinkedList<String>();
staff.add("Amy");
staff.add("Bob");
staff.add("Carl");
ListIterator<String> it=staff.listIterator();
//将第一个元素Amy替代为wyq
String newvalue="wyq";
it.next();
it.set(newvalue);
System.out.println(staff);
}
}
运行结果:
关于LinkedList的插入删除的记忆方法
我们使用迭代器对集合进行遍历的时候回经常类比backspace键,这个时候我要作一些解释:
调用next后调用remove确实可以达到与backspace效果相同的目的,删除左侧的元素。但是如果调用previous,就会删除右侧的元素。
集合头部用next(),集合尾部用previous()
import java.util.*;
public class pred {
public static void main(String[] args) {
LinkedList staff=new LinkedList<String>();
staff.add("Amy");
staff.add("Bob");
staff.add("Carl");
ListIterator<String> it=staff.listIterator();
//新创建的迭代器的位置在第一个元素的前面,因此不能上来就是使用hasPrvious(),会返回false
//正向遍历
while(it.hasNext()) {
System.out.println(it.next());
}
System.out.println();
//反向遍历
while(it.hasPrevious()) {
System.out.println(it.previous());
}
}
}
运行结果:
多个迭代器访问集合
一个迭代器对集合进行修改的时候另一个迭代器正在访问集合,那么肯定会出现混乱,迭代器之间各怀鬼胎,互相不告诉自己的位置以及自己干了啥,导致作战失败。
import java.util.*;
public class pred {
public static void main(String[] args) {
LinkedList staff=new LinkedList<String>();
staff.add("Amy");
staff.add("Bob");
staff.add("Carl");
//生成两个迭代器it与it2
ListIterator<String> it=staff.listIterator();
ListIterator<String> it2=staff.listIterator();
it.next();
it.remove();
it2.next();
}
}
结果:
会抛出ConcurrentModificationException
的异常。
按照索引值访问集合元素
如果只是想要索引查找元素而很少对元素进行插入和修改,用ArrayList
不香嘛?
但是LinkedList
还是有自己的索引方法—get(int index)
既然看到可以按照数字进行索引,那么我是不是就可以使用这种方式对集合进行遍历?就像如下所写的这样:
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
注意这段代码的效率很低,不建议使用。
每次查找一个元素都是从列表的头部重新开始搜索,很费时间。(这里的get做了一些细小的优化:如果索引大于size/2
的时候从表尾开始查找)
迭代器有自己的索引:nextIndex()返回下一次调用next()方法所返回的元素的整数索引;previousIndex()方法返回下一次调用previous()方法所返回的整数索引。
import java.util.*;
public class pred {
public static void main(String[] args) {
LinkedList staff=new LinkedList<String>();
staff.add("Amy");
staff.add("Bob");
staff.add("Carl");
ListIterator<String> it=staff.listIterator();
it.next();//位于第0个和第1个元素之间
System.out.println(it.nextIndex());
System.out.println(it.previousIndex());
}
}
运行结果如下:
最后说明一点:将整数index作为listIterator()的参数 list.listIterator(index),这个迭代器将会指向索引为n的元素的前面。就是火调用next()与get(index)得到的元素都是索引为n的元素。二者相比迭代器效率低一些。
LinkedListTest.java
import java.util.*;
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<String> a=new LinkedList<String>();
a.add("Amy");
a.add("Carl");
a.add("Erica");
LinkedList<String> b=new LinkedList<String>();
b.add("Bob");
b.add("Doug");
b.add("Frances");
b.add("Gloria");
//merge the words from b to a
ListIterator<String> aIt=a.listIterator();
Iterator<String> bIt=b.iterator();
while(bIt.hasNext()) {
if(aIt.hasNext())
aIt.next();
aIt.add(bIt.next());
}
System.out.println(a);
//remove every second word from b
bIt=b.iterator();//将迭代器bIt返回到列表头
while(bIt.hasNext()) {
bIt.next();//skip one element
if(bIt.hasNext()) {
bIt.next();//skip next element
bIt.remove();//remove that element
}
}
System.out.println(b);
//bulk operation:remove all words in b from a
a.removeAll(b);
System.out.println(a);
}
}
运行结果如下:
List、ListIterator、LinkedList的API
[API]java.util.List<E>
集合.方法
1.ListIterator<E> listIterator();
返回一个列表迭代器,用来访问列表中的元素。
2.ListIterator<E> listIterator(int index);
返回一个列表迭代器,用来访问列表中的元素,第一次调用这个迭代器调用的next会返回索引(index)的元素
3.void add(int i,E element);
在给定的位置添加一个元素
4.void addAll(int i,Collection<? extends E> elements);
将一个集合中的所有元素添加到给定位置
5.E remove(int i);
删除并返回给定位置的元素
6.E get(int i);
获取给定位置的元素
7.E set(int i,E element);
用一个新元素替代给定位置的元素,并返回原来的元素。
8.int indexOf(Object element);
返回与指定元素相等的元素在列表中第一次出现的位置,如果没有这样的元素就返回-1.
9.int lastIndexOf(Object element);
返回与指定元素相等的元素在列表中最后一次出现的位置,如果没有这样的元素就返回-1.
第八个和第九个都是用集合调用的
java.util.ListIterator<E>
1.void add(E element);
在当前位置前添加一个元素
2.void set(E element);
用新元素替代next与previous访问的上一个元素。如果上一个next和previous调用之后列表结构发生了变化,将会抛出一个IllegalStateException
的异常
3.boolean hasPrevious();
当反向迭代列表的时候,如果还有可以访问的元素,返回true
4.E previous();
返回前一个对象,迭代器刚开始创建的时候,迭代器一般是在列表的头部,这个时候调用previous会抛出NoSuchElementException
的异常
5.int nextIndex();
返回下一次调用next方法时将返回的元素的索引
6.int previousIndex();
返回下一次调用previous方法时将返回的元素
java.util.LinkedList<E>
LinkedList();//构建一个空链表
LinkedLis(Collection<? extends E> elements);//构造一个链表,并将集合中所有的元素添加到这个链表中
void addFirst(E element);
void addLast(E element);//将元素天教导表头或者表尾
E getFirst();
E getLast();//返回列表头部或者尾部的元素
E removeFirst();
E removeLast();//删除并返回列表头部或者尾部的元素