对于新的计算机科学任务,我们将使用inorder二叉树实现列表/数组。我想要一个建议而不是一个解决方案。
这个想法是拥有一个二进制树,它的节点可以通过索引访问,例如
t = ListTree()
t.insert(2,0) # 1st argument is the value, 2nd the index to insert at
t.get(0) # returns 2
存储值的Node类不可修改,但有一个属性size
,其中包含下面的子项总数,以及left
,right
和{{1指向子节点并相应地存储值。
我目前的主要问题是跟踪索引 - 因为我们不允许在节点本身存储节点的索引,所以我必须依靠遍历来跟踪它。因为我总是在遍历时从左侧节点开始,我还没有想过以递归方式找出我们当前所处的索引的方法。
欢迎任何建议。
谢谢!
答案 0 :(得分:1)
您真的不希望将它存储在节点本身上,因为必须在索引小于插入索引的所有节点的插入上更新索引。我认为真正的问题是如何进行有序遍历。尝试使用递归函数返回其左侧的节点数。
答案 1 :(得分:1)
我认为您不想存储索引,而只是存储每个子树的大小。对于insance,如果你想查找列表中的第10个元素,并且左右子树各有7个元素,你会知道根是8个元素(因为它是按顺序的二进制),并且第一个元素右子树的第9个。有了这些知识,你就会进入正确的子树,寻找第二个元素。
HTH
答案 2 :(得分:0)
嗯,二叉树中的节点不能有值和索引。它们可以有多个数据,但树只能在一个数据上键入/构建。
也许你的作业希望你使用索引值作为树的键,并将值附加到节点,以便快速检索给定索引的值。
答案 3 :(得分:0)
树必须平衡吗?算法是否需要高效?
如果没有,那么最简单的方法就是创建一个所有左子节点都为空的树,即一个转换为链表的树。
要插入,递归查看转到右边的子节点,然后在返回的路上更新节点的大小。像(伪代码)
的东西function insert(node, value, index, depth)
if depth < index
create the rightchild if necessary
insert( rightchild, value, index, depth + 1)
if depth == size
node.value = value
node.size = rightchild.size + 1
完成此操作后,您可以将其修改为更加平衡。当增加列表的长度时,根据当前具有最少的节点将节点添加到左子节点或右子节点,并在离开递归的路径上更新大小。
要概括为更高效,您需要根据其二进制表示法处理索引。
例如,空列表有一个节点,没有值为null且大小为0的子节点。
假设您要在索引1034处插入“hello”。然后您希望最终得到一个树,其根有两个子节点,大小为1024和10.左子节点没有实际子节点,但右节点有一个大小为2的右子级。(隐含大小为8的左侧。)该节点依次有一个大小为0的右子,值为“hello”。 (此列表具有从1开始的索引,但基于0的索引类似。)
因此,您需要递归地将索引分解为其二进制部分,并根据需要添加节点。搜索列表时,在遍历具有空子节点的节点时需要注意
答案 4 :(得分:0)
一个非常简单的解决方案是使用GetFirst()来获取树的第一个节点(这只是找到树的最左边的节点)。如果索引N为0,则返回第一个节点。否则,调用GetNodeNext()N次以获取适当的节点。这不是超级高效的,因为通过索引访问节点需要O(N Lg N)时间。
Node *Tree::GetFirstNode()
{
Node *pN,*child;
pN=GetRootNode();
while(NOTNIL(child=GetNodeLeft(pN)))
{
pN=child;
}
return(pN);
}
Node *Tree::GetNodeNext(Node *pNode)
{
Node *temp;
temp=GetNodeRight(pNode);
if(NOTNIL(temp))
{
pNode=temp;
temp=GetNodeLeft(pNode);
while(NOTNIL(temp))
{
pNode=temp;
temp=GetNodeLeft(pNode);
}
return(pNode);
}
else
{
temp=GetNodeParent(pNode);
while( (NOTNIL(temp)) && (GetNodeRight(temp)==pNode) )
{
pNode=temp;
temp=GetNodeParent(pNode);
}
return(temp);
}
}