我有以下问题: 我有一行数字,我必须阅读。该行的第一个数字是我必须在序列的其余部分执行的操作量。 我将不得不做两种类型的操作:
如果当前数字的值是偶数,我们执行“删除”,如果值为奇数,则执行“插入”。 在操作量之后,我们必须打印整个序列,从我们结束操作的数字开始。
正常工作的例子: 输入:3 1 2 3 输出:0 0 3 1
3是第一个数字,它变为OperCount值。
序列:1 2 3,第一个元素:1
1是奇数,所以我们插入0(currNum的值-1)
我们向前推进1(currNum的值)
输出顺序:1 0 2 3,当前位置:0
0甚至是我们删除下一个值(2)
向前移动被移除的元素的值(2):
输出顺序:1 0 3,当前位置:1
1是偶数,所以我们再一次插入值为0的新元素
按当前元素的值(1)移动到创建的0。
输出顺序:1 0 0 3,当前位置:第一个0
现在这是交易,我们已达到最终状态,现在我们必须打印整个序列,但从当前位置开始。 最终产出: 0 0 3 1
我有工作版本,但它使用链表,因此,它没有通过所有测试。链接列表遍历太长,这就是为什么我需要使用二叉树,但我有点不知道如何从它开始。我将不胜感激任何帮助。
答案 0 :(得分:1)
首先重新定义操作,将大部分(但不是全部)工作放入容器对象中:我们希望容器对象支持4个操作:
1)从[first,limit)
对输入随机访问迭代器构造
2)insert(K)在位置K处找到值X,在其后面插入一个X-1并返回X
3)删除(K)在位置K找到值X,删除它并返回X
4)size()报告内容的大小
容器外的工作只会跟踪K的增量变化:
K += insert(K); K %= size();
或
K += remove(K); K %= size();
在阅读size()
容器数据只是指向节点的root
。
struct node {
unsigned weight;
unsigned value;
node* child[2];
unsigned cweight(unsigned s)
{ return child[s] ? child[s]->weight : 0; }
};
容器成员函数insert
和remove
将是递归静态insert
和remove
函数的包装器,每个函数除K外还带有node*&
。
递归insert
或remove
的每一个必须做的第一件事是:
if (K<cweight(0))
递归传递(child[0], K)
;
else if ((K-=cweight(0))>0)
递归传递(child[1], K-1)
;
否则做基本操作(读取结果,创建或销毁节点)
在执行此操作之后,您可以在递归调用堆栈的每个级别上修复权重(从您执行插入工作的位置开始,或者高于删除时的级别)。
在当前级别递增或递减权重后,您可能需要重新平衡,记住递归更改的哪一侧。插入更简单:如果child[s]->weight*4 >= This->weight*3
需要重新平衡。重新平衡是两个基本树旋转之一,您可以根据child[s]->cweight(s)<child[s]->cweight(1-s)
选择哪一个。重新平衡删除是相同的想法,但不同的细节。
这个系统比红黑或AVL树做了更多最坏情况的重新平衡。但仍然完全是logN。也许对于权重半平衡树有更好的算法。但我不能&#39;吨发现,有一些谷歌搜索,甚至也不是真实姓名,也没有其他细节什么,我只是随意称为&#34;重半平衡树&#34;
将读取操作奇怪地混合到插入和移除操作中的速度提高近2倍意味着您将需要另一个在读取时不会混合的插入的递归版本,并用于部分您读取的点下方的路径(因此它会执行相同的递归权重更改和重新平衡,但具有不同的输入和输出)。
给定随机访问输入迭代器,构造是一个更简单的递归函数。从迭代器范围中获取中间项,并使用整个范围的总权重创建它的节点,然后递归地将中间项之前和之后的子范围传递给相同的递归函数以创建子子树。
我还没有测试过这些,但我认为以下是remove
所需的所有代码以及插入和删除所需的重新平衡。取node*&
static
的{{1}}成员函数tree
和未node*&
的函数不是静态的。
unsigned tree::remove(unsigned K)
{
node* removed = remove(root, K);
unsigned result = removed->value;
delete removed;
return result;
}
// static
node* tree::remove( node*& There, unsigned K) // Find, unlink and return the K'th node
{
node* result;
node* This = There;
unsigned s=0; // Guess at child NOT removed from
This->weight -= 1;
if ( K < This->cweight(0) )
{
s = 1;
result = remove( This->child[0], K );
}
else
{
K -= This->cweight(0);
if ( K > 0 )
{
result = remove( This->child[1], K-1 );
}
else if ( ! This->child[1] )
{
// remove This replacing it with child[0]
There = This->child[0];
return This; // Nothing here/below needs a re-balance check
}
else
{
// remove This replacing it with the leftmost descendent of child[1]
result = This;
There = This = remove( This->child[1], 0 );
This->child[0] = Result->child[0];
This->child[1] = Result->child[1];
This->weight = Result->weight;
}
}
rebalance( There, s );
return result;
}
// static
void tree::rebalance( node*& There, unsigned s)
{
node* This = There;
node* c = This->child[s];
if ( c && c->weight*4 >= This->weight*3 )
{
node* b = c->child[s];
node* d = c->child[1-s];
unsigned bweight = b ? b->weight : 0;
if ( d && bweight < d->weight )
{
// inner rotate: d becomes top of subtree
This->child[s] = d->child[1-s];
c->child[1-s] = d->child[s];
There = d;
d->child[s] = c;
d->child[1-s] = This;
d->weight = This->weight;
c->weight = bweight + c->cweight(1-s) + 1;
This->weight -= c->weight + 1;
}
else
{
// outer rotate: c becomes top of subtree
There = c;
c->child[1-s] = This;
c->weight = This->weight;
This->child[s] = d;
This->weight -= bweight+1;
}
}
}
答案 1 :(得分:0)
您可以使用实现为二叉树的 std :: set 。它的构造函数允许从迭代器构造,因此你不应该有问题将列表转换为集合。