我正在准备考试,我遇到的一个问题是:实现树,LinkedList或Array的最佳方法是什么。
最有可能: - 数组使用1个地址 - LinkedList使用两个地址。
使用LinkedList,我们可以插入我们需要的值(我们完美地管理内存),但大多数人喜欢使用O(N)来访问这个元素,而在Array中它是O(1)。
我该如何回答这个问题?或者我应该说这是主观的。
答案 0 :(得分:1)
对于Binary Search Tree
,答案绝对是一个数组(至少希望是一个可扩展的数组,如vector<>
所以你不限于固定大小)。我将对常见操作进行分析,假设树是平衡的。
<强>查询强>
在BST中,节点需要指向左右子节点,并且父节点指针也很常见。在数组实现中,“指针”可以简单地是数组中的整数索引(这意味着数组将存储Node
个对象)。因此查找节点的父节点和子节点是不变的,因为索引到数组中是恒定的。 O(1)
。链表实现可能还需要存储对其祖先/子项所在位置的引用,因此需要O(N)
遍历列表才能获得所需的引用。
搜索强>
从root
,array[0]
开始,搜索将是O(log N)
操作。搜索只会调用/获取每个节点的子节点的信息,这是O(1)工作量,大约是O(log N)次,因此O(log N)
用于在数组中搜索。
链接列表需要O(N)传递数据才能获得所需的左/右指针,也可以在O(log N)步骤中完成,从而在链接中生成O(n log n)
搜索 - 列出。
插入强>
阵列类似于搜索,除了需要额外的O(1
)指针分配的常量时间。所以O(log N)
插入。
链接列表也类似于搜索例程,除了调整指针需要额外O(n)
时间,因此O(n log n)
删除强>
阵列也类似于搜索,但您可以删除多个O(log n)
因素,因为您必须遍历树,但它仍然是{ {1}}
链接列表也会有O(log n).
加上O(n log n)
以进行遍历。因此,O(n log n)
也适用于链接列表。
<强>结论强>
现在答案应该是相当明显的:)加上数组你会得到比链表更好的O(n log n)
的好处。另外,二元搜索树的一些衍生物,例如caching
(通常是最小堆/最大堆)通常表示为数组,
我希望这会有所帮助:)
答案 1 :(得分:-2)
array
是我想称之为基本类型的东西。也就是说,它基本上是在系统的原始内存上运行的。你可以用一个类包装一个基本的array
来添加越界保护之类的东西,但是你仍然需要原始的支持来访问/索引到任何东西的内存块中组装。
对于(单个)链表,在python中它看起来像这样:
class Entry(object):
def __init__(self, value, child = None)
self.child = child
self.value = value
class LinkedList(object):
def __init__(self, root_entry = None):
self.root = root_entry
self.tail = self.root
self.size = 1 if root_entry else 0
def add_entry(value):
new_entry = Entry(value)
if size:
self.tail.child = new_entry
else:
self.root = new_entry
self.tail = new_entry
self.size +=1
...
依此类推,您可以看到,对于大多数操作,您只需遍历根的子项,直到达到您想要的位置。插入项目只是意味着用新条目替换该条目的子项并将新条目的子项设置为旧子项(并且递增大小)
通常,对于单链接列表,如果已经有旧条目(对于大多数迭代器将使用)或在尾/根处,则元素插入是 O(1)。当你需要遍历列表时,按索引查找元素是 O(n),并且迭代器只能移动down
列表(即index = 0
到{{1} }}
基本上所有这些信息都可以通过阅读相关的维基百科条目来研究。这些都是非常基本的类型,已经存在了很长时间。