【问题标题】:Linked list has different behaviour for similar pointer assignment链表对于类似的指针分配有不同的行为
【发布时间】:2020-07-18 09:10:31
【问题描述】:

我正在编写一个代码,当只给出指向节点的指针而没有给出头节点时,从链表中删除一个节点

/*
struct Node {
  int data;
  struct Node *next;
  Node(int x) {
    data = x;
    next = NULL;
  }
}*head;
*/

// This function should delete node from linked list. The function
// may assume that node exists in linked list and is not last node
// node: reference to the node which is to be deleted
void deleteNode(Node *node)
{
        node=(node->next);
}

不删除列表中的当前指针,但是,

/*
struct Node {
  int data;
  struct Node *next;
  Node(int x) {
    data = x;
    next = NULL;
  }
}*head;
*/

// This function should delete node from linked list. The function
// may assume that node exists in linked list and is not last node
// node: reference to the node which is to be deleted
void deleteNode(Node *node)
{
        *node=*(node->next);
}

从链表中删除节点

为什么?方法有什么区别?

【问题讨论】:

  • 两者都泄漏内存。第一个泄漏下一个节点。第二个用下一个节点的值覆盖当前节点,然后泄漏现在的前下一个节点。
  • 这里的完整解释需要彻底了解指针是什么以及它们是如何工作的。不幸的是,这是一个相当长的话题,stackoverflow 并不能真正替代一本好的 C++ 书籍。所以你只需要独自度过一段美好的时光。

标签: c++ c++11 pointers linked-list singly-linked-list


【解决方案1】:

分配给函数的(非引用)参数在该函数之外没有任何影响。
(了解指针最重要的一点是,指针没有什么特别之处。)

就是这样

void f(int x) { x = 1000; }

int main()
{
    int x = 0;
    f(x);
    std::cout << x << std::endl;
} 

将打印0,而不是1000

因此,您的第一次尝试不会修改任何内容,也没有明显的效果。

您的第二次尝试也有问题 - 它复制了下一个节点但没有删除它。
如果您的节点是动态分配的(通常是这样),这就是内存泄漏。

你需要这样的东西:

void deleteNode(Node *node)
{
    Node* old = node->next;
    *node = *(node->next);
    delete old;
}

但是,通过复制节点来修改列表有点不合常规,因为如果节点的数据很大,则效率非常低。
通常,您会更新列表中的链接,但为了做到这一点,您需要知道前一个节点是什么。

【讨论】:

    【解决方案2】:

    仅在给出指向节点的指针时从链表中删除节点 - 只有在双向链表或索引列表中才有可能。列表本身的性质表明您必须修改另一个节点才能从现有链中删除一个。

    在第一种情况下,节点包含指向前一个节点的指针,成本为 O(1),而对于索引列表,您有索引(键)并可以访问映射\索引机制,获取前一个节点的成本取决于使用的方法。最后一个原因,索引列表有时被实现为双向链接。

    【讨论】:

      【解决方案3】:

      让我们用整数而不是节点来举一个更简单的例子:

      void Modify_1 (int *piVal, int *piNewVal)
       {  
          //piVal has adresse of i passed as argument 
      
           // similar to  node = (node->next);    
           piVal = piNewVal;  // This change just the VALUE of the pointer passed as argument !  
      
      
          //piVal has adresse of j now
       }
      
      void Modify_2 (int *piVal)
      {
          // similar to *node=*(node->next);
          *piVal = 0; // This change de content of pointer 
      }
      
      int main ()
      {
          int i = 3;
          int j = 5;
      
          Modify_1 (&i, &j);
          cout << i << endl; // This print 3 !
      
          Modify_2 (&i);
          cout << i << endl; // This print 0
      
          return 0;
      }
      

      piVal 是一个包含i 地址值的pointer。示例:0x00bcfdb4
      如果您想运行,此地址将作为值 (0x00bcfdb4) 传递。
      只要不写*piVal,就不会改变指向的内容,只会改变地址的VALUE。

      如果你想改变指针,你需要一个**int(在你的情况下是**node

      void Modify_3 (int **piVal, int *piNewVal)
      {
         *piVal = piNewVal;   // this change de pointer adresse
      }  
      
      int main ()
      {
          int x = 5;
          int *pi = &x;
          Modify_3 (&pi, &x);
      
          cout << *pi << endl; // This print 5  
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-09-19
        • 1970-01-01
        • 2018-11-24
        • 1970-01-01
        • 2021-10-18
        • 2020-01-22
        • 2013-12-13
        相关资源
        最近更新 更多