java手写队列和栈(数组实现,自动扩容)

1 简介

  • 队列:先进先出
  • 栈:后进先出
  • 栈是比较好实现的,队列实现起来有点麻烦
  • 不保证线程安全,如果想要线程安全,可以在所有方法前加synchronized,但是这样做的话,明显是很糟糕的。你可以尝试加入读写锁。放置写入的时候执行其他操作。

2 栈

  • 动态扩增的原理:当数组满的时候,自动创建新的数组,并把原数组的内容复制到新数组中。
package data.structure.stack;

/**
 * 数组实现栈结构
 * 要求:
 * 1.实现动态扩增
 * 2.后进先出
 * @Author :吴用
 * @Date :2021-01-20 19:20
 * @Version :1.0
 */
public class ArrayStack<T> {
    /**
     * 数据
     */
    private Object[] datas;
    /**
     * 容量
     */
    private int  capacity;
    /**
     * 当前数据大小
     */
    private int size;
    /**
     * 扩增系数
     */
    private int alpha = 2;
    /**
     * 当前指针位置,永远指向空位置
     */
    private int cur;
    /**
     * 指向首位置
     */
    private int start;

    public ArrayStack() {
        this.cur = 0;
        this.start = 0;
        this.capacity = 2;
        datas = new Object[2];
    }


    public ArrayStack(int capacity) {
        this.cur = 0;
        this.start = 0;
        this.capacity = capacity;
        datas = new Object[capacity];
    }

    /**
     * 添加元素
     * @param o
     * @return
     */
    public boolean push(T o) {
        if(cur == capacity){
            // 进行扩容
            resize();

        }
        datas[cur] = o;
        cur++;
        size++;
        return true;
    }

    /**
     * 推出最后一个元素
     * @return
     */
    public T pop() {
        if(size==0){
            return null;
        }else{
            cur--;
            size--;
            return (T) datas[cur];
        }
    }

    /**
     * 查询最后一个元素
     * @return
     */
    public T peek() {
        if(size==0){
            return null;
        }else{
            return (T) datas[cur-1];
        }
    }

    public int size(){
        return size;
    }

    /**
     * 扩增容量
     */
    private void resize(){
        // 扩增
        capacity = capacity * alpha;
        Object[] temp = new Object[capacity];
        // 复制原来的内容
        for (int i = 0; i < datas.length; i++) {
            temp[i] = datas[i];
        }
        datas = temp;
    }
}

3 双栈实现队列

  • 这种方式实现起来比较简单。
  • 有两个数组实现,左侧数组用于放置数据。
  • 当取数据的时候,如果右侧数组为空,则将左侧数组导入右侧数组,然后再从右侧数组取数据。如果右侧数组不为空,则直接取数据。
  • 在左侧数组容量不足的时候,扩增左侧数组
  • 在取数据的时候,如果右侧数组容量不足,则扩增右侧数组。
package data.structure.queue;

/**
 * 使用双栈实现队列
 * @Author :吴用
 * @Date :2021-01-20 20:06
 * @Version :1.0
 */
public class ArrayQueue<T> {
    /**
     * 左侧数组
     */
    private Object[] leftArr;
    /**
     * 右侧数组
     */
    private Object[] rightArr;
    /**
     * 右侧数组的当前索引
     */
    private int rightStart;
    /**
     * 左侧数组的大小
     */
    private int leftSize;
    /**
     * 右侧数组的大小
     */
    private int rightSize;
    /**
     * 左侧数组的容量
     */
    private int leftCapacity;
    /**
     * 右侧数组的容量
     */
    private int rightCapacity;
    /**
     * 扩增系数
     */
    private int alpha=2;


    public ArrayQueue() {
        this.leftCapacity = 2;
        this.rightCapacity = 2;
        this.leftArr = new Object[2];
        this.rightArr = new Object[2];
    }

    /**
     * 给定数组的容量
     * @param leftCapacity
     */
    public ArrayQueue(int leftCapacity) {
        this.leftCapacity = leftCapacity;
        this.rightCapacity = leftCapacity;
        this.leftArr = new Object[leftCapacity];
        this.rightArr = new Object[leftCapacity];
    }

    /**
     * 向左侧的数组推入数据
     * @param t
     * @return
     */
    public boolean push(T t){
        if(leftSize==leftCapacity){
            // 左侧容量不足时,扩容
            leftResize();
        }
        leftArr[leftSize] = t;
        leftSize++;
        return true;
    }

