Java学习笔记——浅谈数据结构与Java集合框架(第二篇、Queue、Set)

江南好,何处异京华。

香散翠帘多在水,绿残红叶胜于花。无事避风沙。

                              ——《纳兰词》

诗词再好,大图不能忘

上大图:

先说说栈和队列:

栈就好比手枪的弹匣,你往里面压入子弹,最先压入的子弹就到了弹匣最底部的位置,最后压入的子弹在弹匣顶部。发射子弹的时候每次将弹匣顶部的子弹弹出发射。无法越过顶部子弹发射下面的子弹。

栈(stack)是限定仅在表尾进行插入和删除操作的线性表,LIFO

队列就跟上学那会儿排队打饭一样,但是不能加塞儿。

队列(queue)是只允许在队列一端进行插入操作,另一端进行删除操作的线性表,FIFO

这里要特别说明Java中的队列是双向队列(Deque),包括了栈和队列的所有方法

双向队列也分为两种,顺序结构和链式结构。咱们看Deque接口实现类的名字就能看出来ArrayDeque是顺序存储结构,LinkedList是链式存储结构

基本原理就不再赘述了,第一篇已经讲过了顺序结构线性表和链式结构线性表。这里的栈和队列并不是什么新东西,只是两种不同的思维方式,对应了各自不同的方法罢了。

上代码:

 1 public class ArrayDequeStackDemo {
 2
 3     public static void main(String[] args) {
 4         ArrayDeque<String> stack = new ArrayDeque<>();
 5         //以下均为栈操作,在逻辑上把队列想象成一个栈,FILO
 6         stack.push("疯狂Java讲义");
 7         stack.push("轻量级Java EE 企业应用实战");
 8         stack.push("疯狂Android讲义");
 9         //[疯狂Android讲义, 轻量级Java EE 企业应用实战, 疯狂Java讲义]
10         System.out.println(stack);
11
12         //“窥视”栈顶第一个元素,而不出栈。输出:疯狂Android讲义
13         System.out.println(stack.peek());
14         //依然输出[疯狂Android讲义, 轻量级Java EE 企业应用实战, 疯狂Java讲义]
15         System.out.println(stack);
16
17         //获取栈顶,并pop出栈。输出:疯狂Android讲义
18         System.out.println(stack.pop());
19         //[轻量级Java EE 企业应用实战, 疯狂Java讲义]
20         System.out.println(stack);
21     }
22 }
 1 public class ArrayDequeQueueDemo {
 2
 3     public static void main(String[] args) {
 4         ArrayDeque<String> queue = new ArrayDeque<>();
 5         //以下均为队列操作,在逻辑上把队列想象成一个栈,FIFO
 6         queue.offer("疯狂Java讲义");
 7         queue.offer("轻量级Java EE 企业应用实战");
 8         queue.offer("疯狂Android讲义");
 9         //[疯狂Java讲义, 轻量级Java EE 企业应用实战, 疯狂Android讲义]
10         System.out.println(queue);
11
12         //“窥视”栈顶第一个元素,而不出栈。输出:疯狂Java讲义
13         System.out.println(queue.peek());
14         //依然输出[疯狂Java讲义, 轻量级Java EE 企业应用实战, 疯狂Android讲义]
15         System.out.println(queue);
16
17         //poll投票的意思,想象玩狼人杀投死第一个人,输出:疯狂Java讲义
18         System.out.println(queue.poll());
19         //[轻量级Java EE 企业应用实战, 疯狂Android讲义]
20         System.out.println(queue);
21     }
22 }

队列和栈的操作基本上就是这些

再说说Set集合

Set集合就像一个袋子,里面装着若干元素,它们无序且不能重复。

HashSet是Set的实现类,HashSet中的元素无序且不可重复

上代码:

 1 public class HashSetTest {
 2
 3     public static void main(String[] args) {
 4         HashSet<Object> h = new HashSet<>();
 5         h.add(new ClassA());//A类重写equals(Object o),return true
 6         h.add(new ClassA());//equals相等,hashCode不等
 7         h.add(new ClassB());//重写hashCode(),return 1
 8         h.add(new ClassB());//hashCode相等,equals不等
 9         h.add(new ClassC());//重写equals(Object o),return true;重写hashCode(),return 2;
10         h.add(new ClassC());//并没有添加成功,hashCode和equals都相等,这两个对象在HashSet中相等
11         h.add(new ClassC2());//new ClassC2类,重写代码和ClassC一样,一样添加不了.说明hashCode只比较@后面的hashCode值,和@前面的东西无关
12         System.out.println(h);
13         //只看包名后面的结果:[email protected],[email protected],[email protected],[email protected],[email protected]
14     }
15 }

 1 public class ClassA {
 2
 3     public boolean equals(Object o){
 4         return true;
 5     }
 6 }
 7 public class ClassB {
 8
 9     public int hashCode(){
10         return 1;
11     }
12 }
13 public class ClassC {
14
15     public int hashCode(){
16         return 2;
17     }
18     public boolean equals(Object o){
19         return true;
20     }
21 }
22 public class ClassC2 {
23
24     public int hashCode(){
25         return 2;
26     }
27     public boolean equals(Object o){
28         return true;
29     }
30 }

