栈和队列

栈和队列

1. 用数组实现栈和队列

题目:用数组结构实现固定大小的栈和队列

实现栈

public class ArrayStack {
    public Integer[] arr;
    public Integer index;

    public ArrayStack(Integer initSize) {
        if(initSize < 0){
            throw new IllegalArgumentException("The init size is less than 0.");
        }
        arr = new Integer[initSize];
        index = 0;
    }

    public Integer peek(){
        if(index == 0){
            return null;
        }
        return arr[index - 1];
    }

    public void push(Integer num){
        if(index == arr.length){
            throw new ArrayIndexOutOfBoundsException("Full!");
        }
        arr[index++] = num;
    }

    public Integer pop(){
        if(index == 0){
            return null;
        }
        return arr[--index];
    }

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

实现队列

public class ArrayQueue {
    //也可以不用queueSize变量,使用arr.length代替也可以
    public int queueSize;
    public int tempSize;
    public int start;
    public int end;
    public int[] arr;

    public ArrayQueue(int queueSize){
        if(queueSize < 0){
            throw new IllegalArgumentException("size < 0");
        }
        start = 0;
        end = 0;
        tempSize = 0;
        this.queueSize = queueSize;
        arr = new int[queueSize];
    }

    public void push(int num){
        if(tempSize == queueSize){
            throw new ArrayIndexOutOfBoundsException("too much");
        }
        arr[end++] = num;
        if(end == queueSize){
            end = 0;
        }
        tempSize++;
    }

    public int poll(){
        if(tempSize == 0){
            throw null;
        }
        int result = arr[start++];
        if(start == queueSize){
            start = 0;
        }
        tempSize--;
        return result;
    }

    public static void main(String[] args){
        ArrayQueue queue = new ArrayQueue(3);
        queue.push(1);
        queue.push(2);
        queue.push(3);
        System.out.printf(String.valueOf(queue.poll()) + " ");
        queue.push(4);
        System.out.printf(String.valueOf(queue.poll()) + " ");
        queue.push(5);

        queue.push(6);
    }
}

2. 实现一个特殊的栈,返回最小元素

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

要求:

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

解决思路:可以用两个栈来实现:stackData和stackMin

  1. 当向栈中压入数据num时,将num正常存入stackData,比较num和stackMin的栈顶元素,将较小的压入栈顶。
  2. 弹出数据时,两个栈都弹出自己的栈顶元素。
  3. 返回栈中最小元素,即为stackMin的栈顶元素。
import java.util.Stack;

public class GetMinStack {

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

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

        public void myPush(Integer num){
            stackData.push(num);
            if(this.stackMin.empty()){
                stackMin.push(num);
            }else{
                int minPeek = this.stackMin.peek();
                int temp = num < minPeek ? num : minPeek;
                stackMin.push(temp);
            }
        }

        public int pop(){
            if(this.stackData.empty()){
                throw new IllegalArgumentException("MyStack is empty.");
            }else{
                int temp = stackData.pop();
                stackMin.pop();
                System.out.println("pop the number of " + temp);
                return temp;
            }
        }

        public void getMin(){
            if(this.stackMin.empty()){
                throw new IllegalArgumentException("Mystack is empty.");
            }else{
                int temp = stackMin.peek();
                System.out.println("The min is " + temp);
            }
        }
    }

    public static void main(String[] args){
        MyStack myStack = new MyStack();
        myStack.myPush(2);
        myStack.getMin();
        myStack.myPush(3);
        myStack.getMin();
        myStack.myPush(1);
        myStack.getMin();
        myStack.pop();
        myStack.getMin();
        myStack.pop();
        myStack.getMin();
    }
}

3. 仅用队列结构实现栈结构

注:在java中,队列是用链表实现的。Queue queue = new LinkedList<Integer>();

思路:可以用两个队列实现栈结构。分别为data、help。

步骤:

  1. 入栈时将数据加入到队列data中,help队列不变。
  2. 出栈时,将队列data中的数据(除了最后一个元素)弹出到队列help中,弹出data队列的最后一个元素,然后help和data队列交换引用
  3. 求栈顶元素时,将队列data中的数据(除了最后一个元素)弹出到队列help中,然后先记录data队列的最后一个元素,再将其弹出到help队列中,交换help和data队列交换引用
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

/**
 * 仅用队列结构实现栈结构
 */
public class Queue2Stack {

    public static class MyStack{
        public Queue data;
        public Queue help;

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

        public void push(int num){
            data.add(num);
        }

        public int pop(){
            if(data.isEmpty()){
                throw new IllegalArgumentException("stack is empty.");
            }
            while(data.size() > 1){
                help.add(data.poll());
            }
            int num = (int) data.poll();
            swap();
            return num;
        }

