C++ 此函数用于检测循环链表的时间复杂度是多少?

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)

我只是尝试使用无序映射来检测循环链表(我知道这是个坏主意)

在名为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)
        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