    /**
     * 推出首位置的数据
     * @return
     */
    public T poll(){
        if(rightSize == 0){
            // 如果右侧数组为空的时候,左侧数组倒入右侧数组
            leftToRight();
        }
        rightSize--;
        rightStart++;
        return (T) rightArr[rightStart-1];
    }

    /**
     * 查询首位置的数据
     * @return
     */
    public T peek(){
        if(rightSize!=0){
            return (T) rightArr[rightStart];
        }else if(leftSize != 0){
            return (T) leftArr[leftSize-1];
        }else{
            return null;
        }
    }

    /**
     * 获取栈当前的元素个数
     * @return
     */
    public int size(){
        return leftSize + rightSize;
    }

    /**
     * 将左侧数组推入右侧
     */
    private void leftToRight(){
        while(leftSize>rightCapacity){
            // 右侧空间不足的时候,扩容
            rightResize();
        }
        for (int i = 0,size=leftSize; i < size; i++) {
            // 将左侧的元素按顺序推入右侧
            rightArr[i] = leftArr[i];
            leftSize--;
            rightSize++;
        }
        rightStart = 0;
    }

    /**
     * 左侧数组扩容
     */
    private void leftResize(){
        // 扩增
        leftCapacity = leftCapacity * alpha;
        Object[] temp = new Object[leftCapacity];
        // 复制原来的内容
        for (int i = 0; i < leftArr.length; i++) {
            temp[i] = leftArr[i];
        }
        leftArr = temp;
    }

    /**
     * 右侧数组扩容
     */
    private void rightResize(){
        // 扩增
        rightCapacity = rightCapacity * alpha;
        Object[] temp = new Object[rightCapacity];
        // 复制原来的内容
        for (int i = 0; i < rightArr.length; i++) {
            temp[i] = rightArr[i];
        }
        rightArr = temp;
    }
}

4 双向队列

  • 要求既可以从左侧取数据,又可以从右侧取数据
  • 并且在容量不足的时候要实现自动扩容。
package data.structure.queue;

/**
 * 环形队列
 * @Author :吴用
 * @Date :2021-01-20 20:59
 * @Version :1.0
 */
public class CircleQueue<T> {
    /**
     * 队列的容量
     */
    private int capacity;
    /**
     * 当前元素个数
     */
    private int size;
    /**
     * 当前的头指针位置
     */
    private int start;
    /**
     * 当前的尾指针位置
     */
    private int end;
    /**
     * 增长系数
     */
    private int alpha = 2;

    /**
     * 数据
     */
    private Object[] datas;

    public CircleQueue() {
        this.capacity = 2;
        datas = new Object[2];
        size= 0;
        start = 0;
        end = 0;
    }

    public CircleQueue(int capacity) {
        this.capacity = capacity;
        datas = new Object[capacity];
        size= 0;
        start = 0;
        end = 0;
    }

    /**
     * 向末尾添加数据
     * @param t
     * @return
     */
    public boolean push(T t){
        if(size == capacity){
            resize();
        }
        datas[end] = t;
        end++;
        size++;
        if(end==capacity){
            end = 0;
        }
        return true;
    }

    /**
     * 推出首位置的元素
     * @return
     */
    public T poll(){
        if(size==0){
            return null;
        }
        T result = (T)datas[start];
        start++;
        if(start==capacity){
            start=0;
        }
        size--;
        return result;
    }

    /**
     * 推出末位置的元素
     * @return
     */
    public T pop(){
        if(size==0){
            return null;
        }
        end--;
        if(end==-1){
            end = capacity-1;
        }
        size--;
        return (T)datas[end];
    }

    /**
     * 查看首元素
     * @return
     */
    public T lookFirt(){
        if(size==0){
            return null;
        }
        return (T)datas[start];
    }

    /**
     * 查看末元素
     * @return
     */
    public T lookEnd(){
        if(size==0){
            return null;
        }
        if(end-1==-1){
            return (T)datas[capacity-1];
        }else{
            return (T)datas[end-1];
        }
    }

    /**
     * 当前元素个数
     * @return
     */
    public int size(){
        return size;
    }


    /**
     * 扩容,并将数据重新按顺序放到新的数组中
     */
    private void resize(){
        int lastCapacity = capacity;
        capacity = capacity*alpha;
        Object[] temp = new Object[capacity];
        for (int i = 0; i < size; i++) {
            if(start==lastCapacity-1){
                start = 0;
            }
            temp[i] = datas[start];
            start++;
        }
        start = 0;
        end = size;
        datas = temp;
    }
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值