【问题标题】:Insert node at specific position在特定位置插入节点
【发布时间】:2021-02-08 13:10:17
【问题描述】:

我需要在链表的给定位置插入一个节点。 有没有更好的方法呢? 这是我的代码:

struct node
{
    int data;
    node* next;
};
void InsertNodeAtPosition(node *& first , int x , int position)
{

//0 based indexing
    int i = 0;
    node *q = new node;
    q = first;
    while (i != position - 1)
    {
      q = q->next;
      i++;
    }
    node *t = new node;
    t->data = x;
    t->next = q->next;
    q->next = t;
}

我对其进行了测试,它确实有效。但我想在进入下一章之前真正擅长链表。谢谢!

【问题讨论】:

  • 对于链表之类的东西,我总是建议从使用笔和纸开始。通过在几张纸上绘图来执行所有操作。为节点绘制方框,为链接绘制箭头。在修改箭头(链接)时擦除并重新绘制它们。
  • 你正在创建一个新节点,然后立即删除指向它的指针,造成内存泄漏,这里:node *q = new node; q = first; 这看起来不对。
  • 并且在测试代码时,始终使用边缘情况(如0 或列表长度减一作为索引,使用空列表、一节点列表、二节点列表、三节点列表)。并且还使用 invalid 数据进行测试(这里你的函数会失败,尝试在列表末尾给出position)。
  • 对于代码的评论有codereview.stackexchange.com,尽管你应该在那里发布正确的代码。要求审核的问题通常过于宽泛或基于意见
  • @idclev463035818 那我该怎么做呢?

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


【解决方案1】:

你写的函数是错误的,有内存泄漏和未定义的行为。

例如,首先为指针q 分配动态分配内存的地址,然后重新分配指针first 的值。所以分配的内存地址丢失,内存无法释放。

node *q = new node;
q = first;

此外,通过引用传递给函数的指针first 在函数内永远不会改变。

在 while 循环中,您不会检查指针 q 是否等于 nullptr

while (i != position - 1)
{
  q = q->next;
  i++;
}

所以这个说法

q = q->next;

调用未定义的行为。

如果position 等于0 那么条件

i != position - 1

将评估为 true,并且您将再次出现未定义的行为。

函数可以这样写

void InsertNodeAtPosition( node * &first , int x , size_t position )
{
    node **current = &first;

    while ( *current && position-- )
    {
        current = &( *current )->next;
    }

    *current = new node { x, *current };
}

【讨论】:

  • 你到底做了什么.....我理解你回答的第一部分,但你的功能远远超出了我 XD
  • @CosminAndrei 我首先声明了一个指向指针的指针。即现在指针首先通过 C 含义中的引用访问。取消引用指针 current 我可以先更改指针或当前节点的任何数据成员 next。执行while循环,直到当前指针等于nullptr或位置等于0。之后动态分配一个新节点。
【解决方案2】:

有没有更好的办法?

当然,最好不要泄漏内存:

node *q = new node;
q = first;

至于算法本身:对于单链表,将元素插入特定位置的更好方法是将指向前一个节点的指针作为参数传递,而不是头部和位置。这样就不需要线性搜索了。但是对于给定的参数,您尝试的算法是最优的。

至于类设计:更好的方法是为列表实现迭代器并使用它们而不是指向节点的指针,以便可以使用标准算法。并遵循 5 规则以符合 RAII 模式和容器概念。并使用模板来支持不同的数据类型。并支持使用自定义分配器,以便用户控制节点的分配方式。

至于更高级别的设计:使用单链表的更好方法是不执行任何操作,因为标准库已经提供了数据结构的实现:std::forward_list

【讨论】:

  • 如何避免内存泄漏?
  • @CosminAndrei 不要创建不使用的节点。计算函数中new 的数量。计算您的函数应该插入列表中的节点数。
  • @CosminAnrei 你创建了一个新节点并且不做任何事情,所以不要创建它
  • 用节点 q 我在给定位置的节点之前停止,然后我插入节点 t...否则我该怎么做?
  • @CosminAndrei q 和 t 不是节点。它们是指向节点的指针。 q 在迭代时指向几个不同的节点。 How can i do it otherwise?我在答案中建议了一种替代算法。如果您将指向前一个节点的指针直接传递给函数,那么您可以在没有线性搜索的情况下进行插入。
猜你喜欢
  • 2012-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多