【数据结构与算法】栈与队列相关算法的实现

目录

检查括号是否成对出现

反转字符串

循环队列的实现

使用队列实现栈

使用栈实现队列


检查括号是否成对出现

算法要求

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断该字符串是否有效。
有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

比如: "()"、"()[]{}"、"{[]}" 都是有效字符串,而 "(]" 、"([)]" 则不是 

解题思路     

1、我们可以通过一个HashMap来存放所有括号类型,右括号为键,左括号为值。

2、遍历字符串,如果是左括号就入栈,右括号则和栈顶元素作比较,如果刚好形成一对完成括号,则继续。否则说明不是一对完整括号。

3、遍历结束后判断栈中元素是否全部取出,只有全部取出,说明这个字符串中符号成对出现。

    /**
     * 判断这个符号字符串中符号是否成对出现
     * @param s
     * @return
     */
    public static boolean isValid(String s){
        //创建一个hashMap把所有符号都存入
        Map<Character,Character> maps =new HashMap<>();
        maps.put(')','(');
        maps.put(']','[');
        maps.put('}','{');

        Stack<Character> stack =new Stack<>();
        //将字符串转换为字符数组
        char[] chars= s.toCharArray();
        //遍历字符数组
        for (int i = 0; i <chars.length ; i++) {
            //判断这个符号是否为右括号
            if (maps.containsKey(chars[i])){
                //栈中如果为空赋值为#否则取出栈顶元素
                char isEmpty =stack.isEmpty()?'#':stack.pop();
                //判断这个右括号对应的左括号是否等于栈顶元素
                if (isEmpty!=maps.get(chars[i])){
                    return false;
                }
            }else {
                //如果为左括号则入栈
                stack.push(chars[i]);
            }
        }
        //遍历结束 如果栈中还有元素 则说明其中没有对应括号
        return stack.isEmpty();
    }

测试

    public static void main(String[] args) {
        System.out.println("[]{}()中符号是否成对出现:"+isValid("[]{}()"));
        System.out.println("{([})}中符号是否成对出现:"+isValid("{([])}"));
        System.out.println("([)]中符号是否成对出现:"+isValid("([)]"));
        System.out.println("(()中符号是否成对出现:"+isValid("(()"));
    }

测试结果


反转字符串

这个就直接运用栈的后进先出原则,把字符串依次入栈再出栈就行。

   /**
    * 字符串的反转
    * @param s
    * @return
    */   
    public static String stringReversal(String s){
        Stack<Character> stack =new Stack<>();
        for (int i =0;i<s.length();i++){
            stack.push(s.charAt(i));
        }
        String news="";
        for (int i = 0, len = stack.size(); i < len; i++) {
            news+=stack.pop();
        }
        return news;
    }

测试

    public static void main(String[] args) {
        String ts ="the shy";
        String yskm ="you should know me";
        System.out.println("ts反转前:"+ts);
        System.out.println("ts反转后:"+stringReversal(ts));
        System.out.println("yskm反转前:"+yskm);
        System.out.println("yskm反转后:"+stringReversal(yskm));

    }

测试结果


循环队列的实现

和队列相比,循环队列的优点就是不会造成假溢出,因为当队尾到达数组的末尾时,如果数组头部还有空间,则会继续向头部移动。会形成一个循环,除非队尾与队头相邻,则队列才满。

/**
 * 循环队列的实现
 * @author CC
 * @version 1.0
 * @since2023/9/28
 */
public class CircularQueue {
    private int[] array;//使用数组来存储
    private int front;//对头
    private int rear;//队尾

    //实例队列并设置初始容量
    public CircularQueue(int capacity){
        this.array =new int[capacity];
    }


    /**
     * 入队
     * @param element
     * @throws Exception
     */
    public void offer(int element) throws Exception {
        //队尾不能存值 所以队尾的下一个元素如果是队头 说明队列已满
        if ((rear+1)%array.length==front){
            throw new Exception("队列已满!");
        }
        //将值存入队尾
        array[rear] =element;
        //队尾向后移动
        rear =(rear+1)%array.length;
    }

    /**
     * 出队
     * @return
     * @throws Exception
     */
    public int pull() throws Exception {
        //如果队头等于队尾 则只有一个可能 就是该队为空
        if (rear==front){
            throw new Exception("队列为空!");
        }
        //取出队头元素
        int deQueueElement =array[front];
        //队头向后移动
        front=(front+1)%array.length;
        return deQueueElement;
    }

    /**
     * 输出队列
     * @return
     */
    @Override
    public String toString() {
        StringJoiner sj =new StringJoiner("-");
        for (int i=front;i!=rear;i=(i+1)%array.length){
            sj.add(String.valueOf(array[i]));
        }
        return sj.toString()+"-队尾";
    }
}

测试

/**
 * @author CC
 * @version 1.0
 * @since2023/9/28
 */
public class CTest {
    public static void main(String[] args) throws Exception {
        CircularQueue queue = new CircularQueue(5);
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        queue.offer(4);
        System.out.println("接连将1、2、3、4分别入队后:"+queue);
        queue.pull();
        System.out.println("发生一次出队后:"+queue);
        queue.offer(5);
        System.out.println("将5入队后:"+queue);
    }
}

测试结果


使用队列实现栈

实现原理

