首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >栈的实现

栈的实现
EN

Code Review用户
提问于 2016-02-10 16:45:53
回答 1查看 2.3K关注 0票数 9

任务:创建一个类RPNStack,它表示Node类型的对象堆栈。类RPNStack只包含Node类型顶部的一个私有字段。Node类型的对象表示在堆栈上推送的数据:每个对象在其字段val中包含对下一个节点的引用,在其字段中包含一个双值(在这里,单链列表顶部扮演的是头的角色)。类RPNStack提供了三种方法:

  • 方法公开空推(Double d)将节点类型的新对象推到堆栈顶部(即成为新的顶);
  • 方法公共双pop()移除顶节点(因此下一个节点成为新的顶)并从删除的节点返回val;
  • 方法返回true当且仅当堆栈为空(top为空),否则返回false。

请注意,堆栈是一个单链接列表,其中添加和删除元素总是在开始时执行。主程序读取一个用反向波兰表示法(RPN)表示算术表达式的le,例如:2 7 5+*2 0-1 4//在读取每一行后,它被拆分(使用空格作为分隔符),对于每个标记:

  • 如果它是字符串"+",我们从堆栈中弹出两个数字,添加它们并将结果推到堆栈上;
  • 如果它是字符串"*",我们做同样的,但我的数字,而不是添加它们;
  • 如果是字符串"-",则弹出两个元素,从第二个弹出的元素中减去一个弹出的元素,然后将结果推到堆栈上;
  • 如果它是字符串"/",我们做同样的,但除以数字,而不是减去它们;
  • 如果它不是"+“、"*”、"-“或"/",我们将其解释为多个类型double,然后将其推到堆栈上。

在处理完行中的所有标记之后,我们会弹出堆栈的其余数字,这应该是整个表达式的值。然后,我们打印行和结果。我们还检查堆栈现在是否是空的;如果没有,我们会通知用户这个事实,我们清除堆栈,并对输入文件的其余行重复该过程。

我的实施:

我巧妙地修改程序,将其写入文件,只是为了练习。

代码语言:javascript
复制
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {
    public static void main(String[] args) {
        String fileName = "Numbers.txt";
        String fileRes = "NumbersCalc.txt";
        Path filein = Paths.get(fileName);
        if (!Files.exists(filein)     ||
            !Files.isReadable(filein) ||
             Files.isDirectory(filein)) {
            System.out.println("Invalid input file !!!");
            System.exit(1);
        }
        try (BufferedWriter bw =
                Files.newBufferedWriter(Paths.get(fileRes));
             BufferedReader br =
                Files.newBufferedReader(filein)
            ) {
            String line;
            while ( (line = br.readLine()) != null) {
                String[] lineParts = line.split("\\s+");
                for (String string : lineParts) {
                    if(string.equals("+")){
                        RPNStack.push( RPNStack.pop() + RPNStack.pop() );
                    }else if(string.equals("-")){
                        RPNStack.push( RPNStack.pop() - RPNStack.pop() );
                    }else if(string.equals("*")){
                        RPNStack.push( RPNStack.pop() * RPNStack.pop() );
                    }else if(string.equals("/")){
                        RPNStack.push( RPNStack.pop() / RPNStack.pop() );
                    }else if(!string.equals("+") &&!string.equals("-")&&!string.equals("*")&&!string.equals("/")){
                        RPNStack.push(Double.parseDouble(string));
                    }
                }
                bw.write(RPNStack.pop()+System.lineSeparator()/*"\n"*/);
            }
            System.out.println("Results written to " + fileRes);
            if(RPNStack.empty()) System.out.println("Stack is empty");
        } catch(IOException e) {
            System.out.println("Something wrong");
            System.exit(1);
        }
    }
}


public class RPNStack {
    private static Node top = null;

    public static Node getTop() {
        return top;
    }
    public static void push(double d){
        if(top == null) top = new Node(d);
        else            top = new Node(d, top);
    }
    public static double pop(){
        double buf = top.getVal(); 
        top = top.getNext();
        return buf; 
    }
    public static boolean empty(){
        if(top == null) return true;
        else            return false;
    }
}

public class Node {
    private double val;
    private Node next;

    public double getVal() {
        return val;
    }
    public Node getNext() {
        return next;
    }

    public Node(double val, Node next){
        this.val=val;
        this.next=next;
    }
    public Node(double val){
        this(val,null);
    }
}

Numbers.txt:

代码语言:javascript
复制
2 7 5 + * 20 - 1 4 / /
2 7 5 + * 20 - 1 4 / /

问题:

  • 我假设我们需要在类RPNStack中使用静态函数。是对的吗?
  • 当我使用BuffedWriter "\n“时,根本不起作用(我希望从新行中打印值,但它一个接一个地运行),所以我不得不使用"System.lineSeparator()”,我不知道为什么?运行Win 8.1\Eclipce火星
  • 是否有更好的方法来识别符号,而不是串在其他语句上?
  • 只在IOException中使用可以吗?还是我们还需要再用一个渔获物作为异常呢?
  • 还有什么可以做得更好呢?
EN

回答 1

Code Review用户

发布于 2016-02-10 18:11:57

代码语言:javascript
复制
if (!Files.exists(filein)     ||
     !Files.isReadable(filein) ||
     Files.isDirectory(filein)) {
     System.out.println("Invalid input file !!!");
     System.exit(1);
}
  • 假设您在输出中看到消息Invalid input file !!!,这三种消息中哪一种失败了?你能说出来吗?不用手动检查吗?思想的食粮。
  • 这三个条件结合在一起,可以用一个有意义的名称作为单独的方法。喜欢

示例

代码语言:javascript
复制
boolean isFileReadable(File file) 

请将ifs系列替换为switch语句。它会更容易读懂。

代码语言:javascript
复制
String result = "";
String first = RPNStack.pop();
String second = RPNStack.pop(); 
switch(string) {
    case "+":
        result = first + second;
        break;
    //similarly all others. The last else if will become default:
 }
 RPNStack.push(result);

这样逻辑就清楚了。

\n不能在Windows上工作的原因是不同的操作系统有不同的行分隔符。快速的谷歌搜索可以告诉你这意味着什么。

假设方法应该是静态的,这将导致您有一个Stack。你不会想要那样的。static的意思是属于类,但是如果您想在程序中有两个堆栈呢?您应该有实例方法。

关于这个

代码语言:javascript
复制
System.out.println("Something wrong");

怎么了?哪里?如果捕捉到异常,那么至少要将堆栈跟踪添加到打印的消息中。多么?谷歌搜索。

关于只捕获IOException,我说只捕获需要捕获的东西。如果您正在捕获异常,那么如果您可以在catch块中添加一些东西来恢复。如果不可能,那么至少记录一条不需要手动检查错误信息的错误消息。

现在还有什么可以做得更好呢?您可以使用Java的泛型使您的堆栈可重用。您应该创建一个Stack类,然后创建一个使用泛型堆栈类来完成其功能的RPNStack。在您的示例中,您所调用的Main实际上是逻辑上的RPNStack,而您已经命名的RPNStack类是一个堆栈。主类应该只给RPNStack字符串并得到结果。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/119521

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档