ryvova / linkedlist
SortedLinkedListPackage
Requires
- php: >=8.2
- ext-intl: *
Requires (Dev)
- phpstan/phpstan: ^1.11.0
- phpunit/phpunit: ^9
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。