        public int peek(){
            if(data.isEmpty()){
                throw new IllegalArgumentException("stack is empty.");
            }
            while(data.size() > 1){
                help.add(data.poll());
            }
            int num = (int) data.peek();
            help.add(num);
            swap();
            return num;
        }

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

    public static void main(String[] args){
        MyStack stack = new MyStack();
        stack.push(1);
        stack.push(2);
        stack.peek();
        System.out.println("peek:" + stack.peek());
        stack.pop();
        System.out.println("peek:" + stack.peek());
    }
}

4. 仅用栈结构实现队列结构

思路:可以用两个栈来实现,这两个栈分别为pushStack和popStack,一个用来压入用户新增的数据,另一个用来弹出数据。

步骤:

  1. 用户添加数据,将数据依次添加到栈pushStack中,popStack不动
  2. 弹出数据,将pushStack中的全部数据依次弹出到popStack中,然后popStack栈弹出一个元素
  3. 第三步可以将popStack中的全部数据依次弹出并压入pushStack中,也可以等待下一个push操作发生之前,再把popStack中的元素依次弹出压入pushStack中

总之保证两个原则:

  1. 如果要弹出数据,首先要保证pushStack栈为空:将pushStack所有数据弹出到popStack中
  2. 如果要添加数据,首先要保证popStack栈为空:将pushpopStack所有数据弹出到pushStack中
import java.util.Stack;

/**
 * 仅用栈结构实现队列结构
 */
public class Stack2Queue {

    public static class MyQueue{
        public Stack<Integer> pushStack;
        public Stack<Integer> popStack;

        public MyQueue(){
            this.pushStack = new Stack<Integer>();
            this.popStack = new Stack<Integer>();
        }

        public void add(int num){
            while(popStack.size() > 0){
                pushStack.push(popStack.pop());
            }
            pushStack.push(num);
        }

        public int poll(){
            if(popStack.isEmpty()&&pushStack.isEmpty()){
                throw new IllegalArgumentException("queue is empty.");
            }
            while(pushStack.size() > 0){
                popStack.push(pushStack.pop());
            }
            return popStack.pop();
        }

        public int peek(){
            if(popStack.isEmpty()&&pushStack.isEmpty()){
                throw new IllegalArgumentException("queue is empty.");
            }
            while(pushStack.size() > 0){
                popStack.push(pushStack.pop());
            }
            return popStack.peek();
        }
    }

    public static void main(String[] args) {
        MyQueue queue = new MyQueue();
        queue.add(1);
        queue.add(2);
        queue.add(3);
        System.out.println(queue.peek());
        queue.poll();
        System.out.println(queue.peek());
    }
}

5. 猫狗队列

宠物、猫、狗的实现如下:

public class Pet{  
    private String type;  
    public Pet(String type){  
        this.type = type;  
    }  
    public String getPetType(){  
        return this.type;  
    }  
}  
public class Dog extends Pet{  
    public Dog(){  
        super("Dog");  
    }  
}  
public class Cat extends Pet{  
    public Cat(){  
        super("Cat");  
    }  
}  

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

用户可以调用add方法将cat类或者dog类的实例放入队列中;
用户可以调用pollAll方法,将队列中所有的实例按照队列的先后顺序依次弹出;
用户可以调用pollDog方法,将队列中dog类的实例按照队列的先后顺序依次弹出;
用户可以调用pollCat方法,将队列中cat类的实例按照队列的先后顺序依次弹出;
用户可以调用isEmpty方法,检查队列中是否还有dog和cat的实例;
用户可以调用isDogEmpty方法,检查队列中是否还有do的实例;
用户可以调用isCatEmpty方法,检查队列中是否还有cat的实例。

思路:

