前言:许多基础数据类型都和对象的集合有关。具体来说,数据类型的值就是一组对象的集合,所有操作都是关于添加、删除或是访问集合中的对象。而且有很多高级数据结构都是以这样的结构为基石创造出来的,在本文中,我们将了解学习三种这样的数据类型,分别是背包(Bag)、栈(Stack)和队列(Queue)
一、学习感悟
对于数据结构的学习可以用以下步骤来学习:
- 首先先对该结构的场景操作进行API化;
- 然后再对数据类型的值的所有可能的表示方法以及各种操作的实现;
- 总结特点和比较;
接下来就对这三种数据类型进行介绍。
二、API
这三种数据类型都是依赖于之前介绍过的线性表的链式存储结构的,所以理解并掌握链式结构是学习各种算法和数据结构的第一步,若还不是很清楚,可以看一下前面关于线性表的链式存储结构的文章(本文主要是对链式存储结构的进行介绍,如想要对顺序存储结构了解的话,可根据其特性和API进行编写代码,欢迎在评论区留言讨论)。
2.1、背包(Bag)
背包是一种不支持从中删除元素的集合数据类型——它的目的就是帮助用例收集元素并迭代遍历所有收集到的元素(用例也可以检查背包是否为空或者获取背包中元素的数量)。
要理解背包的概念,可以想象一个喜欢收集弹珠球的人。他将所有的弹珠球都放在一个背包里,一次一个,并且会不时在所有的弹珠球中寻找某一颗;


2.1.1 背包API
根据以上的需求,可以写出背包的API:
public class Bag<Item> implements Iterable<Item> Bag() 创建一个空背包 void add(Item item) 添加一个元素 boolean isEmpty() 背包是否为空 int size() 背包中的元素数量
使用Bag的API,用例可以将元素添加进背包并根据需要随时使用foreach语句访问所有的元素。用例也可以使用栈或是队列,但是用Bag可以说明元素的处理顺序不重要,比如在计算一堆Double值的平均值时,无需关注背包元素相加的顺序,只需要在得到所有值的和后除以Bag中元素的数量即可。
2.1.2 背包实现
根据2.1.1的API写出具体的实现,其中关键方法add使用了头插法:
Bag.java核心代码为add(),使用了头插法::
//由于Bag类型不需要考虑元素的相对顺序,所以这里我们可以使用头插法来进行插入,提高效率 public void add(T t) { Node<T> newNode = new Node<>(); newNode.t = t; newNode.next = first.next; first.next = newNode; size++; }
2.1.3 总结
上面就是关于Bag数据类型的实现,从中可以看出Bag是一种不支持删除元素的、无序的、专注于取和存的集合类型。
2.2、栈(Stack)
下压栈(或简称栈)是一种基于后进先出(LIFO)策略的集合类型。比如在桌子上对方一叠书,我们拿书时,一般都是从最上面开始取的,这样的操作就类似栈。


栈管理数据的两种操作如下:
- 写入数据(堆积)操作称作入栈(PUSH);
- 读取数据操作称作出栈(POP);
栈类型的模型结构在生活中的应用也不少,比如浏览器的回退功能,在一个浏览器tag页上打开的网页,通过回退功能可以一次回退到历史最近的浏览记录。还有电脑软件撤销功能,也是这样的策略模型。
栈是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一段被称为栈顶,相对的,把另一端称为