1、基础知识:HashSet判断连个元素相等的方法:hashCode值相等 && equals 为true。

HashSet集合里的元素都没有索引。当程序向HashSet中添加元素的时候,HashSet会根据该元素的hashCode值来计算它的存储位置。访问数据的时候HashSet先计算该元素的hashCode值,再到对应的位置取元素。

所以HashSet访问元素也是很快的。

2、使用HashSet时可能会重写hashCode方法,如果重写了equals方法或者hashCode方法可能会导致一些问题

上代码:

 1 import java.util.HashSet;
 2 import java.util.Iterator;
 3
 4 public class HashSetTest2 {
 5
 6     public static void main(String[] args) {
 7         HashSet<ClassR> h = new HashSet<>();
 8         h.add(new ClassR(1));
 9         h.add(new ClassR(2));
10         h.add(new ClassR(3));
11         h.add(new ClassR(4));
12         h.add(new ClassR(4));//是不能加入相同元素的
13         System.out.println(h);
14         h.remove(new ClassR(4));//可以这样删除
15         System.out.println(h);
16         Iterator<ClassR> it = h.iterator();
17         ClassR r = (ClassR)it.next(); //把第一个元素赋值给r
18         r.count = 2;//将集合中元素ClassR(1)值变成2,这样就和ClassR(2)重复了,hashCode和equals都相等
19         System.out.println(h);
20         h.remove(new ClassR(2));//删除classR(2)
21         h.remove(new ClassR(1));//原来的1已经不是1了,现在集合中没有地址为ClassR(1)地址,值为1的元素,所以无法删除
22         System.out.println(h);//这里剩下的应该就是原来的ClassR(1)(现在count值变成了2)和ClassR(3)
23         System.out.println("h中是否包含count为2的对象?"+h.contains(new ClassR(2))
24                 + "\nh中是否包含count为1的对象?"+h.contains(new ClassR(1)));
25     }
26 }

 1 public class ClassR {
 2
 3     int count;
 4     public ClassR(int count){
 5         this.count = count;
 6     }
 7     public String toString(){
 8         return "R[count:"+count+"]";
 9     }
10     public boolean equals(Object o){
11         if (this == o)
12             return true;
13         if (o != null && o.getClass() == ClassR.class) {
14             ClassR r = (ClassR)o;
15             return this.count == r.count;
16         }
17         return false;
18     }
19     public int hashCode(){
20         return this.count;
21     }
22 }

以上是重写hashCode和equals算法的例子,对比不重写hashCode和equals算法,代码用之前的把ClassR中的重写内容删除就行了。

如果不重写,那么new出来的对象都是不同的元素(至少表面上看是这样,遗憾的是hashCode算法是native方法,无需探知。这里假设元素不是很多的情况下hashCode不会重复),但是重写之后你会发现new出来的对象不仅hashCode会相等,甚至更改某对象属性(字段)后居然两个对象equals为true了。这将会导致HashSet无法准确访问该元素。

3、HashSet优点:HashSet可以自由增加自身长度,并且访问元素速度很快

4、HashSet有个子类叫LinkedHashSet.

LinkedHashSet继承了父类的算法和寻址方式,其新增功能是使用链表维护内部顺序。由于需要维护元素的插入顺序,LinkedHashSet性能略低于其父类HashSet,但是在迭代访问Set中全部元素时有很好的性能。

最后TreeSet是Set的另一个实现类,TreeSet中的元素是有序不可重复的。

1、自然排序

TreeSet会调用集合元素的compareTo(Object obj)方法比较元素之间的大小关系,然后将集合中元素按照升序排列,这就是自然排序

2、定制排序

可重写compareTo方法实现定制排序。

Set就说到这里吧。

时间: 2024-08-09 19:48:03

Java学习笔记——浅谈数据结构与Java集合框架(第二篇、Queue、Set)的相关文章

Java学习笔记——浅谈数据结构与Java集合框架(第一篇、List)

横看成岭侧成峰,远近高低各不同.不识庐山真面目,只缘身在此山中. --苏轼 这一块儿学的是云里雾里,咱们先从简单的入手.逐渐的拨开迷雾见太阳.本次先做List集合的三个实现类的学习笔记 List特点:有序,元素可重复.其实它的本质就是一个线性表(下面会说到) 先上图,Java集合有Collection体系和Map体系: 然后简单介绍一下数据结构和算法: 数据结构就是数据和数据之间的关系,好比分子结构,晶体结构.碳原子按照一定的方式组合在一起形成碳分子,碳分子再按照一定方式形成晶体. 算法是对解题

