队列和栈的问题

本文深入探讨了栈和队列这两种基本数据结构的实现与应用,包括使用数组实现固定大小的栈和队列,如何仅用队列结构实现栈结构,以及相反的实现方式。此外,还介绍了栈和队列的补充练习,如实现特殊栈的最小元素获取功能,以及解决猫狗队列问题的创新方法。
摘要由CSDN通过智能技术生成

一、用数组结构实现大小固定的栈

【核心思想】

  栈结构是“后进先出”,有初始化栈、入栈、出栈、返回栈顶等功能,题目大意就是要求我们用数组实现栈的这些功能。

  初始化栈:给定一个初始大小,创建一个栈。定义一个变量 size ,初始化为 0,用来记录栈中的元素数量。

  入栈:如果 size 小于栈的大小,将要入栈的数放入数组的 size 位置上,size 加 1。否则报错。

  出栈:如果 size 大于 0,返回数组( size - 1 ) 位置上的数,size 减 1。否则报错。

  返回栈顶:如果 size 大于 0,返回数组(size - 1)位置上的数。否则报错。

【代码实现】

public class ArrayToStack {
    private int[] arr;
    private int size;

    /**
     * 初始化栈
     * @param initSize
     */
    public ArrayToStack(int initSize) {
        if (initSize < 0) {
            throw new IllegalArgumentException("The init size is less than 0!");
        }
        arr = new int[initSize];
        size = 0;
    }

    /**
     * 入栈
     * @param obj
     */
    public void push(int obj) {
        //size等于数组长度(栈的大小),说明栈已满,不能入栈
        if (size == arr.length) {
            throw new IndexOutOfBoundsException("The stack is full!");
        }
        arr[size++] = obj;
    }

    /**
     * 出栈
     * @return
     */
    public int pop() {
        //size等于0,说明栈空,不能出栈。
        if (size == 0) {
            throw new IndexOutOfBoundsException("The stack is empty!");
        }
        return arr[--size];
    }

    /**
     * 返回栈顶第一个元素
     * @return
     */
    public int peek() {
        //size等于0,说明栈空,所以没有栈顶。
        if (size == 0) {
            throw new IndexOutOfBoundsException("The stack is empty!");
        }
        return arr[size - 1];
    }

}

二、用数组结构实现大小固定的队列

【核心思想】

【实现代码】

public class ArrayToQueue {
    private Integer[] arr;
    private Integer size;
    private Integer start;
    private Integer end;

    /**
     * 初始化队列
     * @param initSize
     */
    public ArrayToQueue(int initSize) {
        if (initSize < 0) {
            throw new IllegalArgumentException("The init size is less than 0");
        }
        arr = new Integer[initSize];
        size = 0;
        start = 0;
        end = 0;
    }

    /**
     * 入队
     * @param obj
     */
    public void push(int obj) {
        if (size == arr.length) {
            throw new ArrayIndexOutOfBoundsException("The queue is full");
        }
        size++;
        arr[end] = obj;
        end = end == arr.length - 1 ? 0 : end + 1;
    }

    /**
     * 出队
     * @return
     */
    public Integer pop() {
        if (size == 0) {
            throw new ArrayIndexOutOfBoundsException("The queue is empty");
        }
        size--;
        int tmp = start;
        start = start == arr.length - 1 ? 0 : start + 1;
        return arr[tmp];
    }

    /**
     * 返回队列的第一个数
     * @return
     */
    public Integer peek() {
        if (size == 0) {
            return null;
        }
        //如果size不等于0,返回start指向的数
        return arr[start];
    }
} 

三、如何仅用队列结构实现栈结构?

【实现思路】

【代码实现】

/**
 * 仅用队列结构实现栈结构
 *
 * @author yi
 */
public class QueueToStack {
    private Queue<Integer> data;
    private Queue<Integer> help;

    public QueueToStack() {
        this.data = new LinkedList<Integer>();
        this.help = new LinkedList<Integer>();
    }

    /**
     * 正常push添加进入queue
     * @param value
     */
    public void push(int value) {
        data.add(value);
    }

    /**
     * 在pop的时候,pop只留下一个元素,并把pop出来的元素加入到help队列中
     * @return
     */
    public int pop() {
        if (data.isEmpty()) {
            throw new RuntimeException("栈为空");
        }
        while (data.size() > 1) {
            //把data中的元素"剪切"到help队列,直到data只剩下一个元素
            help.add(data.poll());
        }
        //最后一个入队的元素
        int res = data.poll();
        //交换help和data的引用指向
        swap();
        return res;
    }

