java集合源码解读---Queu和Stack的数组和链式实现

栈和队列

所谓的栈,是一个含有至少两个基本操作的抽象数据类型:插入新的元素;删除最近时间插入的元素。遵循FILO(First in,last out,先进后出)的原则。
所谓的队列,也是一个含有至少两个基本操作的抽象数据类型:插入新的元素;删除最久时间插入的元素。遵循FIFO(First in,first out,先进先出)的原则。
关于栈和队列的具体实现,我们即可以借助于数组,也可以采用链表来实现。

1) 栈的数组实现方式

java代码

public class MyStack {

    public int count;
    public Object[] items;

    public MyStack()
    {
        items = new Object[20];
        count = 0;
    }
    public MyStack(int len)
    {
        items = new Object[len];
        count = 0;
    }
    //判断栈是否为空
    boolean isEmpty(){return count==0;}

    //重整数组的大小
    private void resize(int size)
    {
        Object[] newItems = new Object[size];
        for(int i =0;i//进栈
    public void push(E e)
    {
        //如果栈满,则重整数组大小。
        if(count == items.length) resize(2*items.length);
        items[count++] = e;//数组的起始索引是0,入栈后,数组的大小应增加1
    }
    //出栈
    public E pop()
    {
        if(count==0) return null; //如果栈为空
        E item = (E)items[count-1];
        items[count-1] = null;
        count--;
        //重整数组大小,节省存储空间。
        if(count>0&&count<=items.length/4) resize(items.length/2); 

        return item;
    }

    //返回栈中的最后一个元素
    public E peek()
    {
        if(count==0) return null;

        E item = (E)items[count-1];
        return item;
    }
}

2)栈的链式实现方式

java代码

public class MyStack {
    Node head;//表示栈顶
    private class Node
    {
        E item;
        Node next;
    }
    public boolean isEmpty()
    {
        return head==null;
    }
    public void push(E e)
    {
        Node node = new Node();
        node.item = e;
        node.next = head; //栈的物理连接顺序是从上到下
        head = node;
    }
    public E pop()
    {
        if(head==null) return null;
        E e = (E)head.item;//栈顶元素先出
        head=head.next;
        return e;
    }
    public E peek()
    {
        if(head == null) return null;
        else 
            return (E)head.item;
    }
}

3)队列的数组实现方式

java代码

//用数组实现循环队列
 public class ArrayQueue 
{
    private int front;
    private int rear;
    private int capacity;
    private int count;
    private int capacityIncrement;
    private Object[] itemArray;

    public ArrayQueue(){
        front = 0;
        rear = 0;
        count = 0;
        capacity = 10;
        capacityIncrement = 5;//新增队列的长度。
        itemArray = new Object[capacity];
    }

    boolean isEmpty() {return count==0;}

