【问题标题】:How to evaluate the performance of a binary tree implemented via a linked list or an array list?如何评估通过链表或数组列表实现的二叉树的性能?
【发布时间】:2015-04-06 06:24:39
【问题描述】:

这属于https://stackoverflow.com/help/on-topic的“软件算法”

这是来自一个面试问题http://www.glassdoor.com/Interview/Yelp-Software-Engineering-Intern-Interview-Questions-EI_IE43314.0,4_KO5,32_IP2.htm

特别是“通过数组或链表实现二叉树的性能”

如何通过数组或链表实现二叉树?

我被教导这样做的方法是拥有一个链接节点类型的结构,它有两个指针,左和右,即(来自https://courses.cs.washington.edu/courses/cse143/12wi/lectures/02-22/programs/IntTreeNode.java

public class IntTreeNode {
      public int data;            
      public IntTreeNode left;    
      public IntTreeNode right;   
      public IntTreeNode(int data) {
               this(data, null, null);
      } 

     public IntTreeNode(int data, IntTreeNode left, IntTreeNode right) {
            this.data = data;
            this.left = left;
            this.right = right;
      }
}

然后在实际的二叉树中

public class IntTree {
        IntTreeNode overallRoot;
        public IntTree() {
              overallRoot = null;
        }
         ....
  }

如果您只使用数组或链表(一个指针),您将如何处理?

但无论如何,这应该是一个快速的问题。即使您没有实现不应该执行的树,您将如何分析树的性能?性能是否取决于树的状态,就像它是 BST 一样?就像 BST 一样, find 将是 O(log n) 因为你每次都要砍掉一半的树。

您将如何根据这两种实现立即分析性能?

【问题讨论】:

    标签: java algorithm tree linked-list binary-tree


    【解决方案1】:

    我不确定我是否理解正确,但这是我的想法。 基本上,您可以将树中的节点存储为数组/列表的元素。

    对于数组,可以这样想:

    public class Node {
        public int data;
        public int left;
        public int right;
        ...
    }
    

    您的树将是 Nodes (Node[] tree) 的数组,因此根将是第一个元素 tree[0]。 每个元素都将其左右子元素称为数组中的索引。 例如,tree[ tree[0].left ] 将是根的左孩子。 left 的值-1 可能表明该节点没有左孩子; right 也是如此。

    例如,考虑以下树:

         5
      /     \
    2         8
     \       / \
      3     6   9
    

    假设您最初在数组中分配了 10 个元素。 由于树中的节点少于 10 个,因此其中一些将是 null。 这是它的样子: (我将每个Node 表示为(data,left,right) 元组)

    { (5,1,2) , (2,-1,4) , (8,5,3) , (9,-1,-1) , (3,-1,-1) , (6,-1,-1) , null , null , null , null }
    

    因此对于节点(8,5,3),你可以看出它的左孩子是第六个元素(节点(6,-1,-1)),它的右孩子是第四个元素(节点(9,-1,-1))。

    插入/删除函数的性能可能会因您的精确实现而异。 类似的想法也适用于链表(但请记住,它们没有随机访问权限:查找 i-th 元素需要逐个元素地遍历列表)。

    希望这会有所帮助。

    【讨论】:

    • 元组是python的意思吗?不过很好的实现。我喜欢这个主意。那么,由于链表没有随机访问,因此基于数组的实现的性能会更快吗?
    • 很抱歉给您带来了困惑。我的意思是数学意义上的:我的意思是我将节点表示为三个整数。
    • 是的,我认为在这种情况下,数组实现会更好。例如,插入可以对数进行。需要注意的是,一旦数组中的空间用完,您将不得不创建一个新的更大的数组,并将所有元素复制到其中。
    • 如果你使用了一个链表,我假设它是一个包含左右指针的节点列表,插入不也是对数吗?我的意思是您会将您尝试插入的数据与节点的数据进行比较,然后如果较小则向左,如果较大则向右。这样,您每次也可以消除一半的树。
    • 确实,如果你包含指向左右孩子的指针,那么你的运行时间会更好,但它不会是一个链表:)你会回到“正常”的实现一棵树。
    【解决方案2】:

    在分析这样的算法时,您想看看它是什么类型的二叉树(平衡与不平衡),以及与空间/时间复杂度有关的三个因素:

    1. 插入
    2. 删除
    3. 搜索

    比较二叉树的链表和数组实现,我们看到如下:

    1. 链接列表的插入和删除比在数组中完成的成本要低得多(想想为完成这两个操作您必须进行的数组元素移位。
    2. 链接列表提供灵活的大小,而数组则没有;当数据不适合初始数组大小时,您将不得不处理数组扩展。
    3. 数组提供随机访问,而链表不提供;例如在处理完整或完整二叉树的数组实现时,我们可以轻松计算树中任何节点的索引。

    话虽如此,对于Binary Search Trees 的具体实现,链表是更好的实现,因为在二叉搜索树中,访问遵循二叉搜索树的规则(根的值大于左孩子,小于右孩子)。因此,对于插入/删除和搜索,平均复杂度应该是O(log n),前提是树是balanced。如果二叉搜索树不平衡,那么所有操作的复杂度都会变为O(n) - 这是最坏的情况。

    【讨论】:

    • 对于二叉搜索树,使用 jadhachem 提出的数组实现,搜索不会也有 O(log n) 的平均复杂度吗?如果您通过他的示例,它将带您到左节点或右节点,这意味着每次都会消除一半的树
    • 是的,当然,搜索平均会产生O(log n)。但我也在考虑插入和删除——在数组实现中,这些都是昂贵的,因为你必须扩展或移动数据。
    猜你喜欢
    • 2015-07-27
    • 2016-08-03
    • 2020-08-22
    • 2011-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-10
    • 2012-12-28
    相关资源
    最近更新 更多