java(八)数据结构–(九)集合

本文深入探讨了Java数据结构中的集合概念,包括数组、多维数组、动态数组(集合)以及各种集合类如List、Set、Map等。文章详细介绍了集合类的基本概念、层次关系,并对比了ArrayList和Vector的区别。此外,还涵盖了树、枚举、位集合、向量、栈、字典、哈希表和属性等数据结构,以及冒泡排序的原理和实现。
摘要由CSDN通过智能技术生成

目录

 

java(八)数据结构–(九)集合

数组

多维数组

动态数组

集合

1. Java集合类基本概念

2. Java集合类架构层次关系

树(tree)

相关术语

种类

枚举(Enumeration)

位集合(BitSet)

向量(Vector)

栈(Stack)

字典(Dictionary)

哈希表(Hashtable)

属性(Properties)

冒泡排序

原理:

思路:

小结


 

 

java(八)数据结构–(九)集合

  • 程序=数据结构+算法
  • 数据结构就是装数据的容器

数据结构由成百上千种,以下举例击中常见的

数组

  1. 数组:物理地址连续的一块内存空间

数组模型

在数组中除了较为常见的一维数组、二维数组外,还有较为复杂的多维数组、以及动态数组。

多维数组

多维数组是指三维及其以上的维度的数组。 
以三维为例:在理解时可以在在脑海中构建一个方体,这个方体的长、宽、高就可以理解为三维数组的三个维度,类似于二维数组的行和列,三维数组多了一个层。如下图所示:红色为行、黄色位列、蓝色为层。那么我们可以说蓝色的3存在数组的0,0,3。即是0行,0列,3层。

数组模型

动态数组

动态数组与静态数组的区别是,今静态数组在创建时,必须交代数组的大小或是直接将数组里的元素写入进去,另外静态数组在元素存储时,要注意在存储满时,会有内存溢出的情况。而动态数组在创建时不需要交代这些,在数组存储满的时候会自行扩容。在JAVA中动态数组也被称之为集合,JAVA也提供了List集合、Map集合等等。

集合

1. Java集合类基本概念

在编程中,常常需要集中存放多个数据。从传统意义上讲,数组是我们的一个很好的选择,前提是我们事先已经明确知道我们将要保存的对象的数量。一旦在数组初始化时指定了这个数组长度,这个数组长度就是不可变的,如果我们需要保存一个可以动态增长的数据(在编译时无法确定具体的数量),java的集合类就是一个很好的设计方案了。

集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类。所以的集合类都位于java.util包下,后来为了处理多线程环境下的并发安全问题,java5还在java.util.concurrent包下提供了一些多线程支持的集合类

Java容器类类库的用途是”保存对象”,并将其划分为两个不同的概念:

1) Collection 
一组”对立”的元素,通常这些元素都服从某种规则 
  1.1) List必须保持元素特定的顺序–有序性 
  1.2) Set不能有重复元素–唯一性 
  1.3) Queue保持一个队列(先进先出)的顺序 
2) Map 
一组成对的”键值对“对象

Collection和Map的区别在于容器中每个位置保存的元素个数: 
1) Collection 每个位置只能保存一个元素(对象) 
2) Map保存的是“键值对”,就像一个小型数据库。我们可以通过”键”找到该键对应的”值”

2. Java集合类架构层次关系

1. Interface Iterable

迭代器接口,这是Collection类的父接口。实现这个Iterable接口的对象允许使用foreach进行遍历,也就是说,所有的Collection集合对象都具有”foreach可遍历性”。这个Iterable接口只 
有一个方法: iterator()。它返回一个代表当前集合对象的泛型迭代器,用于之后的遍历操作

1.1 Collection

Collection是最基本的集合接口,一个Collection代表一组Object的集合,这些Object被称作Collection的元素。Collection是一个接口,用以提供规范定义,不能被实例化使用

1) Set—无序且唯一

Set集合类似于一个罐子,"丢进"Set集合里的多个对象之间没有明显的顺序。Set继承自Collection接口不能包含有重复元素(记住,这是整个Set类层次的共有属性)

 

Set判断两个对象相同不是使用"=="运算符,而是根据equals方法。也就是说,我们在加入一个新元素的时候,如果这个新元素对象和Set中已有对象进行注意equals比较都返回false,否则Set就会接受这个新元素对象,否则拒绝。

 

因为Set的这个制约,在使用Set集合的时候,应该注意两点:1) 为Set集合里的元素的实现类实现一个有效的equals(Object)方法、2) 对Set的构造函数,传入的Collection参数不能包含重复的元素

 

 

