C++ 寻找「;从末端算起的第n个节点;链表的定义

C++ 寻找「;从末端算起的第n个节点;链表的定义,c++,linked-list,C++,Linked List,这似乎返回了正确的答案,但我不确定这是否是处理事情的最佳方式。看起来我访问前n个节点的次数太多了。有什么建议吗?请注意,我必须使用单链接列表来完成此操作 Node *findNodeFromLast( Node *head, int n ) { Node *currentNode; Node *behindCurrent; currentNode = head; for( int i = 0; i < n; i++ ) { if( curre

这似乎返回了正确的答案,但我不确定这是否是处理事情的最佳方式。看起来我访问前n个节点的次数太多了。有什么建议吗?请注意,我必须使用单链接列表来完成此操作

Node *findNodeFromLast( Node *head, int n )
{
    Node *currentNode;
    Node *behindCurrent;
    currentNode = head;
    for( int i = 0; i < n; i++ ) {
        if( currentNode->next ) {
            currentNode = currentNode->next;
        } else {
            return NULL;
        }
    }

    behindCurrent = head;
    while( currentNode->next ) {
        currentNode = currentNode->next;
        behindCurrent = behindCurrent->next;
    }

    return behindCurrent;
}
public ListNode NthNodeFromEnd(int n){
        ListNode pTemp = head, NthNode = null;
       for(int count=1; count<n;count++){
         if(pTemp!=null){
           pTemp = pTemp.getNext();
         }
       }
       while(pTemp!=null){
         if(NthNode==null){
             NthNode = head;
         }
         else{
            NthNode = NthNode.getNext();
         }
         pTemp = pTemp.getNext();
       }
       if(NthNode!=null){
         NthNode = NthNode.getNext();
         return NthNode;
       }
    return null;
  }
Node*findNodeFromLast(Node*head,int-n)
{
节点*当前节点;
节点*落后于电流;
currentNode=头部;
对于(int i=0;i下一步){
currentNode=currentNode->next;
}否则{
返回NULL;
}
}
落后电流=水头;
同时(当前节点->下一步){
currentNode=currentNode->next;
落后电流=落后电流->下一步;
}
逆流返回;
}

您可以使用双链接列表,这是一个还存储其父级地址的链接列表。横向比较容易,因为你可以从末尾开始,一路工作到开头。

你的运行时间仍然是O(n),所以我看不出有什么问题

从概念上讲,可以将列表分为两部分:返回节点之前的部分和返回节点之后的部分。其中一个部分必须步行两次。您的实现选择了第一个,其优点是没有额外的内存使用(除了几个临时变量)

或者,您可以创建一个堆栈,遍历列表并将每个元素放入堆栈,然后弹出n个项目。然后,你将两次走到列表的末尾,而不是开始。这样做的缺点是将列表存储在内存中两次。(通过只存储n个元素并在添加新元素时将其从堆栈底部删除,可以使堆栈变得更智能;然后只使用足够的空间来存储n个节点。)


我假设你不能通过在适当的地方反转列表来吹走它。然后是恒定内存,仍然是O(n),仍然在列表末尾走两次。

开始两个指针。将第一个
N
元素向前移动,然后将每个指针移动1个元素。当第一个指针到达终点时,第二个指针将给出答案


编辑:是的,它与问题中给出的代码几乎相同。但我觉得伪代码更清楚。要回答这个问题,没有其他go,因为first
N
元素必须访问两次。如果
N
很小,则无所谓。如果
N
较大,则第二个循环较小。因此,它始终是一个
O(n)
解决方案。

首先计算列表中的节点数。然后再次遍历,减少n个节点。仍然是一种O(n)算法,这是不可避免的。

另一种不需要访问两次节点的方法如下:

创建一个大小为n的空数组,从索引0开始指向该数组的指针,并从链表的开头开始迭代。每次访问节点时,将其存储在数组的当前索引中,并前进数组指针。填充数组时,环绕并覆盖以前存储的元素。当您到达列表的末尾时,指针将指向列表末尾的元素n

但这也只是一个O(n)算法。你现在所做的一切都很好。我看不出有什么令人信服的理由来更改它。

Node*fetchnnoderfrmlast(int arg)
    Node* fetchNNodeFrmLast(int arg)
    {
    Node *temp = head;
    Node *nNode = head;
    if(head == NULL || arg <= 0)
    {
        Printf("Either head is null or invalid number entered");
        return;
    }   


    while(temp != NULL)
    {

        temp = temp->next;
        if(arg > 1)
        {
            arg--;

            continue;   
        }       
        nNode = nNode->next;    
    }

    return nNode;   
}
{ 节点*温度=头部; 节点*nNode=头部; if(head==NULL | | arg next; 如果(arg>1) { arg--; 继续; } nNode=nNode->next; } 返回nNode; }
我正在使用一个将递增的静态变量'I' 当从列表末尾回溯时。就像在 问题陈述,我们将基本上跟踪第n个 从链表末尾开始的元素。 递归帮助我们从结尾跟踪

static int i;
public static void NthToLast(LinkedListNode head, int n)
{
    if (head == null)
        return;

    NthToLast(head.Next, n);
    i++;
    if (n == i) 
     { 
     Console.WriteLine("Mth to last" + head.Data); 
     return; 
     }

}
这很简单。。 取两个指针p1,p2
在p1移动“n”个节点后启动p2,并让p1移动到最后一个。p2指向的节点将是最后一个节点的第n个节点。保持两个指针n个节点之间的间隔。当第一个指针到达尾部时,第二个指针将指向所需的节点

代码:


}

此代码似乎更清晰

public Node<T> findNthNodeFromLast(int n) {
    Node<T> current = head;
    Node<T> findElement = head;
    int length = 0;
    while (current != null && current.next != null) {
        length++;
        if (length >= n) {
            findElement = findElement.next;
        }
        current = current.next;
    }

    return findElement;
}
公共节点findNthNodeFromLast(int n){
节点电流=头;
节点findElement=头;
整数长度=0;
while(当前!=null&¤t.next!=null){
长度++;
如果(长度>=n){
findElement=findElement.next;
}
当前=当前。下一步;
}
返回findElement;
}

使用两个指针pTemp和NthNode。最初,两个指针都指向列表的头节点。NthNode仅在pTemp移动n次后才开始移动。从这两个指针开始向前移动,直到pTemp到达列表的末尾。因此,NthNode指向链接列表末尾的第n个节点

Node *findNodeFromLast( Node *head, int n )
{
    Node *currentNode;
    Node *behindCurrent;
    currentNode = head;
    for( int i = 0; i < n; i++ ) {
        if( currentNode->next ) {
            currentNode = currentNode->next;
        } else {
            return NULL;
        }
    }

    behindCurrent = head;
    while( currentNode->next ) {
        currentNode = currentNode->next;
        behindCurrent = behindCurrent->next;
    }

    return behindCurrent;
}
public ListNode NthNodeFromEnd(int n){
        ListNode pTemp = head, NthNode = null;
       for(int count=1; count<n;count++){
         if(pTemp!=null){
           pTemp = pTemp.getNext();
         }
       }
       while(pTemp!=null){
         if(NthNode==null){
             NthNode = head;
         }
         else{
            NthNode = NthNode.getNext();
         }
         pTemp = pTemp.getNext();
       }
       if(NthNode!=null){
         NthNode = NthNode.getNext();
         return NthNode;
       }
    return null;
  }
public listnothNodeFromend(int n){
ListNode pTemp=head,NthNode=null;

对于(int count=1;count这是一个单链接列表,没有关于列表中有多少项的信息吗?正确。单链接列表。只是为了挑剔,我将
命名为
currentNode
,并将
currentNode
命名为其他内容。关于环形缓冲区的有趣文章:相关帖子-确实,对不起,我是叔叔这必须通过一个单链表来完成。这有具体的原因吗?我看不出使用它会产生任何问题…使用一个指针数组,每个单元格一个。唯一的问题是更新它的开销…这与他当前的解决方案不同吗?…这显然是原始帖子中的代码实现的(假设操作正确)这不是问题中的实现所做的吗?我同意alg必须是O(n)。我不同意“前n个元素必须访问两次”。请参阅我的答案,了解访问所有节点一次的alg。我同意这是正确的