数组和链表的区别ArrayList和LinkedList的区别使用LinkedList模拟栈和队列
Posted 刘Java
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数组和链表的区别ArrayList和LinkedList的区别使用LinkedList模拟栈和队列相关的知识,希望对你有一定的参考价值。
介绍了数组和链表的区别,ArrayList和LinkedList的区别以及使用LinkedList模拟栈和队列。
1 数组和链表的结构的异同
相同点:
数组和链表都属于线性表,其中数组是属于顺序储存的实现,逻辑存储和物理存储相同而链表则属于链式储存的实现,逻辑存储和物理存储不相同。两种结构均实现数据结构中的逻辑顺序存储。
不同点:
- 数组:
- 在内存中是一组连续的内存单元。内存空间要求高,必须有足够的连续内存空间。
- 每个元素都有自己的下标索引,元素可以重复,都个元素都可以通过下标索引访问。
- 它的缺点:在存储之前,我们需要申请一块连续的内存空间,并且在编译的时候就必须确定好它的空间的大小。在运行的时候空间的大小是无法随着你的需要进行增加和减少而改变的,当数据量比较大的时候,有可能会出现越界的情况,数据比较小的时候,又有可能会浪费掉内存空间。
- 数组的查询:指针从开始索引按顺序前移,直到查询到对应的数据。速度快,支持随机访问。
- 增加和删除:在某个位置增加或删除元素后,其后面的元素都要重新分配下标索引,速度相对较慢(但可以接受)。
- 链表:
- 在内存中的节点分布是不连续的,随机的,离散的。节点之间通过保存上\\下一个节点的引用来建立联系。内存利用率高,不会浪费内存。链表是动态申请内存空间,不需要像数组需要提前申请好内存的大小,链表只需在用的时候申请就可以,因此不存在容量一说!
- 每个元素都有自己的下标索引,元素可以重复,每个元素都可以通过下标索引访问。但是和数组的底层却是不同的。
- 链表的查询:没有数组速度快,不支持随机访问,只能顺序访问;
- 增加和删除:直接操作相邻的两个节点的引用,不需要整体移动后半部分的数据,速度快。
2 ArrayList和LinkedList的异同
相同点:
- 都是非线程安全的,只有在单线程下才可以使用。为了防止非同步访问,可以采用如下方式创建List list= Collections.synchronizedList(List list);
- LinkedList和ArrayList元素都可以为null,元素都有序(存储顺序)。
不同点:
- 查询:ArrayList继承于AbstractList,LinkedList继承于AbstractSequentialList;AbstractList支持快速随机访问,即支持直接通过索引查找集合元素;AbstractSequentialList不支持快速随机访问,只有通过【index < (size >> 1)】判断索引是否更靠近链表头部或者尾部,让案后选择从头或者尾开始依次遍历!即查询ArrayList速度快,LinkedList速度慢!
- 插入、删除元素:LinkedList的删除和新增方法的实现基本是对该节点的上一个节点和下一个节点的引用设置,不需要操作其他节点,相比于ArrayList来说,效率是非常高的,因为ArrayList的新增和操作需要对数组中的数据做遍历复制操作,并需要调整操作索引后的所有的数的位置。
- LinkedList没有实现自己的 Iterator(其iterator方法,底层调用的是listIterator方法),但是有 ListIterator和 DescendingIterator(实现了Iterator);
- LinkedList需要更多的内存,因为 ArrayList的每个索引的位置是实际的数据,而 LinkedList中的每个节点中存储的是实际的数据和前后节点的位置;
- ArrayList的空间浪费主要体现在 在list列表的结尾预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗相当的空间
应用:
- 数组(ArrayLsit)应用场景:频繁的查询操作,较少的增删操作。
- 链表(LinkedList)应用场景:较少的查询操作,频繁的增删操作。
3 栈和队列的模拟
栈特点:FILO 先进后出
队列的特点:FIFO先进先出
使用LinkedList模拟队列和栈: ( 装饰设计模式 )
- 创建一个类: MyQueue 或者 MyStack
- 引入LinkedList 类,定义为全局变量。
- 提供一个该类的构造器,对全局变量进行初始化。
- 提供存和取的方法,以及判断是否为null的方法。
3.1 模拟栈
/**
* LinkedList模拟栈
* @author lx
*/
public class MyStackFromLinkedList<T> {
private LinkedList<T> ll;
public MyStackFromLinkedList() {
this.ll = new LinkedList<>();
}
/**
* 入栈
* @param obj 入栈的元素
*/
public void add(T obj) {
ll.offerFirst(obj);
}
/**
* 出栈
* @return 出栈的元素
*/
public T get() {
return ll.pollFirst();
}
/**
* 栈是否为空
* @return true-空;false-非空
*/
public Boolean isEmpty() {
return ll.isEmpty();
}
}
/**
* 测试
*/
class MyStackTest {
public static void main(String[] args) {
MyStackFromLinkedList<String> myStack = new MyStackFromLinkedList<>();
//入栈
myStack.add("aa");
myStack.add("bb");
myStack.add("cc");
myStack.add("dd");
while (!myStack.isEmpty()) {
//出栈,先入栈的后出栈
Object o = myStack.get();
//dd cc bb aa
System.out.print(o + " ");
}
}
}
3.2 模拟队列
/**
* LinkedList模拟队列
* @author lx
*/
public class MyQueueFromLinkedList<T> {
private LinkedList<T> ll;
public MyQueueFromLinkedList() {
this.ll = new LinkedList<>();
}
/**
* 入队列
*
* @param obj 入队的元素
*/
public void add(T obj) {
ll.offerFirst(obj);
}
/**
* 出队列
*
* @return 出队的元素
*/
public T get() {
return ll.pollLast();
}
public Boolean isEmpty() {
return ll.isEmpty();
}
}
/**
* 测试
*/
class MyQueueTest {
public static void main(String[] args) {
MyQueueFromLinkedList<String> myQueue = new MyQueueFromLinkedList<>();
//入队列
myQueue.add("a");
myQueue.add("b");
myQueue.add("c");
myQueue.add("d");
while (!myQueue.isEmpty()) {
//出队列,先入队的先出队
Object o = myQueue.get();
//a b c d
System.out.print(o + " ");
}
}
}
以上是关于数组和链表的区别ArrayList和LinkedList的区别使用LinkedList模拟栈和队列的主要内容,如果未能解决你的问题,请参考以下文章