该功能检测循环链接列表的时间复杂性是什么?
What is the time complexity for this function for detecting cyclic linked lists?
我刚刚尝试使用unordered_map检测循环链接列表(我知道这是一个坏主意)。
我的同类linked_list中我的iScyclic()函数的代码片段是:
bool linked_list::isCyclic(Node * head)
{
Node * trav = head;
unordered_map<Node *, int > visited;
while(trav != NULL)
{
if(visited[trav->next_ptr] == 3)
return true;
visited[trav] = 3;
trav = trav->next_ptr;
}
return false;
}
对于每个新节点,我检查next_ptr是否指向已经访问的节点,如果是的话,我返回否则,我只是将该节点设置为访问量,然后更新到下一个节点访问访问,直到有环境有环境或直到所有节点都遍历。
我不知道该算法的大符号是什么,因为根据我的计算,它的o(n*n)是错误的,因为我始终不太准确。
提供算法的复杂性是O(n)
。原因仅仅是因为UNOREDED_MAP和UNOREDED_SET都根据标准库的要求提供恒定的插入,搜索和删除时间。因此,考虑到平均恒定时间k
,复杂性变为O(k*n)
,相当于k*O(n)
,并且随着常数k
的基本复杂性,最终具有O(n)
的基本复杂性。
为了证明这一点,以下示例将您的周期搜索减少到使用std::unordered_set
的最基本情况,该案例仅比std::unordered_map
多,其中键映射到自我。
bool check_for_cycle_short(const Node *p)
{
std::unordered_set<const Node*> mm;
for (; p && mm.insert(p).second; p = p->next);
return p != nullptr;
}
请注意,std::unordered_set<T>::insert
返回iterator,bool
的CC_11,其中后者指示是否确实发生了插入,因为在插入之前找不到密钥。
现在考虑此示例,即O(n^2)
:
bool check_for_cycle_long(const Node *p)
{
for (; p; p = p->next)
{
for (const Node *q = p->next; q; q = q->next)
{
if (q == p)
return true;
}
}
return false;
}
这用每个节点详尽地搜索列表的其余部分,从而执行(n-1) + (n-2) + (n-3).... + (n-(n-1))
比较。
示例
要查看这些操作,请考虑以下简短程序,该程序将链接的列表加载为100000节点,然后检查两者都在最差的情况下(无)中的循环:
#include <iostream>
#include <iomanip>
#include <chrono>
#include <unordered_set>
struct Node
{
Node *next;
};
bool check_for_cycle_short(const Node *p)
{
std::unordered_set<const Node*> mm;
for (; p && mm.insert(p).second; p = p->next);
return p != nullptr;
}
bool check_for_cycle_long(const Node *p)
{
for (; p; p = p->next)
{
for (const Node *q = p->next; q; q = q->next)
{
if (q == p)
return true;
}
}
return false;
}
int main()
{
using namespace std::chrono;
Node *p = nullptr, **pp = &p;
for (int i=0; i<100000; ++i)
{
*pp = new Node();
pp = &(*pp)->next;
}
*pp = nullptr;
auto tp0 = steady_clock::now();
std::cout << std::boolalpha << check_for_cycle_short(p) << 'n';
auto tp1 = steady_clock::now();
std::cout << std::boolalpha << check_for_cycle_long(p) << 'n';
auto tp2 = steady_clock::now();
std::cout << "check_for_cycle_short : " <<
duration_cast<milliseconds>(tp1-tp0).count() << "msn";
std::cout << "check_for_cycle_long : " <<
duration_cast<milliseconds>(tp2-tp1).count() << "msn";
}
输出(MacBook Air Duo-core I7 @ 2.2GHz)
false
false
check_for_cycle_short : 36ms
check_for_cycle_long : 7239ms
正如预期的,结果反映了我们怀疑的结果。
- 解决这个问题的时间复杂性是多少
- 对于像C++这样的现实世界语言,时间复杂性有什么一致的定义吗
- 使用 GetLastError() 的真正正确的方法(时间)是什么?
- 这种日期和时间格式是什么?
- Find() 函数的复杂性是什么?
- 从n的角度来看,该算法的复杂性是什么
- 映射向量的时间复杂性是多少
- 函数不受主内存约束的函数所需的复杂性是什么?
- 该功能检测循环链接列表的时间复杂性是什么?
- 语言环境"en_US"中 std::time_get::get_time() 的正确时间格式是什么?
- 以下代码的复杂性是什么?
- 标准::时间纪元是什么时候?
- std::string::substr成员函数的复杂性是什么?
- 主流C++编译器中 GC 实现的时间线是什么?
- 该代码的复杂性是什么
- 计算时间增量最快的linux C时间函数是什么?看到clock_gettime和gettimeofday表现不佳
- C++set_intersection的复杂性是什么
- 在 LLVM libc++ 中找到的 string::find 中实现的算法(及其复杂性)是什么?
- c++ 计时的默认时间单位是什么?
- 此代码的复杂性是什么?我们是否应该总结复杂性