java线性表与集合_java集合-List

List判断两个对象相等只通过equals方法比较返回true即可。

public class A {

@Override

public boolean equals(Object arg0) {

return true;

}

}

public class SameAListTest {

public static void main(String[] args) {

List list = new ArrayList<>();

list.add(1);

list.add(2);

list.add(3);

//[1, 2, 3]

System.out.println(list);

list.remove(new A());

//[2, 3]

System.out.println(list);

list.remove(new A());

//[3]

System.out.println(list);

}

}

从上面程序可以看出,当程序试图删除一个A对象,List将会调用该A对象的equals方法依次与集合元素进行比较,如果该equals方法以某个集合元素作为参数时返回true,List将会删除该元素,A重写了equals方法,该方法总是返回true。

当调用List的set(int index,Object object)方法来改变List集合指定所引处的元素时,指定的索引必须是List集合的有效索引。例如集合长度是4,就不能指定替换索引为4处的元素--也就是说,set(int index,Object object)方法不会改变List集合的长度。

List还额外提供了一个listIterator方法,该方法返回一个ListIterator对象,ListIterator接口继承了Iterator接口,提供了专门操作List的方法。

public class ListIterators {

public static void main(String[] args) {

List list = new ArrayList<>();

list.add("123");

list.add("231");

list.add("132");

/*正向迭代

* Iterator iterator = list.iterator();

while (iterator.hasNext()) {

System.out.println(iterator.next());

}*/

/*//从指定的索引以后的元素进行迭代 Lambda迭代

ListIterator listIterator = list.listIterator(1);

//231 132

listIterator.forEachRemaining((e) -> System.out.println(e));*/

ListIterator iterator = list.listIterator();

while (iterator.hasNext()) {

String next = iterator.next();

System.out.println(next);

if ("132".equals(next)) {

iterator.add("新添加的");

}

}

System.out.println("反向迭代 +++++++++++++++++++++");

while (iterator.hasPrevious()) {

System.out.println(iterator.previous());

}

//[123, 231, 132, 新添加的]

System.out.println(list);

/*

* 123

231

132

反向迭代 +++++++++++++++++++++

新添加的

132

231

123

[123, 231, 132, 新添加的]

*/

}

}

ListIterator与Iterator相比,ListIterator是反向迭代,Iterator是正向迭代,而且ListIterator还可以通过add方法向List集合中添加元素,Iterator只能删除元素、

ArrayList和Vector实现类

ArrayList和Vector类都是基于数组实现的List类,所以ArrayList和Vector类分装了一个动态的,允许再分配的Object[]数组。ArrayList或Vector对象使用initialCapacity参数来设置该数组的长度,当向ArrayList或Vector中添加元素超出了该数组的长度时,他们的initialCapacity会自动增加。

ArrayList和Vector的区别是:ArrayList是线程不安全的,当多个线程访问同一个ArrayList集合时,如果有超过一个线程修改了ArrayList集合,则程序必须手动保证该集合的同步性,但Vector集合则是线程安全的,无须程序保证该集合的同步性。因此Vector是线程安全的,所以Vector的性能比ArrayList的性能要低;

Vector提供了Stack子类,它用于模拟栈这种数据结构,栈筒仓是指后进先出LIFO的容器,最后push进栈的元素,将最先被pop出栈,出入栈的都是Object,

如果程序需要使用栈这种数据结构,则可以考虑ArrayDeque。

ArrayDeque底层是基于数组实现的,因此性能很好。

public class ArrayListAndVector {

public static void main(String[] args) {

Stack vector = new Stack<>();

vector.push("1");

vector.push("2");

vector.push("3");

while (!vector.empty()) {

System.out.println(vector.pop());// 3 2 1

//System.out.println(vector.peek()); 会死循环,因为栈内不会弹出所以判断会一直执行。

}

}

}

固定长度的List

Arrays提供了asList(Object...a)方法,该方法可以把一个数组或指定个数的对象转化成一个List集合,这个List集合时Arrays的内部类ArrayList的实例。

Array.ArrayList是一个固定长度的List集合,程序只能遍历该集合里的元素,不可增加,删除该集合里的元素。

public class FixedSizeLists {

public static void main(String[] args) {

List asList = Arrays.asList(new String[]{"1","@","#","$"});

//Exception in thread "main" java.lang.UnsupportedOperationException

//System.out.println(asList.add("dsdsd"));

}

}

Queue集合

Queue用于模拟队列这种数据结构,队列通常是指“先进先出FIFO”的容器。队列的头部保存在队列中存放时间最长的元素,队列的尾部保存在队列中存放时间最短的元素。新元素插入offer到队列的尾部,访问元素poll操作会返回队列头部的元素。

Queue接口有一个接口Deque,Deque代表一个双端队列,双端队列可以同时从两端来添加元素,删除元素,因此Deque的实现类即可当成队列使用,也可当成栈使用。Java为Deque提供了ArrayDeque和LinkedList两个实现类。

public class QueueTest {

public static void main(String[] args) {

Queue queue = new ArrayDeque<>();

//将指定元素加入此队列的尾部,当使用有容量限制的队列时,此方法通常比add方法更好。

queue.offer(44);

queue.add(2);

//[44, 2]

System.out.println(queue);

queue.add(3);

//[44, 2, 3]

System.out.println(queue);

System.out.println(queue.poll());//44

System.out.println(queue);//[2, 3]

System.out.println(queue.peek());//2

System.out.println(queue);//[2, 3]

queue.remove();

System.out.println(queue);//[3]

queue.add(3434);

System.out.println(queue);//[3, 3434]

//返回队列头部元素,但是不删除该元素

System.out.println(queue.element());//3

System.out.println(queue);//[3, 3434]

System.out.println(queue.remove(3434));//true

System.out.println(queue);//[3]

}

}

