ryvova/linkedlist

此包最新版本(dev-main)没有提供许可证信息。

SortedLinkedListPackage

dev-main 2023-11-03 13:42 UTC

This package is not auto-updated.

Last update: 2024-09-24 15:37:37 UTC


README

你真的使用链表吗?我在1986年上编程课时第一次遇到它们,从那时起我就不再需要它们了。那时,我就认为这非常愚蠢,因为

  • 访问链表中间的值非常慢(必须逐步遍历),与数组不同。
  • 此外,它还需要存储到下一个(最终上一个)元素的链接,因此内存消耗较大。
  • 低指令级并行性 - 在遍历链表时,CPU没有太多工作要做,因为它不能在加载完当前节点之前开始处理下一个节点。

我使用双向链表。

  • 优点是
    • 这使得删除链表最后一个元素更容易更快(我不必遍历整个链表)。
    • 例如,如果我知道排序列表中的数据具有正态分布,我可以调整添加/删除方法,以便当最小值是1,最大值是10000,并且我想插入/删除7000时,我将从后向前遍历。
  • 缺点是:内存需求更高(每个节点必须包含一个指向下一个(最终上一个)节点的链接)。

要决定是否选择单向/双向链表以及是否按升序/降序排序,就需要了解更多关于

  • 它将用于什么目的,
  • 将要填充的数据将如何看起来,例如,如果数据将按顺序填充,则我们可以修改添加到开始/结束的方法,
  • 时间或内存消耗等重要性的问题。

当合并两个列表时,我使用了它们都是排序的事实。当然,我可以在要添加的列表的每个元素上调用add()方法,这将从头遍历第一个列表并将它放到正确的位置。由于它们都是排序的,我只需要记住我在要添加的列表中添加元素的指针,并从那里继续。

任务没有指定字符串值列表应该如何排序。我使用按系统设置排序。由于int值使用 </=/> 比较,而字符串值使用比较,我修改了compare函数,使其也可以比较int值,这样我就不必每次都找出值的类型。

值得考虑的是,节点不仅包含值,还包含该值出现的次数。这将简化添加和删除节点 - 只需要增加/减少次数,不需要解决指针(除非删除了具有给定值的所有节点)。

在实际应用中,如果库是更大项目的一部分,建议考虑是否将比较器(collator)作为单例实现,因为其设置始终与系统设置相同。

我使用__toString()方法来清楚地显示列表信息,以便进行测试(使用指针的var_dump对象非常令人困惑)。为了确保代码的功能性,我为它编写了单元测试。

值得考虑是否使列表不可变 - 在创建后设置一个标志,并在后续处理过程中检查是否发生了变化。

既然你说你使用自己的PHPStan规则,我也运行了代码通过PHPStan的第9级。

由于极端的内存需求,我从不使用递归。为了确保代码能正常工作,我还为这些方法编写了PHPUnit测试。它应该是一个库,所以我将代码注册为packagist.org上的一个包,包名为ryvova/linkedlist。