数据结构基础:栈和队列

栈和队列都属于抽象数据类型, 所以放到一起.


1. stack

stack很熟悉的一个地方就JVM的虚拟机栈.

数据结构基础:栈和队列_第1张图片


我们知道, 在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种: 数组的存放形式和链表的存放方式;

数组的存放形式:

数组的存储形式下,存在溢出的现象:

①“下溢”现象
 当队列为空时,做出队运算产生的溢出现象。“下溢”是正常现象,常用作程序控制转移的条件。
② "真上溢"现象
当队列满时,做进栈运算产生空间溢出的现象。“真上溢”是一种出错状态,应设法避免。
③ "假上溢"现象
由于入队和出队操作中,头尾指针只增加不减小,致使被删元素的空间永远无法重新利用。当队列中实际的元素个数远远小于内存中本分配的空间时,也可能由于尾指针已超越向量空间的上界而不能做入队操作。该现象称为"假上溢"现象

数据结构基础:栈和队列_第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  extends Queue 

它是线性 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;
        }


    }

}

打印结果:

china, and population is:1000
America, and population is:800
Canada, and population is:700
Japan, and population is:600
Singepore, and population is:200


使用可以参考:

http://www.importnew.com/6932.html



2)并发队列实现

涉及到线程的并发, 这个结合线程来理解更好, 以后再写个文章具体分析这些队列





你可能感兴趣的:(数据结构)