通过创建两个队列,一个为出栈队列,一个为入栈队列。首先入栈队列是一直为空的,在入栈时先将元素存入入栈队列,再将出栈队列的元素依次存入入栈队列,这就将刚入元素就被放入了队尾。然后交换两个队列,出栈时将出栈队列队头元素出栈,也就是最早入栈的元素。

/**
 * @author CC
 * @version 1.0
 * @since2023/9/30
 */
public class MyStack {
    private Queue<Integer> queue1; //出栈队列
    private Queue<Integer> queue2; //入栈队列

    /**
     * 初始化栈 底层使用链表存储
     */
    public MyStack() {
        queue1 = new LinkedList<Integer>();
        queue2 = new LinkedList<Integer>();
    }

    /**
     * 入栈
     * @param item
     */
    public void push(int item) {
        //将元素存入队列2
        queue2.offer(item);
        //将队列1中元素依次出队 并存入队列2
        while (!queue1.isEmpty()){
            queue2.offer(queue1.poll());
        }
        //交换队列1 与 队列2
        Queue<Integer> temp = queue1;
        queue1 = queue2;
        queue2 = temp;
    }

    /**
     * 出栈
     * @return
     */
    public int pop(){
        return queue1.poll();
    }

    /**
     * 获取栈顶元素
     * @return
     */
    public int top(){
        return queue1.peek();
    }

    /**
     * 判断该栈是否为空
     * @return
     */
    public boolean isEmpty(){
        return queue1.isEmpty();
    }


    /**
     * 输出栈中元素
     * @return
     */
    @Override
    public String toString() {
        StringJoiner sj =new StringJoiner("-");
        for (Integer integer : queue1) {
            sj.add(String.valueOf(integer));
        }
        return "栈顶"+sj.toString();
    }
}

测试

/**
 * @author CC
 * @version 1.0
 * @since2023/9/30
 */
public class MyStackT {
    public static void main(String[] args) {
        MyStack stack =new MyStack();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        System.out.println("1、2、3、4依次入栈后:"+stack);

        System.out.println("出栈元素:"+stack.pop());
        System.out.println("出栈一次后:"+stack);

        System.out.println("查看栈顶元素(不取出):"+stack.top());

        System.out.println("查看栈顶元素后:"+stack);
        System.out.println("该栈是否为空:"+stack.isEmpty());
        System.out.println("出栈元素:"+stack.pop());
        System.out.println("出栈元素:"+stack.pop());
        System.out.println("出栈元素:"+stack.pop());
        System.out.println("该栈是否为空:"+stack.isEmpty());
    }
}

 测试结果


使用栈实现队列

实现原理

创建两个栈,一个为入队栈、一个为出队栈。入队栈的出栈顺序为后进先出。因为出队时,需要把入队栈的元素依次出栈再入栈到出队栈。后进先出的后进先出就为先进先出。所以出队栈的出栈顺序为先进先出。以此来实现和队列相同逻辑,先进先出。

/**
 * @author CC
 * @version 1.0
 * @since2023/9/30
 */
public class MyQueue {
    private Stack<Integer> inStack =new Stack<>(); //入队栈
    private Stack<Integer> outStack =new Stack<>(); //出队栈

    /**
     * 入队
     * @param item
     */
    public void offer(int item){
        //将出堆栈中的元素依次放入入队栈中
        while (!outStack.isEmpty()){
            inStack.push(outStack.pop());
        }
        //入队栈入栈
        inStack.push(item);
    }

    /**
     * 出队
     * @return
     */
    public int poll(){
        //将入堆栈中的元素依次放入出队栈中
        while (!inStack.isEmpty()){
            outStack.push(inStack.pop());
        }
        //出堆栈出栈
        return outStack.pop();
    }

    /**
     * 判断队中是否为空
     * @return
     */
    public boolean isEmpty(){
        return inStack.isEmpty()&outStack.isEmpty();
    }

    /**
     * 查看队列元素
     * @return
     */
    @Override
    public String toString() {
        while (!inStack.isEmpty()){
            outStack.push(inStack.pop());
        }
        StringJoiner sj =new StringJoiner("-");
        for (Integer integer : outStack) {
            sj.add(integer.toString());
        }
        return "队尾-"+sj.toString();
    }
}

测试

public class MyQueueT {
    public static void main(String[] args) {
        MyQueue myQueue =new MyQueue();
        // 入队
        myQueue.offer(1);
        myQueue.offer(2);
        myQueue.offer(3);
        myQueue.offer(4);
        myQueue.offer(5);
        System.out.println("依次入队1、2、3、4、5后:"+myQueue);

        // 出队
        System.out.println("出队:"+myQueue.poll()); // 1
        System.out.println("出队:"+myQueue.poll()); // 2
        System.out.println("出队:"+myQueue.poll()); // 3
        System.out.println("连续三次出队后:"+myQueue);
        // 入队
        myQueue.offer(6);
        myQueue.offer(7);
        myQueue.offer(8);
        System.out.println("依次入队6、7、8后:"+myQueue);
        // 出队
        System.out.println("出队:"+myQueue.poll()); // 4
        System.out.println("出队:"+myQueue.poll()); // 5
        System.out.println("出队:"+myQueue.poll()); // 6
        System.out.println("连续三次出队后:"+myQueue);
        System.out.println("队内是否为空:"+myQueue.isEmpty());

        System.out.println("出队:"+myQueue.poll()); // 7
        System.out.println("出队:"+myQueue.poll()); // 8
        System.out.println("队内是否为空:"+myQueue.isEmpty());
    }
}

测试结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值