  1. 用两个队列来实现,分别用来装猫对象和狗对象。为了实现pollAll()方法,让所有实例按入队顺序弹出,就需要给每个对象定义一个时间戳。出队时,时间戳较小的先出。
  2. 但是又不能更改题目给出的Pet类,所以新定义一个类PetEnter,用来封装Pet类和时间戳。
  3. 使用add()方法入队时,压入的是PetEnter对象,而不是Pet对象。并记录时间戳的值赋值给要压入的每一个PetEnter对象。
import java.util.LinkedList;
import java.util.Queue;

public class CatDogQueue {

    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");
        }
    }

    public static class PetEnter{
        private Pet pet;
        private int count;
        public PetEnter(Pet pet){
            this.pet = pet;
            this.count = 0;
        }

        public int getCount() {
            return count;
        }

        public void setCount(int count) {
            this.count = count;
        }
    }

    public static class CatDog{
        public Queue<PetEnter>  catQueue;
        public Queue<PetEnter>  dogQueue;
        public int index;
        public CatDog(){
            this.catQueue = new LinkedList<PetEnter>();
            this.dogQueue = new LinkedList<PetEnter>();
            this.index = 0;
        }

        public void add(PetEnter petEnter){
            petEnter.setCount(index++);
            if("Dog".equals(petEnter.pet.getPetType())){
                this.dogQueue.add(petEnter);
            }else if("Cat".equals(petEnter.pet.getPetType())){
                this.catQueue.add(petEnter);
            }else{
                throw new IllegalArgumentException("It is not a cat or dog.");
            }
        }

        public void pollAll(){
            if(isEmpty()){
                throw new IllegalArgumentException("The Dog and Cat queue are empty.");
            }else if(!isDogEmpty() && !isCatEmpty()){
                while(!isDogEmpty() && !isCatEmpty()){
                    if(dogQueue.peek().count < catQueue.peek().count){
                        pollDog();
                    }else{
                        pollCat();
                    }
                }
                while(!isDogEmpty()){
                    pollDog();
                }
                while(!isCatEmpty()){
                    pollCat();
                }
            }
        }

        public Dog pollDog(){
            if(isDogEmpty()){
                throw new IllegalArgumentException("The Dog queue is empty.");
            }
            Dog dog = (Dog) dogQueue.peek().pet;
            System.out.println(dogQueue.peek().getCount());
            dogQueue.poll();
            return dog;
        }

        public Cat pollCat(){
            if(isCatEmpty()){
                throw new IllegalArgumentException("The Cat queue is empty.");
            }
            Cat cat = (Cat) catQueue.peek().pet;
            System.out.println(catQueue.peek().getCount());
            catQueue.poll();
            return cat;
        }

        public boolean isEmpty(){
            return catQueue.isEmpty() && dogQueue.isEmpty();
        }

        public boolean isDogEmpty(){
            return dogQueue.isEmpty();
        }

        public boolean isCatEmpty(){
            return catQueue.isEmpty();
        }

    }

    public static void main(String[] args) {
        CatDog catDog = new CatDog();
        Dog dog1 = new Dog();
        Dog dog2 = new Dog();
        Dog dog3 = new Dog();
        Cat cat1 = new Cat();
        Cat cat2 = new Cat();
        catDog.add(new PetEnter(dog1));
        catDog.add(new PetEnter(cat1));
        catDog.add(new PetEnter(dog2));
        catDog.add(new PetEnter(dog3));
        catDog.add(new PetEnter(cat2));
        catDog.pollCat();
        catDog.pollDog();
        System.out.println("---");
        catDog.pollAll();
    }
}

6. 流数据中的中位数

题目:如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

例如,

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:

void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof

思路:

  1. 构建一个大根堆maxHeap和一个小根堆minHeap:大根堆是递减的,小根堆是递增的。
  2. 添加数字
    • 当添加数的时候,先判断小根堆是否为空,如果为空,加入小根堆
    • 如果小根堆不为空,和小根堆的根节点比较,如果比小根堆的根节点大,加入小根堆;否则加入大根堆。
    • 加入一个数后,判断两个堆的尺寸是否相差2,是的话,从数量较多的堆中弹出堆顶到另一个堆中。
  3. 查找数字
    • 如果两个堆尺寸相同,分别取堆首,求和然后除以二。
    • 如果不相同,取数量最多的堆的堆顶。

注:也可以先加入大根堆,然后以后再让里面加入数的时候,跟大根堆的堆顶比较。

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;

public class Solution_MedianFinder {

    public static class MedianFinder{

        Queue<Integer> maxHeap;//大根堆
        Queue<Integer> minHeap;//小根堆

        public MedianFinder(){
            maxHeap = new PriorityQueue<>(new MyComparator());
            minHeap = new PriorityQueue<>();
        }

        public static class MyComparator implements Comparator<Integer>{

            @Override
            public int compare(Integer t1, Integer t2) {
                return t2 - t1;
            }
        }

        public void addNum(int num){
            if(minHeap.isEmpty()){
                minHeap.add(num);
            }else{
                int temp = minHeap.peek();
                if(num >= temp){
                    minHeap.add(num);
                }else{
                    maxHeap.add(num);
                }
                if(minHeap.size() - maxHeap.size() > 1){
                    maxHeap.add(minHeap.poll());
                }
                if(maxHeap.size() - minHeap.size() > 1){
                    minHeap.add(maxHeap.poll());
                }
            }

        }

        public double findMedian(){
            if(minHeap.size() == 0){
                return 0;
            }
            if(maxHeap.size() == minHeap.size()){
                return (double) (maxHeap.peek() + minHeap.peek()) / 2;
            }else{
                return maxHeap.size() > minHeap.size() ? maxHeap.peek() : minHeap.peek();
            }
        }
    }

    public static void main(String[] args) {
        MedianFinder finder = new MedianFinder();
        finder.addNum(1);
        finder.addNum(2);
        finder.addNum(3);
        finder.addNum(4);
        System.out.println(finder.findMedian());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值