我有一个数组,其中包含8个元素的空间。我想用以下数组指示的索引用数字8,7,...,1填充这个数组:
7 4 4 2 1 2 0 0
你必须注意到某些指数正在重复。这是因为这些数字表示剩余数组的索引。
我将引导您完成数组填充的步骤,以便您了解:
初始数组(索引)
_ _ _ _ _ _ _ _
0 1 2 3 4 5 6 7
第1步
_ _ _ _ _ _ _ 8
0 1 2 3 4 5 6 -
第2步
_ _ _ _ 7 _ _ 8
0 1 2 3 - 4 5 -
注意当我填写“7”时索引如何更新,这样我也可以在索引4处填写“6”,因为索引4是新位置。
第3步
_ _ _ _ 7 6 _ 8
0 1 2 3 - - 4 -
第4步
_ _ 5 _ 7 6 _ 8
0 1 - 2 - - 3 -
第5步
_ 4 5 _ 7 6 _ 8
0 - - 1 - - 2 -
第6步
_ 4 5 _ 7 6 3 8
0 - - 1 - - - -
第7步
2 4 5 _ 7 6 3 8
- - - 0 - - - -
和“1”可以在最后一个地方填写。
如果我必须填写索引i,我已经解决了直接扫描数组中第i个空位的问题。它是O(n ^ 2)。我需要更好。
问题:是否有可以优化上述算法的数据结构?或者算法本身可以改进吗?
注意:我尝试过使用BIT,但失败了。
答案 0 :(得分:2)
将所有初始索引存储在二叉搜索树中。还与每个节点一起存储总孩子数(所有更深层次)。
只要在数组中插入一个元素,就从O(log n)中的树中删除其索引。同时更新孩子的数量。
对于“新索引”中索引i
的数组中的下一个插入,您需要在搜索树的排序中找到i
元素,它将为您提供“原始”中的位置指数。由于可以查询每个节点的子节点数,因此也可以在O(log n)中完成。
因此,完整的平均和最差情况复杂度为O(n log n)。
答案 1 :(得分:1)
如果您接受使用额外的O(n)内存,您可以这样做:
创建一个辅助数组,在索引i处存储原始数据数组中第i个空闲位置的索引。因此,如果您的原始数组的索引为0 - 7且索引为1,3,5的位置是空闲的,那么您的辅助数组将如下所示:[1,3,5,-1,-1,-1,-1, - 1],其中-1表示原始数组中没有这样的可用空间量。
为了在数据数组中的第i个自由位置插入一个元素,你可以这样做:
int j = helperArray[i]; if (j > -1){ dataArray[j] = itemYouWantToInsert; while (i < helperArray.size() - 1){ helperArray[i] = helperArray[i+1]; i++; } helperArray[i] = -1; } else cout<<"There are less free places in the dataArray.";
插入时间为O(k),其中k =(n-i)。因此,插入的极限时间是O(n),但乐观的是O(1)。 isFree()只是一个示例方法,因为我不知道如何识别dataArray中的“空白空间”。