    //1.入队
    public void insert(E e)
    {
        //1.如果队列已满,就先扩充队列,后插队。
        if(count==capacity) {
            capacity+=capacityIncrement;
            Object[] newArray = new Object[capacity];
        /**
         * 将原队列中的元素原样拷贝到新队列中。如果不是原样拷贝,则会破坏队列的FIFO特性。
         */
        //如果队列中的元素位于itemArray[font.....rear-1]中
        if(frontfor(int i = front;ielse{
            //因队列已满,此时front==rear,应该将队列分成两个区间:[0:rear-1] 和[front:count-1],分别拷贝到新数组的两端。
            //在原队列的中间插入一段新的存储空间。
            //否则,如果在原队列的后面插入新的空间,那么再次进行入队操作时,原来的元素就会被覆盖掉。
            for(int i =0;ifor(int i = front;i//然后,将front改为指向其新位置. 
        }
        itemArray = newArray;
       }

        //2.如果队列未满,直接插队。
        itemArray[rear]=e;  
        rear=(rear+1)%capacity; 
        count++;
    }

    //2.出队
    public E remove()
    {
        if(count==0) return null;
        else{
            E item = (E)itemArray[front];
            itemArray[front] = null;
            front = (front+1)%capacity;
            count--;
            return item;
        }
    }
}
//另外一种数组实现循环队列的简单实现
import java.util.NoSuchElementException;  

public class SimpleArrayQueue {  
    protected Object [] data;  
    protected int size,  
                  head,  
                  tail;  
    public SimpleArrayQueue(){  
        final int INITIAL_LENGTH=10;  
        data=new Object[INITIAL_LENGTH];  
        size=0;  
        head=0;  
        tail=-1;  
    }  
    //获取队列的大小和判断队列是否为空  
    public int theSize(){ return size;}  
    public boolean isEmpty(){ return size==0;}  

    //获取队头元素
    public Object front(){  
        if(size==0) throw new NoSuchElementException();  
        return data[head];  
    } 

    //入队操作 
    public void enqueue(Object element){  
        if(size==data.length){  

            //在java中允许将一个数组变量拷贝给另外一个数组变量。这时,两个变量将引用同一个数组。 
            Object [] oldData=data;//保存原数组data
            data=new Object[data.length*2]; //double the length of data 

            //将数组分成两个区间进行拷贝:区间1:[head:OldData.length-1]和区间2:[0:tail]
            //当head==0时,原数组只有区间1这一段需要被拷贝,当head>0时,原数组有区间1和区间2这两段需要被拷贝。
            //copy oldData[head:OldData.length-1] to data[0:OldData.length-1-head]
            System.arraycopy(oldData, head,data,0,oldData.length-head);  
            /*
             * 如果希望将一个数组的所有值拷贝到一个新的数组中去,就要使用Arrays类中的copyOf()方法:
             *  int[] copiedLckyNumbers = Arrays.copyOf(luckyNumbers,2*luckyNumbers.length);
             *  第二个参数是新数组的长度,这个方法通常用来增加数组的大小。
             *  如果数组的元素是数值型,那么多余的元素将被赋值为0;如果是boolean,多余的元素将会被赋值为false;
             *  相反,如果长度小于原始数组的长度,则只会拷贝最前面的数据元素。 
             */

            if(head>0)//拷贝区间2  
                //copy oldData[0:tail] to data [oldData.length-head:oldlenght-1]  
               //System.arraycopy(oldData, 0, data, head+1, tail+1); //错误写法 
            System.arraycopy(oldData, 0, data,oldData.length-head, tail+1);//正确写法
            head=0;  
            tail=oldData.length-1;  
        }  

        tail=(tail+1)%data.length;  
        data[tail]=element;  
        size++;  
    }  

    //出队操作 
    public Object dequeue(){
         /* 注意 :
          * if(size--==0){throw new NoSuchElementException();}//先执行if(size==0),后执行size--;
          * 放置的顺序。
          * 不能写成if(--size==0){ throw new NoSuchElementException(); }
          * 因为当队列中就剩下一个元素时,--size;会使size为0,此时抛出异常,并没有对该异常进行处理。
          * 程序中断,后面的语句无法执行。       
          */
        Object element=data[head];  
        head=(head+1)%data.length;//当队列满的时候size==data.length,即data.length就是当前size的值。
                                 //如果size变小后,head就会跳过下一个元素,而不是顺移下一个,导致下一个元素被”遗忘“了。
        if(size--==0){ throw new NoSuchElementException(); } //先执行if(size==0),后执行size--;
        return element; //程序最后一句一定要是return语句。
    }  

}  

4)队列的链式实现方式

java代码

public class ListQueue {
    private int count;
    private Node front,rear;

    private class Node
    {
        E item;
        Node link;
    }

//   //提供java类的空参数的构造函数。
//   ListQueue()
//  {
//      count =0;
//      front = null;
//      rear = null;
//      Node node = new Node();
//  }

    public boolean isEmpty(){ return count==0;}

    //入队
    public void insert(E e)
    {
        Node newNode = new Node();//初始化为空节点。
        newNode.item = e;

        //如果队为空
        if(rear==null) 
            front = rear = newNode;
        else{
            rear.link = newNode;//新节点连接到队尾处
            rear = newNode;//新节点变成队尾
        }
        count++;
    }
    //出队
    public E remove()
    {
        //如果队为空
        if(count==0) return null;
        else{
            E item = front.item;
            front = front.link;

            if(front==null) { rear = null; }//队列为空。
            count--;
            return item;
        }
    }
    //克隆队列
    public ListQueue clone()
    {
        ListQueueQ = new ListQueue();
        for(Nodet=front;t!=null;t=t.link)//for循环的这种写法。等价于while循环。
        Q.insert(t.item);
        return Q;
    }
}

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