Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 递归使用多少堆栈(从列表中删除节点)?_Java_List_Recursion_Linked List_Stack Overflow - Fatal编程技术网

Java 递归使用多少堆栈(从列表中删除节点)?

Java 递归使用多少堆栈(从列表中删除节点)?,java,list,recursion,linked-list,stack-overflow,Java,List,Recursion,Linked List,Stack Overflow,更新:请注意,目前这个问题没有多大意义,因为调用堆栈将独立于类型T而增长。调用堆栈仅取决于正在处理的列表中的节点数-这些节点中包含的数据对调用堆栈的大小没有影响 假设我有一个“从列表中删除节点”方法的递归java实现,该方法如下所示: // head public void remove(T data) { if (data == null) throw new IllegalArgumentException(); head = remove(head, da

更新:请注意,目前这个问题没有多大意义,因为调用堆栈将独立于类型T而增长。调用堆栈仅取决于正在处理的列表中的节点数-这些节点中包含的数据对调用堆栈的大小没有影响


假设我有一个“从列表中删除节点”方法的递归java实现,该方法如下所示:

// head
public void remove(T data) {
    if (data == null)
        throw new IllegalArgumentException();
    head = remove(head, data);
}

// other nodes of list
private ListNode remove(ListNode current, T data) {
    if (current == null)
        return null;
    if (current.data.compareTo(data) == 0)
        return current.next;
    current.next = remove(current.next, data);
    return current;
} 
让我们进一步假设类型
T
int

我的问题是:与我正在处理的列表的大小相比,调用堆栈(在最坏的情况下)会有多大

到目前为止我的想法: 据我所见,Java8没有优化递归(对吗?我的整个分析都假设这是真的)。因此,我们将有一个随列表大小线性增长的调用堆栈

更准确地说:这个方法
remove(listnodecurrent,T data)
基本上将在我列表中的每个节点的调用堆栈上放置一个节点引用(32位arch上的32位)和一个
int
(也是32位)

现在,由于列表中的一个节点也由一个引用和一个
int
组成,因此一个节点实际上与其中一个递归调用的大小几乎相同。实际上,其中一个调用甚至可能会占用更多的空间(返回地址也必须推送到堆栈上,对吗?或者可以通过某种方式进行优化?)

因此,如果我是正确的,那么调用堆栈将基本上与最坏情况下的列表本身一样大(当要删除的元素是列表中的最后一个元素时)!真的是这样吗?如果我是正确的,那么对于处理
int
s列表所需的调用堆栈,这意味着一个因子为1甚至更大!因此,在处理大型列表(实际上甚至没有那么大)时,如果使用stacksize的默认设置(0.5M)运行,例如1M,则会出现stackoverflow

我知道,对于更大的数据类型,该因子将更小,但我仍然坚持在任何情况下基本上是这样的:如果没有进行优化,那么调用堆栈将随着列表的大小线性增长-因此,人们应该更喜欢迭代过程而不是递归过程

一般来说,我会说,调用堆栈将以一个因子
大致线性增长(调用中所有参数的大小+返回地址的大小)/单个列表元素的大小,在
int
s的列表中几乎相同,对吗?请不要误解我对所有参数的
size\u的理解:我知道我们只将引用的值传递给那些调用中的对象,而不是整个对象本身。因此,对于大型对象,这个因素可能没有那么显著,但我仍然认为不应该接受不必要的线性空间开销。但是,对于
int
s列表,系数约为1

这个分析是正确的还是我遗漏了什么

背景:与我讨论这个问题的人试图说服我,java中的调用堆栈不会如此显著地增长,并指出我遗漏了一些明显的东西(不幸的是,他没有告诉我什么,对我来说,这真的一点都不明显)-因为我不知道我错过了什么,我渴望学习;)

相关:

对我来说,相关问题中缺少的主要问题是调用堆栈实际使用了多少空间

递归使用多少堆栈(从列表中删除节点)

这是一个很难回答的问题,如果不分析代码或不了解特定JVM的细节。这是因为该方法将许多细节留给了实现者

实施细节不属于 Java虚拟机的规范将不必要地限制 实施者的创造力。例如,运行时的内存布局 数据区域、使用的垃圾收集算法以及任何内部 Java虚拟机指令的优化(例如, 将其翻译成机器代码)由工程师自行决定 实施者

这些细节的一部分是堆栈和堆栈框架实现。由于你实际上是在询问递归删除所创建的堆栈与算法处理的列表之间的关系,所以我们必须考虑到堆栈帧可能甚至不像你所想的那样在堆栈上大(或者在你的问题中提出)。 因为Java虚拟机堆栈永远不会 除了推动和弹出帧之外,可以直接操纵帧 已分配堆

这意味着对于每个堆栈帧,可以只在堆栈上放置一个引用。如果是这样的话,那么对于您提供的示例来说,堆栈和它所处理的列表之间的关系就变得无关紧要了。让我们看看一些数字:

根据:

  • 一个
    整数
    是24个字节

    开销+实例变量(
    int
    )+填充
    =16+4+4=24字节

  • 嵌套在关联节点中的非静态递归定义的
    节点
    列表
    为40字节
    开销+引用+额外开销(引用
    列表
    类)
    =16+8+8+8=40字节

因此,我们可以看到列表中每个条目有64个字节。因此,如果有一个实现,其中帧是堆分配的,那么堆栈和正在处理的列表之间的关系将是
8/64=1/8字节

在堆栈上分配堆栈帧时,更难确定堆栈的大小。事实上,我们需要进一步的实施细节来确定它