疯狂Java学习笔记(53)------------Annotation(注释)第二篇

JDK的元Annotation JDK除了java.lang下提供了3个基本Annotation之外,还在java.lang.annotation包下提供了四个Meta Annotation(元Annotation),这四个都是用于修饰其它Annotation定义 (1)使用@Retention @Retention只能用于修饰一个Annotation定义,用于该Annotation可以保留多长时间,@Retention包含一个RetentionPolicy类型的value成员变量,所以使用@R

疯狂Java学习笔记(70)-----------挚爱Java

与大家分享! 挚爱Java 10个使用Java最广泛的现实领域 写好Java代码的30条经验总结 Java字符串的substring真的会引起内存泄露么? Java内存的原型及工作原理深度剖析 Java 8中HashMap的性能提升 Java内存的原型及工作原理深度剖析 请不要说自己是Java程序猿 Java程序猿必须掌握的8大排序算法 推荐.国外程序猿整理的Java资源大全 编程开发 10个强大的纯CSS3动画案例分享 前端project师的神器Sublime Text使用介绍 浅谈SQL语句

疯狂Java学习笔记(84)----------关于 Java 对象序列化您不知道的 5 件事

数年前,当和一个软件团队一起用 Java 语言编写一个应用程序时,我体会到比一般程序员多知道一点关于 Java 对象序列化的知识所带来的好处. 关于本系列 您觉得自己懂 Java 编程?事实上,大多数程序员对于 Java 平台都是浅尝则止,只学习了足以完成手头上任务的知识而已.在本 系列 中,Ted Neward 深入挖掘 Java 平台的核心功能,揭示一些鲜为人知的事实,帮助您解决最棘手的编程挑战. 大约一年前,一个负责管理应用程序所有用户设置的开发人员,决定将用户设置存储在一个 Hashta

疯狂Java学习笔记(84)----------大约 Java 对象序列化,你不知道 5 事

几年前,.当一个软件团队一起用 Java 书面申请.我认识比一般程序猿多知道一点关于 Java 对象序列化的知识所带来的优点. 关于本系列 您认为自己懂 Java 编程?其实,大多数程序猿对于 Java 平台都是浅尝则止,仅仅学习了足以完毕手头上任务的知识而已.在本 系列 中,Ted Neward 深入挖掘 Java 平台的核心功能,揭示一些鲜为人知的事实,帮助您解决最棘手的编程挑战. 大约一年前,一个负责管理应用程序全部用户设置的开发者,决定将用户设置存储在一个 Hashtable中,然后将这

java学习笔记(3):java的工作原理及相关基础

一.运行机制 如上图所示,图中内容即为Java的运行机制: 1.我们一开始所编写的代码文件存储格式为(如text.java)文件,这就是源程序文件 2.在Java编辑器的作用下,也就是就行了编译,形成字节码文件(如text.class)文件,其实,这个Java编译器是我们所说的Java虚拟机,其中,在命令行的处理方式如下: 要在当前文件目录下打开命令行进行编译 3.之后class文件经过类装载器.字节码校验器.解释器的处理,就变成了1010010……的二进制形式了,通过操作系统平台将结果显示在屏

Java学习笔记-5.常用数据结构

一.数组 1.Java是将数组作为对象来实现的,而非连续的存储空间 2.在Java中,数组时一个类,提供了一些方法和属性,如数组长度array.length 3.Java中数组名可视为对象引用,在初始化时,不能直接定义长度 例:int a[3];    //错误的声明方法 4.数组中的元素也可以是复合数据类型的,这时数组元素实际上是对象引用 例: Complex[] arr = new Complex[3]; int i; for(i = 0; i < arr.length; i++) { ar

疯狂Java学习笔记(52)-----------Annotation(注释)第一篇

从JDK1.5开始,Java中增加了对元数据(MetaData)的支持,也就是Annotation(注释),这种Annotation与Java程序中的单行注释和文本注释是有一定区别,也有一定联系的.其实,我们现在说的Annotation是代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理.通过Annotation,程序开发人员可以在不改变原来逻辑的情况下,在源文件嵌入一些补充的信息.代码分析工具,开发工具和部署工具可通过这些补充信息进行验正或者部署. Annotatio

Java学习笔记—第十二章 Java网络编程入门

第十二章  Java网络编程入门 Java提供的三大类网络功能: (1)URL和URLConnection:三大类中最高级的一种,通过URL网络资源表达方式,可以很容易确定网络上数据的位置.利用URL的表示和建立,Java程序可以直接读入网络上所放的数据,或把自己的数据传送到网络的另一端. (2)Socket:又称"套接字",用于描述IP地址和端口(在Internet中,网络中的每台主机都有一个唯一的IP地址,而每台主机又通过提供多个不同端口来提供多种服务).在客户/服务器网络中,当客