疯狂java10--数据结构之栈和队列

引入--

栈和队列是两种特殊的线性表。比如采用广度优先的方法来遍历二叉树,那你需要一个队列来保存节点;比如想自己实现递归计算,那你需要一个栈;从功能上看,栈和队列都是一种功能弱化的线性表,但从实际用途上看,栈和队列必不可少。例如编译器实现函数调用的时候需要使用栈来存储断点,实现递归算法时也需要使用栈来存储。

10.1栈(LIFO)

栈(stack)是一种数据结构,它代表只能在某一端进行插入,删除操作的特殊线性表,通常就是在线性表的尾端进行插入,删除操作,成为栈顶(top),另一端则被称为栈底(bottom)。如果一个栈不包含任何元素,那这个栈被称为空栈。从栈顶插入一个元素被称为进栈,将一个元素插入栈顶被称为压栈,对应英文说法为push。从栈顶删除一个元素被称为出栈,将一个元素从栈顶删除被称为弹出栈,对应的英文说法为pop。栈有顺序栈和链栈。

栈的常用操作:初始化,通常是一个构造器;返回栈的长度,即数据元素的个数;入栈,向栈顶插入一个数据元素;出栈,从栈的栈顶删除一个数据元素,该方法通常返回被删除的元素;访问栈顶元素,返回栈顶的数据元素,但不删除栈顶元素;判断栈是否为空;清空栈。对于删除操作来说,只要让记录栈内元素个数的size减少1,程序即可通过arr[size-1]访问到新的栈顶元素。但不要忘记释放原来栈顶元素的数组引用,否则会引起内存泄露。对于链栈的进栈操作,程序只需要做两件事情:让top引用指向新添加的元素,新元素的next引用指向原来的栈顶元素;让记录栈内元素个数的size变量+1。对于链栈的出栈操作,需要将栈顶元素弹出栈,程序需要做两件事情:让top引用指向原栈顶元素的下一个元素,并释放原来的栈顶元素;让记录栈内元素的个数的size变量-1。

由于栈不需要实现随机存,取的功能,它只需从栈顶插入,删除元素,因此顺序结构所提供的高效存,取就没有太大的价值了,即使采用链式结构的实现,程序同样可以高效地出栈,入栈。对于链栈而言,栈内包含几个元素,底层链式结构就只需保存几个节点,每个节点需要额外添加一个next引用,这会引起部分空间的浪费。但对于顺序栈来说,程序开始就需要在底层为它开辟一块连续的内存空间,这种空间浪费其实更大。链栈的空间利用率比顺序栈的空间利用率要高一些。

java集合实际上提供了一下两种栈供开发者使用:java.util.Stack(最普通的顺序栈);java.util.LinkedList,同样提供了push(),pop(),peek()等方法,它代表栈的链式实现;前者线程安全,后者线程不安全,但可以通过工具类方法使其安全。

10.2队列(FIFO)

队列是另一种被限制过的线性表,它使用固定的一端来插入数据元素,另一端只用于删除元素。也就是说,队列中元素的移动方向总是固定的。插入的一端成为队尾,进行删除操作的端成为队头。队列有顺序队列和链队列。

队列的常用操作:初始化,通常是一个构造器;返回队列的长度,即数据元素的个数;加入元素,向队列的rear端插入一个数据元素,队列的长度+1;删除元素,从队列的front端删除一个数据元素,队列长度-1,该方法通常返回被删除的元素;访问队列的前端元素,front端元素,但不删除该元素;判断队列是否为空。顺序队列的front总是保存着队列中即将出队列的元素的索引;顺序队列中的rear总是保存着下一个即将进入队列的元素的索引。队列中的元素个数为rear-front。

假满现象:当向队列中插满元素,再依次删除所有元素后,front和rear都会指向队尾的现象。此时再试图加入数据将加不进去。对于此问题,程序有如下解决方法:1)每次将元素移出队列时都将队列中的所有元素向front端移动一位,这种方式下front值永远为0,只是rear随着插入删除而变化。但这种方式非常浪费时间,因为每次将元素从队列移除都需要进行整体搬家。2)将数组存储区域看成一个首尾相接的环形区域,当存放到数组的最大地址之后,rear的值将再次变为0。采用这种技巧存储的队列成为循环队列。如果此时elementData[front]==null表明此时队列为空,否则表明该队列已满。

链队列采用链式结构来保存队列中的元素,该队列允许添加无限多个元素,因此链队列无队列满的问题。

java集合框架中提供了一个Queue接口,该接口代表了一个队列,实现该接口的类可以当成队列使用。Queue里包含了6个方法,用于代表队列所包含的3个标志性方法(插入,移除和访问)。java提供了该接口的实现类,最为典型的为ArrayBlockingQueue(顺序队列)和LinkedBlockingQueue(链队列)。JDK1.5还为Queue接口提供了一个Deque接口,这个接口代表另一种特殊的队列-双向队列。

add() offer()         remove() poll()         element() peek()   前者为跑出异常版本,后者为返回特殊值的版本。

10.3双向队列

双向队列代表一种特殊的队列,它可以在两端同时进行插入,删除操作。Deque既可当成队列使用,也可当成栈使用。JDK提供了一个古老的stack类,但现在已经不再推荐开发者使用这个古老的栈实现,而是推荐使用Deque实现类作为栈使用。JDK为Deque提供了ArrayDeque,LinkedBlockingDeque,LinkedList这几个实现类。其中第一个代表顺序存储结构的双向队列,第二个是一个线程安全的,链式结构的双向队列,第三个是链式存储结构的双向队列。

猜你喜欢

转载自blog.csdn.net/little_____white/article/details/82151857