LinkedList容器类简介
LinkedList容器类也是List接口的一个实现类,但是和之前介绍的ArrayList类、Vector类和Stack类不同,它的底层是通过双向链表结构来实现的。双向链表结构是链表结构的一种,链表结构最大的好处就是大大提高了容器中元素的增删效率,但是相对应的,它的查询效率会相应的降低。那么为什么会出现这种现象呢?这里就需要先了解链表结构。
在java中我们可以通过数组来完成对数据的储存,但是这样会降低数据的增删效率。因为当我们对数组中的元素进行操作的时候,对应数组中的元素的索引大概率会发生变化。比如,当我在数组中的某个位置增加一个元素时,如果数组中该位置存在元素,那么无论它的后面是否存在元素,自这个元素开始(包括这个元素)往后的所有元素的索引都会增加1,而如果当我在指定位置删除某一个元素时,如果被删除的这个元素的后面有元素,那么这个元素后面的所有元素的索引都会减1。这样,如果数组的长度极长,那么对数组中的元素进行增删操作时就相当于同时要对后面的元素进行改变索引的操作,这样自然就降低了增删效率。
但是链表结构不同,这里就以双向链表来说明。链表中的数据是以对象的方式来进行储存的,因此要在链表中找到一个数据我们需要先找到与这个数据相对因的地址,这里和我们之前做的对象存储时的内存分析是相符合的。链表结构中的每一个对象可以理解位一个单元,这些单元通过特殊的方式链接起来就组成了一个链表结构。这里完全可以用我们日常生活中见到的链状结构来类比。
如下图所示,在java中我们把链表结构的每一元素都定义在一个类Node中,如果是双向链表,那么此时Node类中要定义一个变量用于储存元素本身,另外还要定义一个next变量和一个prev变量。其中next指向链表中下一个对象的地址而prev指向上一个元素的地址,通过这种方式我们就把java中那些分散存储的数据链接在了一起,成了一个链状结构。
关于链表结构这里要注意两点,第一,链表中元素的地址是随机的,也就是说一个链表中相邻的两个元素他们在内存中存储的位置不一定是相邻的,它的存储和对象的存储一样,开辟的存储空间并不是相邻的,和方法栈的开辟方式不一样。这也就意味着任何一个元素只要将它的地址通过通过上面的方式进行链接,它就可以轻松地成为链表的一部分,因此链表的增删效率是比较高的。第二,链表的查询方式是从链表的头不开始的,当然双向链表也可以从尾部开始,但这也就意味着如果查询的元素离链表头或者尾比较远,那么就需要一番功夫了,所以链表的查询查询效率是比较低下的。
综上,LinkedList类的是List的一个具体实现类,它的特点是查询效率低,增删效率高,并且线程是不安全的。
LinkedList容器类的使用
关于LInkedList容器类的使用有两套标准,第一套是是List标准,第二套是非List标准。首先,由于LinkedList容器类是List接口的具体实现类,因此它实现了List中的所有抽象方法,同时具备了List有序可重复的存储特征。通过这种标准来使用LinkedList容器类时,可以完全将其当作之前说过的几个类来使用,因为它同样实现了List接口种的所有方法,因此我们依旧可以正常的添加元素,获取元素,遍历元素,使用的方法也完全一样。
为什么说使用LinkedList容器类还有一套标准呢?因为LinkedList的底层是通过双向链表来实现的,所以这个容器类中理应拥有对双向链表进行操作的方法,这些方法不能定义在List接口当中,因此不属于List标准。这些方法常用的有:addFist、addLast、getFirst、getLast、removeFirst、removeLast、pop、push以及isEmpoty。
void addFist(E e):将指定元素插入到开头;
void addLast(E e):将指定元素插入到结尾;
E getFirst():获取此列表的第一个元素;
E getLast():获取此列表的最后一个元素;
E removeFirst():移除此列表第一个元素并返回;
E removeLast():移除此列表最后一个元素并返回;
E pop():从此列表所表示的栈中弹出一个元素,等效于removeFirst;
void push(E e):将指定元素添加进此列表表示的栈中,相当于addFirst;
boolean isEmpoty():判断由LinkedList类创建的的容器是否位空,如果为空,返回值true,否则返回值false。
以上的几个方法均比较简单,通过对象使用,要注意就是pop方法和push方法,在使用时相当于将容器竖了起来,栈顶元素为双向列表的头元素。这里依旧用上面的那张双向链表的模型图来说明,当调用pop方法和push方法的时候,相当于把这个双向链表顺时针旋转90度,此时链表尾部被堵住,我们只能从上端获取元素,即双向链表的头元素为栈顶元素。以上方法的使用详见下面演示代码。
package com.container.demo;
import java.util.List;
import java.util.LinkedList;
public class LinkedListTest {
public static void main(String[] args) {
List<String> list = new LinkedList<>();
//添加元素
list.add("a");
list.add("b");
list.add("c");
list.add("a");
//获取元素
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("_______________");
for (String str:list
) {
System.out.println(str);
}
System.out.println("____LinkedList_____");
LinkedList<String> linkedList = new LinkedList<>();
linkedList.addFirst("a");
linkedList.addFirst("b");
linkedList.addFirst("c");
for (String str:linkedList
) {
System.out.println(str);
}
System.out.println("___________________");
LinkedList<String> linkedList1 = new LinkedList<>();
linkedList1.addLast("a");
linkedList1.addLast("b");
linkedList1.addLast("c");
for (String str1:linkedList1
) {
System.out.println(str1);
}
System.out.println("头元素:"+linkedList1.getFirst());
System.out.println("尾元素:"+linkedList1.getLast());
System.out.println("删除头元素"+linkedList1.removeFirst());
System.out.println("删除尾元素"+linkedList1.removeLast());
for (String str1:linkedList1
) {
System.out.println(str1);
}
System.out.println("________________________");
//删除头元素不返回
linkedList1.pop();
for (String str1:linkedList1
) {
System.out.println(str1);
}
System.out.println("_____________________");
linkedList1.push("h");
for (String str1:linkedList1
) {
System.out.println(str1);
}
System.out.println(linkedList1.isEmpty());
}
}