C++ 此函数用于检测循环链表的时间复杂度是多少?
我只是尝试使用无序映射来检测循环链表(我知道这是个坏主意) 在名为linked_list的类中,我的IsCycle()函数的代码段如下:C++ 此函数用于检测循环链表的时间复杂度是多少?,c++,algorithm,time-complexity,C++,Algorithm,Time Complexity,我只是尝试使用无序映射来检测循环链表(我知道这是个坏主意) 在名为linked_list的类中,我的IsCycle()函数的代码段如下: bool linked_list::isCyclic(Node * head) { Node * trav = head; unordered_map<Node *, int > visited; while(trav != NULL) { if(visited[trav->next_ptr] == 3)
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;
}
bool链表::isCyclic(节点*头)
{
节点*trav=头部;
访问了无序的地图;
while(trav!=NULL)
{
if(已访问[trav->next_ptr]==3)
返回true;
访问量[trav]=3;
trav=trav->next_ptr;
}
返回false;
}
对于每个新节点,我检查下一个ptr是否指向已访问的节点,如果是,则返回true,否则我只是将该节点设置为已访问,并将trav更新到下一个要访问的节点,直到出现循环情况或遍历所有节点
我不想知道这个算法的大O符号是什么,因为根据我的计算,它是O(n*n),我猜这是错误的,因为我并不总是那么准确。提供的算法的复杂性是
O(n)
。原因很简单,因为无序_映射和无序_集都根据标准库的要求提供恒定的插入、搜索和删除时间。因此,给定一个平均常数时间k
,复杂性变为O(k*n)
,这相当于k*O(n)
,并且随着常数k
变得不相关,其基本复杂性最终为O(n)
为了演示这一点,下面的示例将循环搜索简化为使用std::unordered_set
的最基本情况,它比std::unordered_map
略多,其中键映射到self
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;
}
这将使用每个节点彻底搜索列表的其余部分,从而执行(n-1)+(n-2)+(n-3)…+(n-(n-1))
比较
示例
在操作中看到这些,考虑下面的短程序,该程序加载一个具有100000个节点的链表,然后检查最坏情况下的循环(没有):
正如预期的那样,结果反映了我们的怀疑。所提供算法的复杂性是
O(n)
。原因很简单,因为无序_映射和无序_集都根据标准库的要求提供恒定的插入、搜索和删除时间。因此,给定一个平均常数时间k
,复杂性变为O(k*n)
,这相当于k*O(n)
,并且随着常数k
变得不相关,其基本复杂性最终为O(n)
为了演示这一点,下面的示例将循环搜索简化为使用std::unordered_set
的最基本情况,它比std::unordered_map
略多,其中键映射到self
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;
}
这将使用每个节点彻底搜索列表的其余部分,从而执行(n-1)+(n-2)+(n-3)…+(n-(n-1))
比较
示例
在操作中看到这些,考虑下面的短程序,该程序加载一个具有100000个节点的链表,然后检查最坏情况下的循环(没有):
正如预期的那样,结果反映了我们的怀疑。您是通过什么方式得出O(n^2)的?或者这是一个猜测,类似于你的结论,这是错误的?因为所有节点的while循环和无序_图的时间复杂性,正如我在一些论坛上读到的,是O(n)。这就是我认为它是O(n^2)的原因,但正如我之前提到的,我是这个主题的绝对初学者,所以有99%的可能性我是错的。你是通过什么方式得出O(n^2)的?或者这是一个猜测,类似于你的结论,这是错误的?因为所有节点的while循环和无序_图的时间复杂性,正如我在一些论坛上读到的,是O(n)。这就是我认为它是O(n^2)的原因,但正如我之前提到的,我是这个主题的绝对初学者,所以有99%的可能性我错了。谢谢你的精彩解释。我提供的代码是否不正确?我的意思是,它不是为不同的测试用例提供了正确的输出吗?谢谢你的精彩解释。我提供的代码是否不正确?我的意思是,它不能为不同的测试用例提供正确的输出吗?
#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() << "ms\n";
std::cout << "check_for_cycle_long : " <<
duration_cast<milliseconds>(tp2-tp1).count() << "ms\n";
}
false
false
check_for_cycle_short : 36ms
check_for_cycle_long : 7239ms