栈和队列都属于抽象数据类型, 所以放到一起.
1. stack
stack很熟悉的一个地方就JVM的虚拟机栈.
我们知道, 在JVM里面的栈区, Java虚拟机栈(Java Virtual Machine Stacks)是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
JAVA里面stack有已经实现的stack.
继承于Vector, 存储数据采用的是数组来保存数据:
protected Object[] elementData;
至于使用很简单, Stack里面主要实现的有一下几个方法:
方法名 | 返回类型 | 说明 |
empty | boolean | 判断stack是否为空。 |
peek | E | 返回栈顶端的元素。 |
pop | E | 弹出栈顶的元素 |
push | E | 将元素压入栈 |
search | int | 返回最靠近顶端的目标元素到顶端的距离。 |
使用参考:
http://shmilyaw-hotmail-com.iteye.com/blog/1825171
stack用链表的简单实现:
package com.cain.datastructrue;
/**
* Created by wisdom on 15-10-14.
*/
public class Stack {
private Node first;
private int N;
public boolean push(String string) {
Node oldFirst = first;
first = new Node();
first.item = null;
first.next = oldFirst;
N++;
return true;
}
public Object pop() {
Object item = first.item;
first.item = null;
first = first.next;
N--;
return item;
}
private class Node {
Node next;
Object item;
}
/*
* other function ....
* */
}
2. 队列 (Queue)
队列是比较重要的一个内容.决定稍微深展下.
先来看看基础的FIFO队列
2.1 FIFO
队列(Queue)是只允许在一端进行插入,而在另一端进行删除(front删除, rear添加), 因此队列也称为"先进先出" 的线性表。
队列的实现方式有2种: 数组的存放形式和链表的存放方式;
数组的存放形式:
数组的存储形式下,存在溢出的现象:
①“下溢”现象
当队列为空时,做出队运算产生的溢出现象。“下溢”是正常现象,常用作程序控制转移的条件。
② "真上溢"现象
当队列满时,做进栈运算产生空间溢出的现象。“真上溢”是一种出错状态,应设法避免。
③ "假上溢"现象
由于入队和出队操作中,头尾指针只增加不减小,致使被删元素的空间永远无法重新利用。当队列中实际的元素个数远远小于内存中本分配的空间时,也可能由于尾指针已超越向量空间的上界而不能做入队操作。该现象称为"假上溢"现象
循环队列:
如上图右边部分所示,这种头尾相接的顺序存储结构称为循环队列(circular queue)。
循环队列中需要注意的几个重要问题:
①队空的判定条件,队空的条件是front=rear;
②队满的判定条件,(rear+1)%QueueSize=front。QueueSize为队列初始空间大小。
我参考的是:
http://blog.csdn.net/wuwenxiang91322/article/details/12259099
把上面这两点理解了差不多就理解了队列的原理了, 我也简单的实现下循环队列:
public interface MyQueue {
public boolean enqueue(E obj);
public E dequeue();
public int size();
public boolean isEmpty();
}
package com.cain.mydatastructure;
/**
* Created by wisdom on 15-11-6.
*/
public class CircleQueue implements MyQueue {
private E[] elements;
private int front;
private int rear;
private int size;
private static final int DEFAULT_SIZE = 10;
public CircleQueue() {
this(CircleQueue.DEFAULT_SIZE);
}
public CircleQueue(int size) {
elements = (E[]) new Object[size];
}
@Override
public boolean enqueue(E obj) {
if((rear+1)%elements.length==front){
return false;
}else {
elements[rear]=obj;
rear=(rear+1)%elements.length;
size++;
}
return true;
}
@Override
public E dequeue() {
if (front==rear)
return null;
else {
E data=elements[front];
front=(front+1)%elements.length;
size--;
return data;
}
}
@Override
public int size() {
//这样计算方式有问题
// return (rear-front)&(elements.length-1);
//// if (rear>front)
//// return rear-front;
//// else
//// return elements.length-1;
return size;
}
@Override
public boolean isEmpty() {
return front==rear;
}
}
package com.cain.mydatastructure;
/**
* Created by wisdom on 15-11-6.
*/
public class CircleQueueTest {
public static void main(String[] args) {
CircleQueue queue=new CircleQueue();
queue.enqueue("hello");
queue.enqueue("my");
queue.enqueue("world");
System.out.println(queue.size());
System.out.println(queue.dequeue());
System.out.println(queue.dequeue());
System.out.println(queue.dequeue());
//test for number
queue.enqueue("hello");
queue.enqueue("my");
queue.enqueue("world");
queue.enqueue("hello");
queue.enqueue("my");
queue.enqueue("world");
queue.enqueue("hello");
queue.enqueue("my");
queue.enqueue("world");
//队列的初始值为10, 第10个放不进去的
System.out.println(queue.enqueue("hello"));
System.out.println(queue.size());
}
}
队列的链表实现
在队列的形成过程中,可以利用线性链表的原理,来生成一个队列。
基于链表的队列,要动态创建和删除节点,这方面的效率当然没有数组高,但是它可以动态增长。
队列采用的FIFO(first in first out),新元素(等待进入队列的元素)总是被插入到链表的尾部,而读取的时候总是从链表的头部开始读取。每次读取一个元素,释放一个元素。所谓的动态创建,动态释放。因而也不存在溢出等问题。
代码实现参考:
http://blog.csdn.net/wuwenxiang91322/article/details/12303111
2.2 Deque
再来看看另外一种形式的队列Deque : public interface Deque
它是线性 collection,支持在两端插入和移除元素。
具体的看这个文章
http://uule.iteye.com/blog/2095650?utm_source=tuicool
--注意 Queue和Deque都只是接口, 还不能直接拿来用~
那么直觉会问,JDK队列的现实现类有哪些呢?
2.3 其他部分
(参考的是 http://blog.sina.com.cn/s/blog_72ef7bea0101cy7h.html )
JDK7之前已有的队列实现分为两类:用于一般用途的实现和用于并发的实现。
1)一般的用途
LinkedList实现了Queue接口,所以有先入先出队列的操作的方法;
PriorityQueue类是基于堆(数据结构)的优先队列(也叫堆),至于优先队列的原理看上个文章,
至于使用, 我简单写了个测试:
package com.cain.mydatastructure;
import java.util.Comparator;
import java.util.PriorityQueue;
/**
* Created by wisdom on 15-11-8.
*/
public class PriorityQueueTest {
private String country;
private int population;
public PriorityQueueTest(String country, int population) {
this.country = country;
this.population = population;
}
public int getPopulation() {
return population;
}
public String getCountry() {
return country;
}
public static void main(String[] args) {
Comparator comparator = new Comparator() {
@Override
public int compare(PriorityQueueTest o1, PriorityQueueTest o2) {
return o2.getPopulation() - o1.getPopulation();
}
};
//5是初始容量大小而已,所以当你超过了这个大小,队列会有个增加的动作
PriorityQueue queueTests = new PriorityQueue(5, comparator);
queueTests.add(new PriorityQueueTest("china", 1000));
queueTests.add(new PriorityQueueTest("America", 800));
queueTests.add(new PriorityQueueTest("Japan", 600));
queueTests.add(new PriorityQueueTest("Singepore", 200));
queueTests.add(new PriorityQueueTest("Canada", 700));
// queueTests.remove();
while (true) {
PriorityQueueTest test = queueTests.poll();
if (test != null) {
System.out.println(test.getCountry() + ", and population is:" + test.getPopulation());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else
break;
}
}
}
使用可以参考:
http://www.importnew.com/6932.html
2)并发队列实现
涉及到线程的并发, 这个结合线程来理解更好, 以后再写个文章具体分析这些队列