Data structures 为什么线程树的顺序遍历是O(N)?

Data structures 为什么线程树的顺序遍历是O(N)?,data-structures,binary-tree,Data Structures,Binary Tree,我似乎无法理解线程二叉树的顺序遍历是如何为O(N)。。 因为当您想将父对象添加到遍历路径时,必须降低链接以找到最左边的子对象,然后按线程返回。那不是O(N^2)吗 谢谢 没有找到父对象的循环。否则,将两次穿过两个节点之间的每个圆弧。这就是2*弧的数目=2*(节点的数目-1),也就是O(N) 树的遍历(线程化或非线程化)是O(N),因为从其父节点开始访问任何节点都是O(1)。对节点的访问由三个固定操作组成:从父节点下降到节点,访问本身(在节点上花费时间),然后返回到父节点。O(1*N)是O(N)

我似乎无法理解线程二叉树的顺序遍历是如何为O(N)。。 因为当您想将父对象添加到遍历路径时,必须降低链接以找到最左边的子对象,然后按线程返回。那不是O(N^2)吗


谢谢

没有找到父对象的循环。否则,将两次穿过两个节点之间的每个圆弧。这就是2*弧的数目=2*(节点的数目-1),也就是O(N)

树的遍历(线程化或非线程化)是O(N),因为从其父节点开始访问任何节点都是O(1)。对节点的访问由三个固定操作组成:从父节点下降到节点,访问本身(在节点上花费时间),然后返回到父节点。O(1*N)是O(N)

查看它的最终方式是,树是一个图,遍历只穿过图中的每条边两次。边的数量与节点的数量成正比,因为没有循环或冗余边(每个节点可以通过一条唯一的路径到达)。具有N个节点的树正好有N-1条边:除了树的根节点外,每个节点都有一条从其父节点指向它的边

有时,访问节点似乎需要多次下降。例如,在访问子树中最右边的节点后,我们必须先弹出多个级别,然后才能向右进入下一个子树。但是我们并不是一路下来只是为了访问那个节点。每一级下降都可以被认为是访问正下方节点所必需的,以及相反的上升 费用与此一并计算。通过访问节点V,我们还可以访问它下面的所有节点,但所有这些节点都受益于并共享从V的父节点到V的边遍历,然后再次备份

这与摊销分析有关,摊销分析适用于以下情况:根据对问题结构的一些一般观察,我们可以全面了解总体成本,但在单个操作的详细层面上,成本分布不均,令人困惑

摊销分析帮助我们理解,例如,通过指数增长调整自身大小的哈希表中的N个插入是O(N)。大多数插入操作都很快,但我们会不时地扩展表并处理其内容。这类似于在树遍历过程中,我们必须执行多次连续提升才能爬出深子树

关于哈希表的总体观察结果是,插入到表中的每个项在三次调整大小操作中平均会移动到一个较大的表中大约三次,因此每次插入都可以被视为三次重新插入的“预付费”,这是一个固定成本。当然,“较旧”的项目将移动更多次,但这被移动次数较少的“较新”项目所抵消,从而稀释了成本。上面已经提到了对树的全局观察:它有N-1条边,每个边在遍历过程中正好被遍历两次,因此每个节点的访问为其各自边的双重遍历“付费”。因为这很容易看到,所以我们实际上不必正式地将摊销分析应用于树遍历

现在假设我们对每个节点执行单独的搜索(该树是一个平衡的搜索树)。那么遍历仍然不是O(N*N),而是O(N logn)。假设我们有一个有序的搜索树,它包含连续的整数。如果我们在整数上递增,并对每个值执行单独的搜索,那么每个搜索都是O(logn),我们最终执行其中的N个。在这种情况下,边遍历不再共享,因此摊销不适用。为了到达我们正在搜索的某个给定节点(在深度D处找到),我们必须两次穿过D边,为了该节点和该节点。循环中另一个整数的下一次搜索将完全独立于前一个整数

它还可以帮助您思考一个链表,它可以被视为一个非常不平衡的树。访问长度为N的链表中的所有项目并返回到head节点显然是O(N)。单独搜索每个项目是O(N*N),但在遍历中,我们不是单独搜索每个节点,而是使用每个前置节点作为寻找下一个节点的跳板