改进从 O(n) 到 O(1) 的双端队列移动
Improvement deque movement from O(n) to O(1)
任务是队列中有 N 个号码。
并且原始序列是从 1 到 N。
“移动a b”的意思是移动a前面的所有数字(包括a)
然后将它们插入 b 的前面(不改变顺序)
并在 "Exit" 出现时输出整个队列。
这是我处理 "Move":
的代码
//I establish q & q1 deque
while(cin>>commend){
if(commend == "Move"){
cin>>a>>b;
int checka,checkb = 0;
//search for a,b position
//it1,it2 are both iterators
for(int m = 0; m < num ; m++){
if(q[m] == a){
it1 = q.begin()+m;
checka = 1;
}
else if(q[m] == b){
it2 = q.begin()+m;
con2 = m; //store m in con2 to use below
checkb = 1;
}
else if( checka == 1 && checkb == 1)
break;
}
//con is also a iterator
//q1 is a new deque to store the elements before (include)number"a"
//procedures below are moving the numbers before(include)"a" and push_front the elements between number "a" and number "b"
for(con = it1; con>= q.begin() ; con--)
q1.push_front(*con);
for(con = it2; con > it1+1; con--){
q1.push_front(*con);
}
//copy the "swaped" elements from q1 to q
//and clear q1
for(int m = 0; m<con2-1; m++)
q[m] = q1[m];
q1.clear();
}
}
但是速度是O(N),如果需要用O(1)完成任务,我不知道在哪里可以改进。
除了构建链表之外还有什么建议吗?
您可以维护队列中号码的链表加上索引(散列,如 std::unordered_map),每个号码作为指向队列中号码的键。要更改顺序,您只需在 O(1) 时间内在索引中查找 a 和 b,转到列表中的数字并交换它们的链接指针以更改它们的顺序,再次在 O(1) 时间内。
您不能在 O(1)
中执行 Move
功能。这是因为复杂性由搜索和创建操作共同决定。您的搜索操作需要 O(n)
,并且您不能减少它,除非并且直到您更改数据结构(您不想这样做)。即使你,假设你在O(1)
中搜索,如果数据存储在一个连续的内存块中,你将只能在O(1)
中进行复制操作,然后你可以使用memcpy()
。但是,您的搜索操作永远不会在 O(n)
下进行,因此根据我的说法,没有改变渐近边界的余地。此外,如果 a
和 b
相等,您的程序将不会执行任何操作。
任务是队列中有 N 个号码。 并且原始序列是从 1 到 N。 “移动a b”的意思是移动a前面的所有数字(包括a) 然后将它们插入 b 的前面(不改变顺序) 并在 "Exit" 出现时输出整个队列。
这是我处理 "Move":
的代码//I establish q & q1 deque
while(cin>>commend){
if(commend == "Move"){
cin>>a>>b;
int checka,checkb = 0;
//search for a,b position
//it1,it2 are both iterators
for(int m = 0; m < num ; m++){
if(q[m] == a){
it1 = q.begin()+m;
checka = 1;
}
else if(q[m] == b){
it2 = q.begin()+m;
con2 = m; //store m in con2 to use below
checkb = 1;
}
else if( checka == 1 && checkb == 1)
break;
}
//con is also a iterator
//q1 is a new deque to store the elements before (include)number"a"
//procedures below are moving the numbers before(include)"a" and push_front the elements between number "a" and number "b"
for(con = it1; con>= q.begin() ; con--)
q1.push_front(*con);
for(con = it2; con > it1+1; con--){
q1.push_front(*con);
}
//copy the "swaped" elements from q1 to q
//and clear q1
for(int m = 0; m<con2-1; m++)
q[m] = q1[m];
q1.clear();
}
}
但是速度是O(N),如果需要用O(1)完成任务,我不知道在哪里可以改进。
除了构建链表之外还有什么建议吗?
您可以维护队列中号码的链表加上索引(散列,如 std::unordered_map),每个号码作为指向队列中号码的键。要更改顺序,您只需在 O(1) 时间内在索引中查找 a 和 b,转到列表中的数字并交换它们的链接指针以更改它们的顺序,再次在 O(1) 时间内。
您不能在 O(1)
中执行 Move
功能。这是因为复杂性由搜索和创建操作共同决定。您的搜索操作需要 O(n)
,并且您不能减少它,除非并且直到您更改数据结构(您不想这样做)。即使你,假设你在O(1)
中搜索,如果数据存储在一个连续的内存块中,你将只能在O(1)
中进行复制操作,然后你可以使用memcpy()
。但是,您的搜索操作永远不会在 O(n)
下进行,因此根据我的说法,没有改变渐近边界的余地。此外,如果 a
和 b
相等,您的程序将不会执行任何操作。