    /**
     * 返回栈顶的第一个元素
     * @return
     */
    public int peek() {
        if (data.isEmpty()) {
            throw new RuntimeException("栈为空");
        }
        while (data.size() > 1) {
            help.add(data.poll());
        }
        int res = data.poll();
        help.add(res);
        swap();
        return res;
    }

    public void swap() {
        Queue<Integer> temp = help;
        help = data;
        data = temp;
    }
}

四、如何仅用栈结构实现队列结构? 

 【实现思路】

  

【代码实现】

/**
 * 仅用栈结构实现队列结构
 *
 * @author yi
 */
public class StackToQueue {
    private Stack<Integer> stackPush;
    private Stack<Integer> stackPop;

    public StackToQueue() {
        stackPush = new Stack<>();
        stackPop = new Stack<>();
    }

    /**
     * 入队
     * @param obj
     */
    public void push(int obj) {
        stackPush.push(obj);
    }

    /**
     * 出队
     * @return
     */
    public int poll() {
        if (stackPop.empty() && stackPush.empty()) {
            throw new RuntimeException("Queue is empty!");
        } else if (stackPop.empty()) {
            while (!stackPush.empty()) {
                stackPop.push(stackPush.pop());
            }
        }
        return stackPop.pop();
    }

    /**
     * 返回队列的第一个数
     * @return
     */
    public int peek() {
        if (stackPop.empty() && stackPush.empty()) {
            throw new RuntimeException("Queue is empty!");
        } else if (stackPop.empty()) {
            while (!stackPush.empty()) {
                stackPop.push(stackPush.pop());
            }
        }
        return stackPop.peek();
    }
}

五、栈的补充练习

  实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作。

【要求】

  1.pop、push、getMin操作的时间复杂度都是O(1)。
  2.设计的栈类型可以使用现成的栈结构。

【实现思路】

【代码实现】

public class MyStack {
    private Stack<Integer> stackData;
    private Stack<Integer> stackMin;

    public MyStack() {
        this.stackData = new Stack<>();
        this.stackMin = new Stack<>();
    }

    public void push(int newNum) {
        if (this.stackMin.isEmpty()) {
            this.stackMin.push(newNum);
        } else if (newNum < this.getMin()) {
            this.stackMin.push(newNum);
        } else {
            int newMin = this.stackMin.peek();
            this.stackMin.push(newMin);
        }
        this.stackData.push(newNum);
    }

    public int pop() {
        if (this.stackData.isEmpty()) {
            throw new RuntimeException("Your stack is empty");
        }
        this.stackMin.pop();
        return this.stackData.pop();
    }

    public int getMin() {
        if (this.stackMin.isEmpty()) {
            throw new RuntimeException("Your stack is empty.");
        }
        return this.stackMin.peek();
    }

    public static void main(String[] args) {
        MyStack stack = new MyStack();
        stack.push(3);
        System.out.println(stack.getMin());//3
        stack.push(5);
        System.out.println(stack.getMin());//3
        stack.push(1);
        System.out.println(stack.getMin());//1
        System.out.println(stack.pop());//1
        System.out.println(stack.getMin());//3
    }

}

六、队列的补充练习

6.1 猫狗队列问题

【题目】

  宠物、狗和猫的类如下: 

public static class Pet {
    private String type;

    public Pet(String type) {
        this.type = type;
    }

    public String getPetType() {
        return this.type;
    }
}

public static class Dog extends Pet {
    public Dog() {
        super("dog");
    }
}

public static class Cat extends Pet {
    public Cat() {
        super("cat");
    }
}

【要求】

  实现一种狗猫队列的结构,要求如下:

  1. 用户可以调用add方法将cat类或dog类的 实例放入队列中;
  2. 用户可以调用pollAll方法,将队列中所有的实例按照进队列 的先后顺序依次弹出;
  3. 用户可以调用pollDog方法,将队列中dog类的实例按照 进队列的先后顺序依次弹出;
  4. 用户可以调用pollCat方法,将队列中cat类的实 例按照进队列的先后顺序依次弹出;
  5. 用户可以调用isEmpty方法,检查队列中是 否还有dog或cat的实例;
  6.  用户可以调用isDogEmpty方法,检查队列中是否有dog 类的实例; 用户可以调用isCatEmpty方法,检查队列中是否有cat类的实例

【代码实现】

public class DogCatQueue_Code {
    /**
     * 以下的Pet、Dog、Cat类是用户提供的基础类,不能修改
     */
    public static class Pet {
        private String type;

        public Pet(String type) {
            this.type = type;
        }

        public String getPetType() {
            return this.type;
        }
    }