1.1) HashSet

HashSet是Set接口的典型实现,HashSet使用HASH算法来存储集合中的元素,因此具有良好的存取和查找性能。当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据该HashCode值决定该对象在HashSet中的存储位置。

 

值得主要的是,HashSet集合判断两个元素相等的标准是两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法的返回值相等

 

 

1.1.1) LinkedHashSet

LinkedHashSet集合也是根据元素的hashCode值来决定元素的存储位置,但和HashSet不同的是,它同时使用链表维护元素的次序,这样使得元素看起来是以插入的顺序保存的。

当遍历LinkedHashSet集合里的元素时,LinkedHashSet将会按元素的添加顺序来访问集合里的元素。

LinkedHashSet需要维护元素的插入顺序,因此性能略低于HashSet的性能,但在迭代访问Set里的全部元素时(遍历)将有很好的性能(链表很适合进行遍历)

 

1.2) SortedSet

此接口主要用于排序操作,即实现此接口的子类都属于排序的子类

 

1.2.1) TreeSet

TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态

 

1.3) EnumSet

EnumSet是一个专门为枚举类设计的集合类,EnumSet中所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式、或隐式地指定。EnumSet的集合元素也是有序的,它们以枚举值在Enum类内的定义顺序来决定集合元素的顺序

2) List——有序、可重复

List集合代表一个元素有序、可重复的集合,集合中每个元素都有其对应的顺序索引。List集合允许加入重复元素,因为它可以通过索引来访问指定位置的集合元素。List集合默认按元素的添加顺序设置元素的索引

 

2.1) ArrayList

ArrayList是基于数组实现的List类,它封装了一个动态的增长的、允许再分配的Object[]数组。

 

2.2) Vector

Vector和ArrayList在用法上几乎完全相同,但由于Vector是一个古老的集合,所以Vector提供了一些方法名很长的方法,但随着JDK1.2以后,java提供了系统的集合框架,就将Vector改为实现List接口,统一归入集合框架体系中

 

2.2.1) Stack

Stack是Vector提供的一个子类,用于模拟"栈"这种数据结构(LIFO后进先出)

 

2.3) LinkedList

implements List<E>, Deque<E>。实现List接口,能对它进行队列操作,即可以根据索引来随机访问集合中的元素。同时它还实现Deque接口,即能将LinkedList当作双端队列使用。自然也可以被当作"栈来使用"

ArrayList,Vector主要区别为以下几点: 
(1):Vector是线程安全的,源码中有很多的synchronized可以看出,而ArrayList不是。导致Vector效率无法和ArrayList相比; 
(2):ArrayList和Vector都采用线性连续存储空间,当存储空间不足的时候,ArrayList默认增加为原来的50%,Vector默认增加为原来的一倍; 
(3):Vector可以设置capacityIncrement,而ArrayList不可以,从字面理解就是capacity容量,Increment增加,容量增长的参数。

3) Queue

Queue用于模拟"队列"这种数据结构(先进先出 FIFO)。队列的头部保存着队列中存放时间最长的元素,队列的尾部保存着队列中存放时间最短的元素。新元素插入(offer)到队列的尾部访问元素(poll)操作会返回队列头部的元素,队列不允许随机访问队列中的元素。结合生活中常见的排队就会很好理解这个概念

3.1) PriorityQueue

PriorityQueue并不是一个比较标准的队列实现,PriorityQueue保存队列元素的顺序并不是按照加入队列的顺序,而是按照队列元素的大小进行重新排序,这点从它的类名也可以看出来

3.2) Deque

Deque接口代表一个"双端队列",双端队列可以同时从两端来添加、删除元素,因此Deque的实现类既可以当成队列使用、也可以当成栈使用

3.2.1) ArrayDeque

是一个基于数组的双端队列,和ArrayList类似,它们的底层都采用一个动态的、可重分配的Object[]数组来存储集合元素,当集合元素超出该数组的容量时,系统会在底层重新分配一个Object[]数组来存储集合元素

1.2 Map

Map用于保存具有“映射关系”的数据,因此Map集合里保存着两组值,一组值用于保存Map里的key,另外一组值用于保存Map里的value。key和value都可以是任何引用类型的数据。Map的key不允许重复,即同一个Map对象的任何两个key通过equals方法比较结果总是返回false。 
关于Map,我们要从代码复用的角度去理解,java是先实现了Map,然后通过包装了一个所有value都为null的Map就实现了Set集合 
Map的这些实现类和子接口中key集的存储形式和Set集合完全相同(即key不能重复) 
Map的这些实现类和子接口中value集的存储形式和List非常类似(即value可以重复、根据索引来查找)

 

