【数据结构】队列和栈

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunshineTan/article/details/80964782

1,队列(queue)

只允许在队头(front)出,队尾(rear)进。
先进先出(FIFO,first in first out)

1)循环队列

循环队列充分利用向量空间,克服“假溢出”。

①插入删除

在循环队列中,队头指针和队尾指针的动态变化决定队列的长度。
front指定队首位置,删除一个元素就将front顺时针移动一位;
rear指向元素要插入的位置,插入一个元素就将rear顺时针移动一位;

②判断队满队空

方法一:设一布尔变量以区别队满队空。
方法二: 队满时:(rear+1)%n==front(n为队列长度)

2)操作

Throws exception    Returns special value
Insert  add(e)      offer(e)     //进队列,将元素加入队列末尾.前者返回异常,后者返回特殊值标记异常
Remove  remove()    poll()       //获取队列头的元素并移除
Examine element()   peek()       //获取队列头的元素
isEmpty() //判断是否为空

2,栈(stack)

1)概念

仅在表尾进行增删的线性表。
栈顶(top)、栈底(bottom)、后进先出(LIFO,last in first out)。
将一个递归算法改为非递归算法时,通常使用栈作为辅助结构。

2)操作

栈顶指针保持不变,栈顶指针的动态变化决定栈中元素的个数。有元素入栈,栈顶指针增加,有元素出栈,栈顶指针减少。

empty()
peek()//查看栈顶内容
pop()
push(E object)
search(Object o)

3)计算

①卡特兰数

若一序列进栈顺序为e1,e2,e3,e4,e5,问存在多少种可能的出栈序列?

设n个数出栈方式有f(n)种,入栈顺序确定,记下标1、2、…、n。
设最后一个出栈的是第k个数,则说明k之前的k-1个数要完成进栈出栈,有f(k-1)种方式;
对于k之后的n-k个数再完成进栈出栈,有f(n-k)种方式;
最后第k个数出栈,这时有f(k-1)*f(n-k)种方式。
注意:每个数都有可能是最后出栈的。
所以:f(n)=f(0)*f(n-1)+f(1)*f(n-2)+…+f(k-1)*f(n-k)+…+f(n-1)*f(0);

结果
即:f(5)=42种。

相关问题:已知前序遍历的顺序是xxxx求这棵树有多少种形状。

3,应用

1)用两个栈实现队列

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
解题思路:
一个栈压入元素,而另一个栈作为缓冲,将栈1的元素出栈后压入栈2中。也可以将栈1中的最后一个元素直接出栈,而不用压入栈2中再出栈。

private Stack<Integer> stack1;
    private Stack<Integer> stack2;
    public void push(int node) {
        stack1.push(node);
    }
    public int pop() throws Exception {
        if (stack1.isEmpty() && stack2.isEmpty()) {
            throw new Exception("栈为空!");
        }
        if (stack2.isEmpty()) {
            while(!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }

2)包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
思路:定义两个栈,一个存放入的值。另一个存最小值。

Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
    public void push(int node) {
        stack1.push(node);
        if (stack2.isEmpty()) {
            stack2.push(node);
        }else {
            if (stack2.peek() > node) {
                stack2.push(node);
            }
        }
    }
    public void pop() {
        if (stack1.pop() == stack2.peek()) {
            stack2.pop();
        }
    }
    public int top() {
        return stack1.peek();
    }
    public int min() {
        return stack2.peek();
    }

3)栈的压入弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
思路:用栈来压入弹出元素,相等则出栈。
如果下一个弹出的数字是栈顶数字,弹出;
如果下一个弹出的不是栈顶数字,把压栈序列中还没有入栈的数字压入辅助栈,直到下一个需要弹出的数字压入栈顶为止。
如果所有数字都压入栈了仍未找到下一个弹出数字,那么该序列就不是一个弹出序列。

 public boolean IsPopOrder(int [] pushA,int [] popA) {
        if (pushA == null || popA == null) {
            return false;
        }
        Stack<Integer> stack = new Stack<>();//辅助栈
        int index = 0;
        for (int i = 0; i < pushA.length; i++) {
            stack.push(pushA[i]);
            while (!stack.isEmpty() && stack.peek() == popA[index]) {
                stack.pop();
                index++;
            }
        }
        return stack.isEmpty();
    }

猜你喜欢

转载自blog.csdn.net/SunshineTan/article/details/80964782