如何保持“已完成的事情” Java中的递归算法中的计数?
我有一个递归算法,它逐个字符地遍历字符串,并解析它以创建树状结构。 我希望能够跟踪解析器当前所在的字符索引(对于错误消息以及其他任何内容),但我不热衷于实现像元组这样的东西来处理多个返回类型。
我尝试使用 Integer 类型,在方法外部声明并传递到递归方法中,但因为它是最终的,所以当我返回时,递归调用增量会被“忘记”。 (因为整数值的增量使按值传递的对象引用指向新对象)
有没有办法获得类似于工作的东西,而不会污染我的代码?
I have a recursive algorithm which steps through a string, character by character, and parses it to create a tree-like structure. I want to be able to keep track of the character index the parser is currently at (for error messages as much as anything else) but am not keen on implementing something like a tuple to handle multiple returned types.
I tried using an Integer type, declared outside the method and passed into the recursive method, but because it's final, recursive call increments are "forgotten" when I return. (Because the increment of the Integer value makes the passed-by-value object reference point at a new object)
Is there a way to get something similar to work which won't pollute my code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
你还可以这样做:
You could also do:
整数是不可变的,这意味着当您将其作为参数传递时,它会创建一个副本而不是对同一项目的引用。 (说明)。
为了获得您正在寻找的行为,您可以编写自己的类,它就像仅可变的 Integer 类。 然后,只需将其传递给递归函数,它就会在递归中递增,并且当递归结束后再次访问它时,它仍然会保持其新值。
编辑:请注意,使用 int[] 数组是此方法的变体...在 Java 中,数组也是通过引用传递的,而不是像基元或不可变类那样复制。
Integers are immutable, which means that when you pass it as an argument it creates a copy rather than a reference to the same item. (explanation).
To get the behavior you're looking for, you can write your own class which is like Integer only mutable. Then, just pass it to the recursive function, it is incremented within the recursion, and when you access it again after the recursion is over it will still maintain its new values.
Edit: Note that using an int[] array is a variation on this method... In Java, arrays are also passed by reference rather than copied like primitives or immutable classes.
您可以只使用一个静态 int 类变量,每次调用 doIt 方法时该变量都会递增。
You could just use a static int class variable that gets incremented each time your doIt method is called.
既然您已经发现了伪可变整数“hack”,那么这个选项怎么样:
创建一个单独的解析器类对您来说有意义吗? 如果这样做,您可以将当前状态存储在成员变量中。 您可能需要考虑如何处理任何线程安全问题,对于这个特定的应用程序来说这可能有点过分了,但它可能对您有用。
Since you've already discovered the pseudo-mutable integer "hack," how about this option:
Does it make sense for you to make a separate Parser class? If you do this, you can store the current state in a member variable. You probably need to think about how you're going to handle any thread safety issues, and it might be overkill for this particular application, but it might work for you.
这是一种黑客行为,但有时我使用可变的 AtomicInteger 来做这样的事情。 我还见过传入大小为 1 的 int[] 的情况。
It's kind of a hack, but sometimes I use an AtomicInteger, which is mutable, to do things like this. I've also seen cases where an int[] of size 1 is passed in.
我当前使用的解决方案是:
然后将其传递给递归算法:
当我想增加它时:
不是超级优雅,但它有效......
The current solution I am using is:
and then pass it to the recursive algorithm:
and when I want to increment it:
Not super elegant, but it works...
老实说,我会重新编码该函数,使其成为使用循环的线性算法。 这样,如果您单步执行非常大的字符串,就不会耗尽堆空间。 此外,您不需要仅仅为了跟踪计数而使用额外的参数。
这也可能会使算法更快,因为它不需要为每个字符进行函数调用。
当然,除非有特定原因,否则它需要递归。
To be honest I would recode the function to make it a linear algorithm that uses a loop. This way you have no chance of running out of heap space if you are stepping through an extremely large string. Also, you would not need to have a the extra parameter just to keep track of the count.
This also would probably have the result of making the algorithm faster because it does not need to make a function call for every character.
Unless of course there is a specific reason it needs to be recursive.
我能想到的一种可能性是将计数存储在类的成员变量中。 当然,这假设公共
doIt
方法仅由单个线程调用。另一种选择是重构公共方法以调用私有帮助器方法。 私有方法将列表作为参数并返回计数。 例如:
这假设您可以在公共
doIt
方法中执行错误处理,因为count
变量实际上并未传递回调用方。 如果您需要这样做,您当然可以抛出异常:如果不了解更多关于算法实际工作原理的信息,很难知道这是否有帮助。
One possibility I can think of is to store the count in a member variable of the class. This of course assumes that the public
doIt
method is only called by a single thread.Another option is to refactor the public method to call a private helper method. The private method takes the list as a parameter and returns the count. For example:
This assumes that you can do the error handling in the public
doIt
method, since thecount
variable isn't actually passed back to the caller. If you need to do that, you could of course throw an exception:It's difficult to know whether that will help without knowing more about how your algorithm actually works.