1) HashMap

和HashSet集合不能保证元素的顺序一样,HashMap也不能保证key-value对的顺序。并且类似于HashSet判断两个key是否相等的标准也是: 两个key通过equals()方法比较返回true、同时两个key的hashCode值也必须相等

1.1) LinkedHashMap

LinkedHashMap也使用双向链表来维护key-value对的次序,该链表负责维护Map的迭代顺序,与key-value对的插入顺序一致(注意和TreeMap对所有的key-value进行排序进行区分)

2) Hashtable

是一个古老的Map实现类

2.1) Properties

Properties对象在处理属性文件时特别方便(windows平台上的.ini文件),Properties类可以把Map对象和属性文件关联起来,从而可以把Map对象中的key-value对写入到属性文件中,也可以把属性文件中的"属性名-属性值"加载到Map对象中

3) SortedMap

正如Set接口派生出SortedSet子接口,SortedSet接口有一个TreeSet实现类一样,Map接口也派生出一个SortedMap子接口,SortedMap接口也有一个TreeMap实现类

3.1) TreeMap

TreeMap就是一个红黑树数据结构,每个key-value对即作为红黑树的一个节点。TreeMap存储key-value对(节点)时,需要根据key对节点进行排序。TreeMap可以保证所有的

     key-value对处于有序状态。同样,TreeMap也有两种排序方式: 自然排序、定制排序

4) WeakHashMap

WeakHashMap与HashMap的用法基本相似。区别在于,HashMap的key保留了对实际对象的"强引用",这意味着只要该HashMap对象不被销毁,该HashMap所引用的对象就不会被垃圾回收。

  但WeakHashMap的key只保留了对实际对象的弱引用,这意味着如果WeakHashMap对象的key所引用的对象没有被其他强引用变量所引用,则这些key所引用的对象可能被垃圾回收,当垃圾回收了该key所对应的实际对象之后,WeakHashMap也可能自动删除这些key所对应的key-value对

5) IdentityHashMap

IdentityHashMap的实现机制与HashMap基本相似,在IdentityHashMap中,当且仅当两个key严格相等(key1 == key2)时,IdentityHashMap才认为两个key相等

6) EnumMap

EnumMap是一个与枚举类一起使用的Map实现,EnumMap中的所有key都必须是单个枚举类的枚举值。创建EnumMap时必须显式或隐式指定它对应的枚举类。EnumMap根据key的自然顺序

  (即枚举值在枚举类中的定义顺序)

HashMap,HashTable主要区别为以下几点:

  1. HashMap是继承自AbstractMap类,而HashTable是继承自Dictionary类。不过它们都实现了同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口
  2. Hashtable既不支持Null key也不支持Null value。Hashtable的put()方法的注释中有说明。 HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null
  3. Hashtable是线程安全的,它的每个方法中都加入了Synchronize方法。在多线程并发的环境下,可以直接使用Hashtable,不需要自己为它的方法实现同步
  4. HashMap不是线程安全的,在多线程并发的环境下,可能会产生死锁等问题。使用HashMap时就必须要自己增加同步处理,
  5. HashMap不是线程安全的,但是它的效率会比Hashtable要好很多。

树(tree)

树是有n(n>=1)个节点组成的具有层次性的集合。是一种常见到的数据结构 
特点:

  • 每个节点都有零个或多个子节点;
  • 没有父节点的节点被称之为根节点;
  • 每一个非根节点有且只有一个父节点;
  • 每一个非根节点都可以将其分为多个不想交的子树;

相关术语

  1. 度:一个节点含有的子树个数;
  2. 叶节点/终端节点:度等于0的节点;
  3. 分支节点/非终端节点:度不等于0;
  4. 双亲节点/父节点:一个含有子节点的节点,则称其为其子节点的父节点;
  5. 孩子节点/子节点:一个节点含有子树的根节点称为该节点的子节点;
  6. 兄弟节点:拥有相同父节点的节点;
  7. 树的度:最大节点的度,称为树的度;
  8. 节点的层次:从根节点开始,根节点为第一层,根节点的子节点为第二层,依次类推;
  9. 数的高度/深度:节点的最大层次;
  10. 堂兄弟节点:双亲在同一层的节点;
  11. 森林:由m(m>=0)颗不相交的树。

种类

无序树