PriorityQueue实现类 priority 优先的

PriorityQueue保存队列元素的元素并不是按加入队列的顺序,而是按队列元素的大小进行重新排序,因此当调用peek方法或者poll方法去除队列中的元素时,并不是取出最先进入队列的元素,而是取出队列中的最小的元素。PriorityQueue已经违反了队列的最基本的原则:先进先出

public class PriorityQueues {

public static void main(String[] args) {

PriorityQueue priorityQueue = new PriorityQueue<>();

priorityQueue.add(12);

priorityQueue.add(-6);

priorityQueue.add(-9);

priorityQueue.add(1);

//[-9, 1, -6, 12]

System.out.println(priorityQueue);

priorityQueue.poll();

//[-6, 1, 12]

System.out.println(priorityQueue);

}

}

PriorityQueue不允许插入null元素,PriorityQueue可以定制排序和自然排序。

PriorityQueue自然排序的元素必须实现Comparable接口,而且应该是同一个类的实例

PriorityQueue不要求队列元素实现Comparable接口。

Deque接口和ArrayDeque实现类

Deque接口是Queue接口的子接口,他代表一个双端队列。

ArrayList和ArrayDeque两个集合类的实现机制基本相同,他们的底层都是采用一个动态的可重新分配的Object[]数组来保存集合元素,当集合元素超出了该数组的容量时,系统会在底层重新分配一个Object[]数组来存储集合元素。

把ArrayDeque当成栈来使用

public class ArryDeque {

public static void main(String[] args) {

Deque deque = new ArrayDeque<>();

deque.push(1);

deque.push(2);

deque.push(3);

deque.push(4);

//[4, 3, 2, 1]

System.out.println(deque);

System.out.println(deque.pop()); // 4

System.out.println(deque);//[3, 2, 1]

}

} //后入先出

把ArrayDeque当成队列使用

public class ArryDeque2 {

public static void main(String[] args) {

Deque deque = new ArrayDeque<>();

deque.offer(1123);

deque.offer(143);

deque.offer(-11);

System.out.println(deque);//[1123, 143, -11]

System.out.println(deque.poll());//1123

System.out.println(deque);//[143, -11]

System.out.println(deque.poll());//143

System.out.println(deque);//[-11]

}

}

ArrayDque不仅可以作为栈使用,也可以作为队列使用。

LinkedList实现类

可以根据索引来随机访问集合中的元素,LinkedList还是实现了Deque接口,可以被当成双端队列来使用,因此既可以被当成栈使用,也可以当做为队列使用。

public class LinkedListTest {

public static void main(String[] args) {

LinkedList linkedList = new LinkedList<>();

//将数组元素加入栈顶

linkedList.push(1);

//将数组元素加入栈底

linkedList.offer(2);

//[1, 2]

System.out.println(linkedList);

//加入栈顶

linkedList.offerFirst(3);

//[3, 1, 2]

System.out.println(linkedList);

for (int i = 0; i < linkedList.size(); i++) {

System.out.println(linkedList.get(i)); //3 1 2

}

//访问但不删除栈底

System.out.println(linkedList.peekLast());//2

//[3, 1, 2]

System.out.println(linkedList);

//访问但不删除栈顶

System.out.println(linkedList.peekFirst());//3

//[3, 1, 2]

System.out.println(linkedList);

//访问并删除栈顶

System.out.println(linkedList.pollFirst());//3

//[1, 2]

System.out.println(linkedList);

}

}

LinkedList和ArrayList和ArrayDeque实现机制完全不同

ArrayList,ArrayDeque内部以数组的形式来保存集合中的元素,因此随机访问几个元素时具有较好的性能,而LinkedList内部以链表的形式来保存集合中的元素,因此随机访问集合元素时性能较差,但在插入,删除元素时性能比较出色,只需要改变指针所指的地址即可。

对于所有的内部基于数组的集合实现,例如ArrayList和ArrayDeque等,使用随机访问的性能比使用Iterator迭代访问的性能要好,因为随机访问会被映射成对数组元素的访问。

各种线性表的性能分析

Java提供的List就是一个线性表接口,而ArrayList,LinkedList又是线性表的两种典型实现:基于数组的线性表和基于链的线性表。Queue代表了队列,Deque代表了双端队列,既可以作为队列使用,又可以当做栈使用。

LinkedList集合不仅提供了List的功能,还提供了双端队列,栈的功能。

一般来说,由于数组以一块连续内存区来保存所有的数组元素,所以数组在随机访问时性能最好,所有的内部以数组作为底层实现的集合在随机访问时性能都比较好。而内部以链表作为底层实现的集合在执行插入,删除操作时有较好的性能。但总体来说,ArrayList的性能比LinkedList的性能要好,因此大部分时候都应该考虑使用ArrayList。

使用List集合的一些建议

如果需要遍历List集合,对于ArrayList,Vector集合,应该是用随机访问方法get来遍历集合元素,这样性能更好。对于LinkedList集合,则应该采用迭代器Iterator来遍历集合元素。

如果需要经常执行插入,删除操作来改变含大量数据的List集合的大小,则可考虑使用LinkedList集合,使用ArrayList,Vector集合可能需要经常分配内部数组的大小,效果可能较差。

如果有多个线程需要访问List集合中的元素,需要考虑使用Collections将几个包装成线程安全集合。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值