    public static class Dog extends Pet {
        public Dog() {
            super("dog");
        }
    }

    public static class Cat extends Pet {
        public Cat() {
            super("cat");
        }
    }

    /**
     * 为了不修改原来的基础类,我们自定义一个PetEnterQueue类,这个类才是放入到猫狗队列中去的对象
     * 保留原来的属性pet,并且新增一个count属性,将不同实例盖上时间戳
     */
    public static class PetEnterQueue {
        private Pet pet;
        private long count;

        public PetEnterQueue(Pet pet, long count) {
            this.pet = pet;
            this.count = count;
        }

        public Pet getPet() {
            return this.pet;
        }

        public long getCount() {
            return this.count;
        }

        public String getEnterPetType() {
            return this.pet.getPetType();
        }
    }

    /**
     * 我们实现的队列就是PetEnterQueue类的实例
     * 首先有一个不断累加的数据项count用来表示实例进队列的时间(不分cat还是dog)
     * 同时有两个队列,一个只存放Dog,另一个只存放Cat。
     */
    public static class DogCatQueue {
        private Queue<PetEnterQueue> dogQ;
        private Queue<PetEnterQueue> catQ;
        private long count;

        public DogCatQueue() {
            this.dogQ = new LinkedList<>();
            this.catQ = new LinkedList<>();
            this.count = 0;
        }

        public void add(Pet pet) {
            //如果pet是dog类型
            if (pet.getPetType().equals("dog")) {
                //在dog队列中添加信息:当前进入的是dog,并且当前数是count
                this.dogQ.add(new PetEnterQueue(pet, this.count++));
            } else if (pet.getPetType().equals("cat")) {
                this.catQ.add(new PetEnterQueue(pet, this.count++));
            } else {
                throw new RuntimeException("err, not dog or cat");
            }
        }

        /**
         * 弹出整体最早的
         * @return
         */
        public Pet pollAll() {
            if (!this.dogQ.isEmpty() && !this.catQ.isEmpty()) {
                //dog队列最早的dog最小,还是cat队列最早的cat最小
                //注意这里使用的是peek而不是poll
                //peek用于查询队列头部的元素;poll用于弹出队列中的头部元素
                if (this.dogQ.peek().getCount() < this.catQ.peek().getCount()) {
                    return this.dogQ.poll().getPet();
                } else {
                    return this.catQ.poll().getPet();
                }
            } else if (!this.dogQ.isEmpty()) {
                return this.dogQ.poll().getPet();
            } else if (!this.catQ.isEmpty()) {
                return this.catQ.poll().getPet();
            } else {
                throw new RuntimeException("err, queue is empty!");
            }
        }

        /**
         * 单独弹出dog
         * @return
         */
        public Dog pollDog() {
            if (!this.isDogQueueEmpty()) {
                return (Dog) this.dogQ.poll().getPet();
            } else {
                throw new RuntimeException("Dog queue is empty!");
            }
        }

        /**
         * 单独弹出cat
         * @return
         */
        public Cat pollCat() {
            if (!this.isCatQueueEmpty()) {
                return (Cat) this.catQ.poll().getPet();
            } else {
                throw new RuntimeException("Cat queue is empty!");
            }
        }

        public boolean isDogQueueEmpty() {
            return this.dogQ.isEmpty();
        }

        public boolean isCatQueueEmpty() {
            return this.catQ.isEmpty();
        }
    }

    public static void main(String[] args) {
        DogCatQueue test = new DogCatQueue();

        Pet dog1 = new Dog();
        Pet cat1 = new Cat();
        Pet dog2 = new Dog();
        Pet cat2 = new Cat();
        Pet dog3 = new Dog();
        Pet cat3 = new Cat();

        test.add(dog1);
        test.add(cat1);
        test.add(dog2);
        test.add(cat2);
        test.add(dog3);
        test.add(cat3);

        test.add(dog1);
        test.add(cat1);
        test.add(dog2);
        test.add(cat2);
        test.add(dog3);
        test.add(cat3);

        test.add(dog1);
        test.add(cat1);
        test.add(dog2);
        test.add(cat2);
        test.add(dog3);
        test.add(cat3);

        while (!test.isDogQueueEmpty()) {
            System.out.println(test.pollDog().getPetType());
        }
        while (!test.isCatQueueEmpty()) {
            System.out.println(test.pollCat().getPetType());
        }
    }
}

 

 

 

 

参考:https://blog.csdn.net/LYN9822/article/details/86530165

转载于:https://www.cnblogs.com/yft-javaNotes/p/10719905.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值