动态列表表示可以删除或更改列表中的元素。
问题类似于在Windows中处理重复文件名的方式。 例如:
file
file (1)
file (2)
file (3)
如果删除file (2)
,然后添加另一个名为file
的文件,file (2)
将成为生成的文件名。 (不要以为在Windows中会发生这种情况)
有没有一种优雅的方法可以在不翻阅每个插页的整个列表的情况下执行此操作?
答案 0 :(得分:1)
您可以使用队列存储已释放的整数和计数器,以记住最后一个:
Queue s;
int lastUsedInt; //Initialize to 0
void delete( int fileNumber ){
s.push(fileNumber);
}
int getIntForNewFile(){
if( s.empty() ){ //If our queue is empty then there are no unused spaces
return lastUsedInt++; //Return lastUsedInt and increment it by 1
}
else{
int i = s.top(); //Get current top of the queue
s.pop(); //Delete current top of the queue
return i; //Return the retrieved number
}
}
这里有一些Cpp伪代码:)
这将按照删除的顺序“填充”空白点。 因此,如果你有1到10的文件,那么删除5和2:5将首先填充,然后是2。
如果您希望按顺序填充它们,则可以使用已排序的容器。 在C ++中,它将是priority_queue。
答案 1 :(得分:1)
使用最小堆来存储被删除的项目。如果堆为空,则没有空闲项。否则,拿第一个。
http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=789
提供了一个简单的最小堆实现使用它:
BinaryHeap<int> MyHeap = new BinaryHeap<int>();
从列表中删除项目时,请将该数字添加到堆中:
MyHeap.Insert(number);
获取下一个号码:
if (MyHeap.Count > 0)
nextNumber = MyHeap.RemoveRoot();
else
nextNumber = List.Count;
这可以保证您始终获得最小的可用号码。
答案 2 :(得分:0)
我会使用自平衡二叉树作为集合表示(例如,C ++标准std::set<int>
容器)。
该集合将包含所有“未分配”的数字,最多包括一个大于最大分配数量的数字。
将该集初始化为包含0
(或1
,无论您的偏好是什么)。
要分配新号码,请抓取集合中的最小元素并将其删除。拨打该号码n
。如果该集现在为空,请将n+1
放入集合中。
要取消分配号码,请将其添加到集合中。然后执行以下清理算法:
步骤1:如果集合中有一个元素,请停止。
步骤2:如果集合中的最大元素减去第二大元素大于1,则停止。
步骤3:删除最大的元素。
第4步:转到第2步。
使用此数据结构和算法,k
分配/解除分配操作的任何序列都需要O(k log k)时间。 (即使“清理”操作本身都是O(k log k)时间,您只能在插入元素后删除它,因此总时间不超过O(k log k)。)
换句话说,每个分配/解除分配都需要对数摊销时间。