在链接列表中找到一个带查找表的圆圈

Finding a circle in a linked list with lookup table

本文关键字:查找 一个 列表 链接      更新时间:2023-10-16

我正在尝试在链接列表中找到一个圆,并在圆圈开头返回节点。例如,如果列表为a-> b-> c-> d-> c-我们将返回c

这是我的代码:

ListNode<T> * findCircle()
{
  map<ListNode<T>*, bool> addresses;
  ListNode<T>* node = head;
  if(addresses.find(node)->second)
    cout << " wtf " << endl;
  while(node)
  { 
    if((addresses.find(node))->second)
    {
      return node;
    } 
    else
      addresses.insert(pair<ListNode<T>*,bool>(node, 1));
    node = node->next;
  }
  return NULL;
}

我有几个问题:

1)这是解决问题的正确方法

2)我是否使用最有效的方法来查找/插入键和值

3)为什么不起作用?当我在地图上检查头部时,在插入头之前,它仍然执行IF语句并打印" WTF"。我的算法是将节点插入具有真实值的键,如果它在地图中找不到,否则如果键已经在地图中。

,则返回节点。

我尝试使用std ::设置进行此操作,但它给了我麻烦,所以我切换到了地图。令我感到困惑的是,以下代码使用完全相同的方法可以使用以下代码(使用查找表中删除链接列表中的重复项)。

  void removeDuplicates()
    {
      map<T, bool> listData;
      ListNode<T> *node;
      ListNode<T> *prev = node;
      for(node = head; node; node = node->next)
      {
        if(listData.find(node->data)->second)
        {
          prev->next = node->next;
          delete node;
        }
        else
        {
          listData.insert( pair<T, bool>(node->data, 1));
        }
        prev = node;
      }
    }

第二个代码的块是一种fluke,但第一个块不做?

您需要检查查找操作是否真正找到数据

auto iterator itr = address.find(node);
if(itr != address.end()){
    if(itr->second == true){ cout << "WTF" << endl; }
}

时循环类似。至于您的方法,我认为它具有O(n)的最佳运行时间。您所能做的就是降低常数。

addresses.find(node)->second

find()失败时,当前会产生未定义的行为,因为您正在尝试访问过去迭代器的second字段。而是使用

addresses.find(node) != addresses.end()

另外:找到一个循环的确切位置(通常称为),还是您只想查看是否存在周期?如果是的,那么一种极其聪明的算法可以使用两个指针在线性时间和恒定空间中解决问题,其中一个移动的速度是另一个指针的两倍:)