Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在单个遍历中找到单个链表的中间节点(如果没有给出链表的长度)_C++_Linked List - Fatal编程技术网

C++ 如何在单个遍历中找到单个链表的中间节点(如果没有给出链表的长度)

C++ 如何在单个遍历中找到单个链表的中间节点(如果没有给出链表的长度),c++,linked-list,C++,Linked List,我有一个问题陈述,比如:“如何在一次遍历中找到单个链表的中间节点,问题是我们不知道链表中的节点数?” 我有一个答案,比如“在遍历链表时,获取一个向量并开始推送所有节点的地址,然后递增一个计数器,直到到达链表的末尾”。因此,在最后我们可以得到列表中的节点数,如果偶数(计数器/2)或奇数(计数器/2+计数器%2)给出中间节点数,我们可以得到vectore.at(middleNodeEnumber)指向中间节点” 这很好……但这是存储一个非常大的链表的所有地址的内存浪费!那么我们如何才能有更好的解决方

我有一个问题陈述,比如:“如何在一次遍历中找到单个链表的中间节点,问题是我们不知道链表中的节点数?”

我有一个答案,比如“在遍历链表时,获取一个向量并开始推送所有节点的地址,然后递增一个计数器,直到到达链表的末尾”。因此,在最后我们可以得到列表中的节点数,如果偶数(计数器/2)或奇数(计数器/2+计数器%2)给出中间节点数,我们可以得到
vectore.at(middleNodeEnumber)
指向中间节点”


这很好……但这是存储一个非常大的链表的所有地址的内存浪费!那么我们如何才能有更好的解决方案呢?

您可以使用一个带有两个迭代器的单循环,例如
it1
it2
,其中您只需在循环的每一次迭代中增加
it2
。当
it1
重新开始时终止单击列表的结尾。
it2
现在将指向列表的中间元素。

尝试以下操作:

您有两个指针。一个指向中间,另一个指向末尾,这两个指针在开始时都指向列表的开头。每秒钟成功增加一次结束指针,您就增加一次中间a,直到结束指针到达末尾。

假设您有一个
std::list l

std::list<T>::iterator i = l.begin();
std::list<T>::iterator m = l.begin();
bool even = true;
while (i != list.end())
{
  if (even) ++m;
  ++i;
  even = !even;
}
std::list::iterator i=l.begin();
std::list::迭代器m=l.begin();
布尔偶数=真;
while(i!=list.end())
{
if(偶数)++m;
++一,;
偶数=!偶数;
}

现在
m
指向
l

的中间,以下是步骤:

std::list<T>::iterator i = l.begin();
std::list<T>::iterator m = l.begin();
bool even = true;
while (i != list.end())
{
  if (even) ++m;
  ++i;
  even = !even;
}
  • 取两个指针
    *p1
    *p2
    ,指向链接的头 名单
  • 启动一个循环并递增
    *p2
    ,2次(使用空检查)
  • 如果
    *p2
    不为空,则将
    *p1
    增加1次
  • *p2
    达到空值时,您的
    *p1
    位于中心

[注意:如果处理容器类型的链表,可以使用迭代器而不是指针]

使用两个指针。将第一个指针移动两个节点,将第二个指针移动一个节点。当第一个指针到达末尾时,第二个指针将指向中间

// How to find the middle node of a single linked list in a single traversal
//     1. The length of the list is not given
//     2. If the number of nodes is even, there are two middle nodes,
//        return the first one.
Node* MiddleNode(Node* const head)
{
    if (!head)
    {
        return head;
    }

    Node* p1 = head, * p2 = head->next;

    while (p2 && p2->next)
    {
        p1 = p1->next;
        p2 = p2->next->next;
    }

    return p1;
}

试试这段代码

这是我的第一个想法,但它仍然是“只有一次遍历”吗“?是的,因为您只有一个循环。如果这是作业,我不知道这是否是作业的目的,但出于实际的目的,这一次遍历了列表。真正的答案应该是这样的,因为如果你从循环构造中考虑任务,当前的答案只能保持单次遍历规则。但实际扫描次数至少为1.5N。我看不出我的答案和接受的答案之间有任何区别,它们做的是相同的事情。在首次
advance b
之后,您必须检查空值。否则就崩溃!取决于准确的问题陈述。如果给定列表的中间位置,则其长度必须为奇数。你可以在循环之前<代码>提前B/COD>。“你是正确的,不能崩溃:”但是,我用C++替换了代码,它说明并解决了你所描述的问题。如果它有偶数个节点,我们怎么能照顾一个链表?如果我们在继续之前不检查空,它会给崩溃RI8。虽然这确实是希望的答案,但我从来没有理解为什么它会考虑一个单一的遍历。实际上是两次(或1.5次)并行遍历,指针/迭代器增量不少于两次(1.5次)串行遍历。这是避免计数器,但不是任何遍历。