【问题标题】:Link list in C and javaC和Java中的链接列表
【发布时间】:2012-01-26 10:47:27
【问题描述】:

1) 我可以在 C 中不使用指针(并且不使用结构)创建链接列表吗?

2) Java 不使用指针,那么链表是如何在 Java 中实现的?

【问题讨论】:

  • 你查过java.util.LinkedList的来源吗?

标签: java c linked-list


【解决方案1】:
  1. 我不明白这怎么可能。
  2. Java 确实有指针。它们在 Java 中只是称为引用,但它们基本上是同一回事。每个指向对象的变量都是对象的引用或指针。如果变量为 null,并且您尝试取消引用它,则会收到 NullPointerException。

【讨论】:

  • 请不要忘记,使用指针只是 Java 中引用的一种可能实现。我认为大多数人不会在 Hotspot 中将 CompressedOops 称为指针。 NullPointerException 是一个不幸的命名选择,Bloch(我认为)说他应该把它命名为 NullReferenceException.. 有一件事 C# 固定在那里;)
  • “我认为大多数人不会将 Hotspot 中的 CompressedOops 称为指针”——它是地址的一种相当直接的表示,不过,我认为说实现仍然没有什么牵强“基本上是一样的东西”作为指针。问题是“Java 不使用指针,那么如何......”。准确地说,“Java 使用了一种不同形式的间接,称为引用”。从理论上讲,Java 实现可以在引用中使用一些位来编码类型和/或值,在这种情况下,实现不像指针。不知道有没有。
  • @Steve 我同意那里不是黑白的,我将 CompressedOops 更多地描述为堆中的索引,但它仍然映射到相当简单的对象的地址。关于您的最后一点:我认为我记得 Azul 的 VM 所做的事情与实际情况非常相似 - 他们的目标客户并不关心 32gb 堆,因此他们可以使用较低的位来获得对他们更有用的东西.
  • @Voo:我提到它是因为我曾经花了一周时间调试一个大整数库实现(在汇编程序中,而不是 Java 中),它直接将“小”值(最多约 2^30)存储在手柄,带有标志。对于“大”值,句柄包含指针。在 Java 的情况下,同样的技巧可以让你在没有分配的情况下进行自动装箱,假设你可以弄清楚如何使用带有这样一个“对象”的监视器。
【解决方案2】:

如果您可以忍受一些愚蠢的限制,例如列表具有固定的最大长度并预先分配所有潜在元素,您可以使用索引来替换指针。

这可以使元素本身更小,因为如果您知道元素数量的良好边界(您必须这样做,以便预分配工作),您可以调整索引的大小,但您可以不要用指针来做到这一点。对于最多包含 1,000 个元素的列表,您可能会使用 uint16_t 索引,它是 64 位架构上指针大小的 1/4。

另一方面,索引涉及地址计算,仅在跟随直接指针时不需要,因此可能会有性能成本。

【讨论】:

  • “一些愚蠢的限制” - 愚蠢的方式与池分配器愚蠢的方式完全相同;-)
  • 我不明白为什么以后无法扩展阵列? (或者我们在这里把引用算作指针吗?)对我来说似乎很容易。实际上,我很确定 Java 中的并发 hashmap 在这些方面做了一些事情。
  • “可能会有性能成本” - 取决于目标架构提供的寻址模式,等等。
  • @SteveJessop:我说可能! :)
【解决方案3】:

至于1,我觉得不可能。

对于 2,你应该看看这个优秀的资源http://cslibrary.stanford.edu/

【讨论】:

  • 有可能。使用数组,并使用指针而不是索引。不可能无限增长的链表。
  • @k4rtik:Oli 是倒着写的,他指的是索引而不是指针。请参阅 unwind 的回答(以及我的回答)。
  • @k4rtik, cha0site:是的,我是倒着写的!
【解决方案4】:

对于 java - 它是 LinkedList 正在使用的引用 http://docs.oracle.com/javase/6/docs/api/java/util/LinkedList.html

【讨论】:

    【解决方案5】:

    1 - 不。链表的关键在于它是动态数据结构。这意味着您可以在运行时更改其大小(而不是在编译程序时必须知道它的大小)。这只能通过指针来完成,因为当您分配一些新内存时,您需要知道如何找到它。

    你可以不使用结构体,但它们是最合适的结构体。

    2 - Java 有对对象的引用。它们基本上和指针一样,只是你不能用它们做算术,而且它们是类型安全的。

    【讨论】:

      【解决方案6】:

      1 - 绝对。使用一组并行数组(每个属性一个)并使用数组索引作为指针。一代又一代的 FORTRAN 程序员(以及像我这样向那些 FORTRAN 程序员学习的大学生)将这种方法用于各种数据结构 - 列表、树、堆栈、队列等。它很丑陋,它是一个巨大的痛苦,它有一些真正的限制,但这当然是可能的。指针类型和聚合类型使数据结构的实现更容易,但它们几乎不是必需的。

      2 - Java 到处都使用指针;它只是不向程序员公开指针类型的操作。任何时候你使用引用类型(基本上,任何需要你使用new 来创建实例的东西)你都在使用指针。

      【讨论】:

        【解决方案7】:

        1) 由于所有内存分配都涉及到指针,并且您需要为列表中的新条目分配额外的内存,因此无法实现随元素数量增长和收缩的传统链表。

        2) Java 有references,和指针一样,只是不能对它们进行指针运算(如int* p = q + 1;)。

        【讨论】:

          【解决方案8】:
          1. C 中没有指针或structs 的链表?也许。你可以有一组数组,一个包含数据,另一个包含下一个节点的索引。当然,数组使用指针。
          2. Java 使用几乎但不完全是指针的引用。

          【讨论】:

            【解决方案9】:

            1) 如果您绝对必须这样做,建议“愚蠢的限制”的答案可能是您最好的选择,尽管其中一些限制完全破坏了使用链表的意义。例如,容易调整大小变得不可能调整大小。为什么你不想使用指针?

            2) 仅仅因为您没有看到它们并不意味着它们不存在。更准确的说法是“我不必在 Java 中处理指针或它们的算术运算”。如果您需要向自己证明指针在幕后,请使用 int 和 Integer 执行以下过程

            0) (我们是优秀的代码负责人)声明并将变量初始化为 3 1)打印它 2)将它传递给另一个函数 3)在该函数中增加它 4)再次打印 5) 返回 6) 从调用函数打印。

            对于 int 类型,您将打印 3 4 3,对于 Integer,您将打印 3、4、4。这是因为对象是通过引用传递的,这意味着您仍在处理底层的指针。参考是不同的,因为(在大多数情况下)您不必处理它们。

            【讨论】:

              猜你喜欢
              • 2020-07-17
              • 2019-07-03
              • 2019-05-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-05-08
              • 1970-01-01
              相关资源
              最近更新 更多