算法(Java)——栈、队列、堆

在刷算法题中,栈是一种常用的数据结构。下面介绍一些Java中栈的常用的一些方法以及力扣刷题中用到栈的一些题目。

Java Stack类,栈是Vector的一个子类,实现后进先出的栈。

Stack stackA = new Stack();

使用Stack类,由于Stack继承了Vector接口,而Vector底层是一个Object[]数组,那么就要考虑空间扩容和移位的问题,造成速度较慢,可以使用LinkedList来做Stack的容器。

1.栈的函数
Stack<Integer> stack = new Stack<Integer>();//建栈
stack.push(Element);//进栈
stack.pop();//出栈
stack.peek();//取栈顶值(不出栈)
stack.isEmpty();//判断栈是否为空
2.力扣关于栈的题
1)剑指offer09:用两个栈实现队列

题目:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

解题思路:用两个栈,一个栈将输入的数存入栈中,再出栈存到另一个栈中,再出栈的时候就实现了队列的先进先出。

算法代码

class CQueue {
    private Stack StackA;
    private Stack StackB;
    public CQueue() {  //创建栈
        StackA = new Stack();
        StackB = new Stack();
    }    
    public void appendTail(int value) { //入队,进栈
        StackA.push(value);
    }    
    public int deleteHead() {
        if(StackB.empty()){ 
            while(!StackA.empty()){ //将栈A中的数都存到栈B中
                StackB.push(StackA.pop());
            }
        }
        if(StackB.empty()) return -1;
        else return (int)StackB.pop();
    }
}
2)剑指offer31:栈的压入,弹出序列

题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。

解题思路:辅助栈,判断栈顶元素与输出序列是否相同,相同则出栈,最后判断栈是否为空。

算法代码

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        Stack<Integer> stackA = new Stack();
        int in=0;
        for(int i=0;i<pushed.length;i++){
            stackA.push(pushed[i]);  //进栈
            while(!stackA.isEmpty() && stackA.peek()==popped[in]){ 
                //栈顶元素等于出栈序列元素,出栈
                stackA.pop();
                in++;
            }
        }
        return stackA.isEmpty();//根据栈是否为空,判断
    }
}
3)剑指offer30:包含min函数的栈。

题目:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

解题思路:建立两个辅助栈。

  1. 辅助栈A:用于存储所有元素,保证入栈push()函数、出栈pop()函数,获取栈顶top()函数的正常逻辑。
  2. 辅助栈B:存储栈A中所有非严格降序的元素,则栈A中的最小元素始终对应栈B的栈顶元素。

算法代码

class MinStack {

    Stack<Integer> stackA, stackB;
    public MinStack() {
        stackA = new Stack<>();
        stackB = new Stack<>();
    }
    
    public void push(int x) {
        stackA.add(x);
        if(stackB.empty()||stackB.peek()>=x)
            stackB.add(x);
    }
    
    public void pop() {
        if(stackA.pop().equals(stackB.peek()))  //比较的同时,先执行stackA.pop()
            stackB.pop();
    }
    
    public int top() {
        return stackA.peek();
    }
    
    public int min() {
        return stackB.peek();
    }
}

队列

LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用。

Queue<String> queue = new LinkedList<String>();
1.队列的函数
添加:queue.offer() queue.add()
删除队列第一个元素:queue.poll()返回null queue.remove()返回异常
查询队列头部元素:peek()返回null element()返回异常
2.力扣关于队列的题

待补充

堆主要介绍PriorityQueue实现的堆。

PriorityQueue,即优先队列。优先队列的作用是能保证每次取出的元素都是队列中权值最小的。堆保证每次插入都排好序。

Java中PriorityQueue默认是小顶堆,可以通过传入自定义的Comparator函数来实现大顶堆。

PriorityQueue<Integer> queue = new PriorityQueue<Integer>(new Comparator<Integer>(){
            public int compare(Integer n1, Integer n2){
                return n2-n1;
            }
        });
1.优先队列实现的堆的函数
创建:PriorityQueue<Integer> queue = new PriorityQueue<Integer>(new Comparator<Integer>()
add()offer() 向优先队列中插入元素
element()peek() 获取但不删除队首元素
remove()poll() 获取并删除队首元素
2.力扣关于堆的题
1)剑指offer40:最小的k个数

题目:输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

解题思路:使用大顶堆,先将前k个元素加入大顶堆,然后遍历其余元素,若小于堆顶,则加入堆,最后输出堆。

算法代码

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        int[] res = new int[k];
        if(k==0) return res;
        //将小顶堆改为大顶堆,通过comparator函数
        PriorityQueue<Integer> queue = new PriorityQueue<Integer>(new Comparator<Integer>(){
            public int compare(Integer n1, Integer n2){
                return n2-n1;
            }
        });
        for(int i=0;i<k;i++)  queue.offer(arr[i]); //将数组前k个元素加入大顶堆
        for(int i=k;i<arr.length;i++){ //遍历其余元素,若小于堆顶,则加入堆
            if(queue.peek()>arr[i]){
                queue.poll();
                queue.offer(arr[i]);
            }
        }
        for(int i=0;i<k;i++) res[i]=queue.poll(); //将遍历完的大顶堆中元素存入数组
        return res;
    }
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1. 什么是二叉树? 二叉树是一种树形结构,其中每个节点最多有两个子节点。一个节点的左子节点比该节点小,右子节点比该节点大。二叉树通常用于搜索和排序。 2. 二叉树的遍历方法有哪些? 二叉树的遍历方法包括前序遍历、中序遍历和后序遍历。前序遍历是从根节点开始遍历,先访问根节点,再访问左子树,最后访问右子树。中序遍历是从根节点开始遍历,先访问左子树,再访问根节点,最后访问右子树。后序遍历是从根节点开始遍历,先访问左子树,再访问右子树,最后访问根节点。 3. 二叉树的查找方法有哪些? 二叉树的查找方法包括递归查找和非递归查找。递归查找是从根节点开始查找,如果当前节点的值等于要查找的值,则返回当前节点。如果要查找的值比当前节点小,则继续在左子树中查找;如果要查找的值比当前节点大,则继续在右子树中查找。非递归查找可以使用队列实现,从根节点开始,每次将当前节点的左右子节点入/队列,直到找到要查找的值或者/队列为空。 4. 二叉树的插入与删除操作如何实现? 二叉树的插入操作是将要插入的节点与当前节点的值进行比较,如果小于当前节点的值,则继续在左子树中插入;如果大于当前节点的值,则继续在右子树中插入。当找到一个空节点时,就将要插入的节点作为该空节点的子节点。删除操作需要分为三种情况:删除叶子节点、删除只有一个子节点的节点和删除有两个子节点的节点。删除叶子节点很简单,只需要将其父节点的对应子节点置为空即可。删除只有一个子节点的节点,需要将其子节点替换为该节点的位置。删除有两个子节点的节点,则可以找到该节点的后继节点(即右子树中最小的节点),将其替换为该节点,然后删除后继节点。 5. 什么是平衡二叉树? 平衡二叉树是一种特殊的二叉树,它保证左右子树的高度差不超过1。这种平衡可以确保二叉树的查找、插入和删除操作的时间复杂度都是O(logn)。常见的平衡二叉树包括红黑树和AVL树。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值