树中任意节点的子节点之间没有顺序关系,这种树叫无序树,也称自由树;

有序树

树中任意节点的子节点之间都有顺序关系,这种树叫有序树;

二叉树

每个节点的最多含有两个子树的树;

完全二叉树

深度为n的树中,除了第n层之外的层次的节点数都达到了最大,最后一层(第n层)的节点都集中在数的左边。

 

完全二叉树和非完全二叉树

完全二叉树的第i层最多会有个节点 
共i层的完全的二叉树最多有个节点 
完全二叉树中,只允许最后一层有空缺节点且空缺在右边 
对于任意节点的,如果其右子树的深度为j,则其左子树的深度为j或j+1.

满二叉树

一个二叉树中,如果每一层的节点数都达到最大值,则这个二叉树就是满二叉树。也就是说,除了最后一层无任何节点外,每一层上的节点都有两个子节点的二叉树

 

满二叉树

  • 一个二叉树的层数为K,且节点总数是。因此满二叉树中的节点数一定是奇数个
  • 第i层上的节点数为 
    层数为K的满二叉树中最后一层皆为

哈夫曼树

哈夫曼树(霍夫曼树)又称最优二叉树,在给定的n个全值 
构造 
哈夫曼树的构造 
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为: 
(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点); 
(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和; 
(3)从森林中删除选取的两棵树,并将新树加入森林; 
(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

枚举(Enumeration)

枚举(Enumeration)接口虽然它本身不属于数据结构,但它在其他数据结构的范畴里应用很广。 枚举(The Enumeration)接口定义了一种从数据结构中取回连续元素的方式。 
例如,枚举定义了一个叫nextElement 的方法,该方法用来得到一个包含多元素的数据结构的下一个元素。 
关于枚举接口的更多信息,请参见枚举(Enumeration)。

位集合(BitSet)

位集合类实现了一组可以单独设置和清除的位或标志。 
该类在处理一组布尔值的时候非常有用,你只需要给每个值赋值一”位”,然后对位进行适当的设置或清除,就可以对布尔值进行操作了。 
关于该类的更多信息,请参见位集合(BitSet)。

向量(Vector)

向量(Vector)类和传统数组非常相似,但是Vector的大小能根据需要动态的变化。 
和数组一样,Vector对象的元素也能通过索引访问。 
使用Vector类最主要的好处就是在创建对象的时候不必给对象指定大小,它的大小会根据需要动态的变化。 
关于该类的更多信息,请参见向量(Vector)

栈(Stack)

栈(Stack)实现了一个后进先出(LIFO)的数据结构。 
你可以把栈理解为对象的垂直分布的栈,当你添加一个新元素时,就将新元素放在其他元素的顶部。 
当你从栈中取元素的时候,就从栈顶取一个元素。换句话说,最后进栈的元素最先被取出。 
关于该类的更多信息,请参见栈(Stack)。

字典(Dictionary)

字典(Dictionary) 类是一个抽象类,它定义了键映射到值的数据结构。 
当你想要通过特定的键而不是整数索引来访问数据的时候,这时候应该使用Dictionary。 
由于Dictionary类是抽象类,所以它只提供了键映射到值的数据结构,而没有提供特定的实现。 
关于该类的更多信息,请参见字典( Dictionary)。

哈希表(Hashtable)

Hashtable类提供了一种在用户定义键结构的基础上来组织数据的手段。 
例如,在地址列表的哈希表中,你可以根据邮政编码作为键来存储和排序数据,而不是通过人名。 
哈希表键的具体含义完全取决于哈希表的使用情景和它包含的数据。 
关于该类的更多信息,请参见哈希表(HashTable)。

属性(Properties)

Properties 继承于 Hashtable.Properties 类表示了一个持久的属性集.属性列表中每个键及其对应值都是一个字符串。 
Properties 类被许多Java类使用。例如,在获取环境变量时它就作为System.getProperties()方法的返回值。

冒泡排序

原理:

比较两个相邻的元素,将值大的元素交换至右端。

思路:

依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。重复第一趟步骤,直至全部排序完成。

小结

N个数字要排序完成,总共进行N-1趟排序,每i趟的排序次数为(N-i)次,所以可以用双重循环语句,外层控制循环多少趟,内层控制每一趟的循环次数,即

for(int i=1;i<arr.length;i++){

for(int j=1;j<arr.length-i;j++){

//交换位置

}

}

文章内容来自网络摘取,如有雷同纯属巧合。

文章是本人的复习笔记,分享给大家。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值