Algorithm 嵌套循环复杂性
我有几个大小不同的列表,列表的每个索引都包含一个键和一个对象:list1.add('key',obj) 列表都已排序 我的目标是遍历列表,并使用键将列表2、3、4或n中的一个或多个项目与主列表中的一个项目进行匹配 目前,我做了如下工作:Algorithm 嵌套循环复杂性,algorithm,list,loops,time-complexity,Algorithm,List,Loops,Time Complexity,我有几个大小不同的列表,列表的每个索引都包含一个键和一个对象:list1.add('key',obj) 列表都已排序 我的目标是遍历列表,并使用键将列表2、3、4或n中的一个或多个项目与主列表中的一个项目进行匹配 目前,我做了如下工作: for i to list1 size for j to list2 size if list1[i] = list2[j] do stuff 当我循环时,我正在使用布尔值快速退出,使用if current!=上一次检查时,我正在从获
for i to list1 size
for j to list2 size
if list1[i] = list2[j]
do stuff
当我循环时,我正在使用布尔值快速退出,使用if current!=上一次检查时,我正在从获取对象的列表中删除该对象
它的工作很好,但我现在有另一个列表,我需要匹配和可能的另一个n名单之后。名单大小不一
我可以看到的两个选项是,在内部列表发生变化的地方,重复上述代码段数次——我不喜欢这种方法
另一个选项是扩展上述内容,完成一个内部循环后,移动到下一个:
for i to list1 size
for j to list2 size
if list1[i] = list2[j]
do stuff
for k to list2 size
if list1[i] = list2[k]
do stuff
我认为我认为第二种方法更有效是正确的,但是我不确定。还有,还有更好的办法吗
感谢您的建议/帮助。如果列表都已排序,那么您只需在每个列表中迭代一次;在主列表的每次迭代中,迭代次列表(从先前保存的索引开始,初始化为0),直到找到值大于主列表当前值的索引,保存此索引,然后继续下一次次次列表
Array<Integer> indices = new Array(n-1); // indices for every list except list1
for(int i = 0; i < indices.size; i++) {
indices[i] = 0;
}
for(int i = 0; i < list1.size; i++) {
Value curVal = list1[i];
while(indices[0] < list2.size && list2[indices[0]] <= curVal) {
if(list2[indices[0]] == curVal) {
// do stuff on list2[indices[0]]
}
indices[0]++;
}
while(indices[1] < list3.size && list3[indices[1]] < curVal) {
if(list3[indices[1]] == curVal) {
// do stuff on list3[indices[1]]
}
indices[1]++;
}
// etc
}
这是时间复杂度O(n),其中n是所有列表长度的总和
编辑:如果很难通过
比较键,则它们都具有相同的时间复杂度。第一个选项是O(i*j)+O(i*k)
,第二个选项是O(i*(j+k))
@Barmar:谢谢。那么复杂性是n^2吗?我认为在某些情况下,它可能会不断改进,但复杂性分析不是我的强项:)这个问题似乎离题了,因为cs.stackexchange.com会是解决此类问题的更好地方。@Barmar:谢谢,我没有意识到它会被认为离题。我现在就移动它,除非你想根据评论发布答案嗨,我只是想实现你的解决方案。不幸的是,我没有访问迭代器的权限;德尔福旧版本的乐趣。在何处执行“&&list2[index[0]]@SteveGreen键的顺序如何?根据您的示例,它看起来可能是“如果key1的字母前缀小于key2的字母前缀,则key1list2[索引[0]]@SteveGreen如果编写isLessThan
方法不可行,那么如果您可以访问集合
数据结构(这可以实现为带有空值的映射
或字典
),那么您可以将所有List1键添加到集合中,然后遍历所有其他列表,测试集合成员资格list2[index[0]]@SteveGreen提供了一个很好的哈希函数的Delphi实现。分配一个名为set
的数组,该数组大于List1.size,通常大于25%到100%,具体取决于内存限制(数组越大,冲突越少)。此数组包含字符串的链接列表。将字符串添加到数组时,计算int key=hash(string)modulo set.size
,并将该字符串附加到set[key]
处的链接列表中。查找也会执行相同的操作-计算关键点,然后遍历链表以获得精确的结果match@SteveGreen使用链表处理冲突是一种“封闭寻址”方案;“开放寻址”方案是一种在检测到冲突时将字符串添加到相邻数组元素的方案(对于“相邻”的某些定义,不同的开放寻址方案使用不同的探测技术)。有关特定的开放寻址方案,请参阅Wikipedia上的文章。
public class ListIterator {
int index = 0;
List<Value> list;
Value curVal() {
return list[index];
}
boolean hasNext() {
return (index < list.size);
}
}
List<ListIterator> iterators;
for(int i = 0; i < list1.size; i++) {
Value curVal = list1[i];
for(int j = 0; j < iterators.size; j++) {
ListIterator iterator = iterators[j];
while(iterator.hasNext() && iterator.curVal() <= curVal) {
if(iterator.curVal() == curVal) {
// do something with iterator.curVal()
}
iterator.index++;
}
}
}
Set<String> set = new Set(List1);
Array<List> lists = new Array();
// add lists to Array<List>
for(int i = 0; i < lists.size; i++) {
List currentList = lists[i];
for(int j = 0; j < currentList.size; j++) {
if(set.contains(currentList[j]) {
// do something
}
}
}