数据结构之栈的实现和有关问题

​本文概要:

  1. 栈的实现

  2. 括号匹配问题

  3. 逆波兰表达式求值问题

 

概述

栈是一种先进后出(FILO)的数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读取数据时从栈顶开始弹出数据。

我们称数据进入栈的动作我们称为压栈,数据从栈中出去的动作为弹栈。

栈的实现

public class Stack<T> implements Iterable<T> {
   /**
    * 栈空间大小,初始为0
    */
   private int size;
   /**
    * 定义链表表头
    */
   private Node<T> head;

   /**
    * 定义节点类,使用链表的方式实现栈
    * @param <T>
    */
   class Node<T> {
       /**
        * 数据元素
        */
       private T item;
       /**
        * 下一个节点指针
        */
       private Node<T> next;

       public Node(T item,Node<T> next){
           this.item = item;
           this.next = next;
      }
  }

   /**
    * 栈的构造方法,初始化栈空间大小和head节点
    */
   public Stack(){
       this.size = 0;
       this.head = new Node<>(null,null);
  }

   /**
    * 获取栈空间元素个数
    * @return
    */
   public int size(){
       return size;
  }

   /**
    * 判断栈是否为空
    * @return
    */
   public boolean isEmpty(){
       return size == 0;
  }
   /**
    * 压栈,将节点元素压入栈中
    * @param item 节点元素
    */
   public void push(T item){
       //首结点指向的第一个节点
       Node<T> oldFirst = head.next;
       //需要插入的新节点
       Node<T> newNode = new Node<>(item,null);
       //让首结点指向新节点
       head.next = newNode;
       //让新节点指向原来的第一个节点
       newNode.next = oldFirst;
       //元素个数+1
       size++;
  }

   /**
    * 弹栈,将第一个元素弹出
    * @return
    */
   public T pop(){
       //首结点指向的第一个节点
       Node<T> oldFirst = head.next;
       if(oldFirst==null){
           return null;
      }
       //让首结点指向原来第一个节点的下一个节点
       head.next = oldFirst.next;
       //元素个数-1
       size--;
       return oldFirst.item;
  }


   @Override
   public Iterator<T> iterator() {
       return new SIterator();
  }

   private class SIterator implements Iterator<T>{
       private Node<T> node;

       public SIterator(){
           this.node = head;
      }
       @Override
       public boolean hasNext() {
           return node.next!=null;
      }
       @Override
       public T next() {
           node = node.next;
           return node.item;
      }
  }
}

测试:

public class StackTest {

   @Test
   public void stackTest(){
       Stack<String> stack = new Stack<>();

       stack.push("a");
       stack.push("b");
       stack.push("c");
       stack.push("d");

       for (String s : stack) {
           System.out.println(s);
      }

       System.out.println("-------------");
       int size = stack.size();
       System.out.println("栈内元素个数:"+size);
       for (int i = 0; i < size; i++) {
           System.out.println(stack.pop());
      }
       System.out.println("-------------");
       System.out.println(stack.isEmpty());

  }
}

案例1 括号匹配问题

问题描述:

给定一个字符串,里边可能包含“()”小括号和其他字符,请编写程序检查该字符串中的小括号是否成对出现。

例如:
“(上海)(长安)”:正确匹配
“上海((长安))”:正确匹配
“上海(长安(北京)(深圳)南京)”:正确匹配
“上海(长安))”:错误匹配
“((上海)长安”:错误匹配

示例代码:

@Test
public void bracketsMatch() {
   String str1 = "(上海)(长安)";
   String str2 = "上海((长安))";
   String str3 = "上海(长安(北京)(深圳)南京)";
   String str4 = "上海(长安))";
   String str5 = "((上海)长安";
   System.out.println(isMatch(str1));
   System.out.println(isMatch(str2));
   System.out.println(isMatch(str3));
   System.out.println(isMatch(str4));
   System.out.println(isMatch(str5));
}
public static boolean isMatch(String str) {
   //判空处理
   if (str == null || str.length() == 0) {
       return true;
  }
   //定义一个栈来存放左括号
   Stack<Character> bracket = new Stack<>();
   for (int i = 0; i < str.length(); i++) {
       //遍历字符串,如果遇到左括号就压入栈中
       if ('(' == str.charAt(i)) {
           bracket.push('(');
      } else if (')' == str.charAt(i)) {
           //如果遇到右括号就进行弹栈,如果弹栈元素为空则说明括号不匹配
           Character pop = bracket.pop();
           if (pop == null) {
               return false;
          }
      }
  }
   //遍历结束之后看栈中是否还剩余左括号,如果栈为空则说明字符串括号匹配,如果不为空则说明括号不匹配
   return bracket.isEmpty();
}

 

案例2逆波兰表达式求值问题

中缀表达式:

平常生活中使用的表达式,例如:1+3*2,2-(1+3)等等,特点是:二元运算符总是置于两个操作数中间。

逆波兰表达式(后缀表达式):运算符总是放在跟它相关的操作数之后。例如:ab+

中缀表达式逆波兰表达式
a+bab+
a+(b-c)abc-+
a+(b-c)*dabc-d*+

需求:

给定一个只包含加减乘除四种运算的逆波兰表达式的数组表示方式,求出该逆波兰表达式的结果。

/**
* 案例2:逆波兰表达式
* 给定一个只包含加减乘除四种运算的逆波兰表达式的数组表示方式,求出该逆波兰表达式的结果。
* 中缀表达式:3*(17-15)+18/6
*/
@Test
public void againstPolandTest() {
   //中缀表达式:3*(17-15)+18/6,逆波兰表达式如下
   String[] notation = {"3", "17", "15", "-", "*", "18", "6", "/", "+"};
//实现caculate方法
   int result = caculate(notation);
   System.out.println("逆波兰表达式的计算结果为:" + result);
}

caculate方法的实现

private int caculate(String[] notation) {
   //定义一个栈来存储操作数
   Stack<Integer> stack = new Stack<>();
   //从左往右遍历逆波兰表达式,得到每一个元素
   for (int i = 0; i < notation.length; i++) {
       String cuur = notation[i];
       //判断当前元素是操作数还是运算符
       int t1;
       int t2;
       switch (cuur) {
           //如果是运算符,则从栈中弹出两个元素进行计算,并把计算结果压入栈中
           case "+":
               t1 = stack.pop();
               t2 = stack.pop();
               stack.push(t2 + t1);
               break;
           case "-":
               t1 = stack.pop();
               t2 = stack.pop();
               stack.push(t2 - t1);
               break;
           case "*":
               t1 = stack.pop();
               t2 = stack.pop();
               stack.push(t2 * t1);
               break;
           case "/":
               t1 = stack.pop();
               t2 = stack.pop();
               stack.push(t2 / t1);
               break;
           //如果是操作数,则直接压入栈中
           default:
               stack.push(Integer.parseInt(cuur));
               break;
      }

  }
   //最后栈中的数据就是计算结果
   return stack.pop();
}

 

好了,本次内容就是这些,学无止境,关注我,我们一起学习进步。如果觉得内容还可以,帮忙点个赞,点个在看呗,谢谢~我们下期见。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值