【问题标题】:C programming Linked Lists delete node at position NC编程链接列表删除位置N处的节点
【发布时间】:2011-06-28 01:45:57
【问题描述】:

编辑:找出问题所在。此外,如果您通过 google 或其他搜索引擎发现此问题,这里就是我出错的地方以及如何解决它。

我的 deleteNode() 方法以正确的温度在列表中正确移动,并保持头部不变。我出错的地方是我作为该方法的结果返回的内容。我返回的 temp 或 newNode 不正确,因为它遍历列表直到找到定义的位置。一旦找到定义的位置,它将重新分配 ->next 指针以指向正确的 next->next> 指针,但我又返回了错误的东西。因为我们已经使用 temp/NewNode 在列表中移动了,所以我们丢失了标题,我们正在返回我们找到的位置以及仍然在列表的下一个位置中的任何内容。

我们如何解决这个问题是返回头部(这是传递给方法的内容)。之所以如此,是因为我们必须了解 LinkedLists 是如何工作的。每个节点的指针指向下一个节点。前任。我们有一个链表 |A|| - |B|| - |C|| - |D|| - |E|| - |F||

如果我们想删除节点 C,我们使用 temp 指针移动到节点 B,然后将 B->next 分配给 temp->next->next 从而跳过 C 节点并分配 D 节点。

注意:(据我所知,这实际上并没有释放 C 节点的内存,因此它不是最佳实践,因为这样会导致内存泄漏)您应该在 C 节点上使用 free() 方法。

这是我最终使用的代码

struct node* DeleteNode(struct node* head, int pos) {

     struct node* temp = head;
     int length = LinkedListLength(temp);
     int i;

    if(pos <= 0 || pos > length){
        printf("ERROR: Node does not exist!\n");
    }else{
        if(pos == 1){
            head = head->next; //move from head (1st node) to second node
        }else{
            for(i = 1; i < pos-1; ++i){ //move through list
                    temp = temp->next;
            }
            temp->next = temp->next->next;
        }
    }
    return head;
}

希望这有助于了解我是如何修复它的。

/////////////////////////////////////// ///////////////////////////////////////// /
///////////////////////////////////////// ////////////////////////////////////////////////
原帖
///////////////////////////////////////// ////////////////////////////////////////////////
///////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// p>

编辑:注意:这是我花了几天时间(估计 4 小时)编写的家庭作业,我只是被困在这一部分上。你可以在下面查看我的尝试

我已经能够从开始/结束插入和删除,但是我似乎无法让位于链接列表中位置 N 的删除节点工作。

我的伪代码如下所示:

  1. 链表:1,3,5,7,9,23
  2. 抓取链表
  3. 创建新结构节点 A = head
  4. 在链表中移动直到 位置
  5. 将节点分配给节点->下一步
  6. 返回链表

示例输入

Node structure 
int data;
struct node* next;

int values[] = {1,3,5,7,9,23};
struct node* llist = CreateList(values,6);

llist = DeleteNode(llist, 1);
llist = DeleteNode(llist, 5);
llist = DeleteNode(llist, 3);

一旦代码运行,llist 的值应该是 3、5、9 但是,它将第一个节点替换为 0

实际代码:

struct node* DeleteNode(struct node* head, int pos) {

struct node* temp = head;
struct node* newNode = head;
int length;
int i;

printf("DeleteNode: position = %d \nBefore: ", pos);
PrintList(temp);

if(pos <= 0){ //node does NOT exist
    printf("ERROR: Node does not exist!\n");
}else{ //node DOES exist
    length = LinkedListLength(temp);

    if(length < pos){ //if length < position Node does not exist
        printf("ERROR: Node does not exist!\n");
    }else{
        if(pos == 0){
            newNode = temp->next;
        }else if(pos == 1){
            newNode = temp->next;
        }else{
            for(i = 1; i < pos; i++){
                printf("i = %d\n", i);
                temp = temp->next;
                newNode->next;
            }
            if(temp->next == NULL){
                newNode = NULL;
            }else{
                newNode = temp->next;
            }
        }
    printf("After: ");
    PrintList(newNode);
    printf("\n");
    }
}
return newNode;
}

编辑#2:代码错误

提前感谢您的帮助。从我的结论来看,我的问题是我没有正确地浏览列表,但我不确定为什么我没有。

【问题讨论】:

  • 想想上面的第一个测试用例会发生什么(当你删除列表中的第一个节点时)。如果你把它画出来,你应该可以看到它......
  • @maerics:是的,这是作业,抱歉我没有说明,但我确实做了多次可靠的尝试。我的机构确实允许帮助,显然不允许复制粘贴。如果它有帮助,我不只是在寻找答案,我实际上很好奇为什么我的代码不起作用,因为据我所知,它应该正确地通过他的列表。
  • @nithins:也许我应该回到只使用 temp 结构而不是使用 newNode ?无论如何,我希望代码if(pos == 1) 做的是检查它的第一个节点是否是,然后将指针移动到第二个节点,这样你就不再有第一个节点 = 1 而是 = 3。第一次检查有效正确(除非它以后会引起问题?)
  • 这不能直接粘贴您的代码,因为语句newNode-&gt; = NULL; 甚至不会编译。粘贴你实际编译的代码。

标签: c data-structures struct linked-list


【解决方案1】:

在你的代码中,你有一行

newNode->next;

在您的 for 循环中。该操作没有任何作用。

你也有

newNode-> = NULL;

这不是有效的 C,我不知道你是如何编译的。

但实际上,不要使用那个循环。链表是最基本的递归数据结构之一。因此,几乎所有操作它们的算法都是最优雅的递归解决方案。

typedef struct node node_t;

node_t* delete_at_index(node_t* head, unsigned i)
{
    node_t* next;

    if(head == NULL)
        return head;

    next = head->next;

    return i == 0
             ? (free(head), next)                                 /* If i == 0, the first element needs to die. Do it. */
             : (head->next = delete_at_index(next, i - 1), head); /* If it isn't the first element, we recursively check the rest. */
}

【讨论】:

  • 感谢您的回答,但不幸的是,这并没有帮助我理解为什么我编写的代码不起作用...
  • 你想错了。循环不仅丑陋,而且导致更多的混乱而不是它的价值。报废它。这最好用递归来表示,并导致三行解决方案。
  • 我知道这是一种丑陋的做法。但这将帮助我理解为什么循环不起作用。我知道在递归方法中,每次我们传递给递归方法以遍历列表时,我们都将头指针移动到下一个指针,当我们到达 i finally == 0 的位置时,我们找到了我们的位置。我明白这一点。再次只是想了解为什么我的循环不能正常工作
  • 我会告诉你,但你必须保证不在你的作业中使用循环。我的眼睛在燃烧。
  • 好吧。如果你告诉我我的循环哪里出错了,我会编写自己的递归方法,因为我通常不使用递归!我什至会更新问题以反映我的循环出了什么问题以及如何修复它以及使用更好的替代方法
【解决方案2】:

从单链表中删除给定节点n可以归结为这个操作:

  • 将指向n 的指针设置为指向n-&gt;next。

您可以将其分解为两个操作:

  • 找到指向n的指针;
  • 将该指针设置为n-&gt;next。

出现复杂情况是因为指向n 的指针可能是列表中前一个节点的p-&gt;next 字段,或者是head 指针(如果n 是列表中的第一个节点) .

您的代码似乎并不完整 - 它从未将任何节点的 -&gt;next 字段设置为任何内容,因此很难说到底出了什么问题。

【讨论】:

  • @Clark Gaebel:嗯,通常情况下,人们想从列表中删除一个节点,但出于其他目的保留节点本身(可能添加到不同的列表中)。我认为处理节点本身是一个概念上不同的操作。
  • 函数名是DeleteNode。我希望它删除节点。另外,检查用例。
  • 啊@Clark 我明白你在说什么释放节点。因此,您的代码使用了 free()。直到现在都没有想过需要这样做。
【解决方案3】:
// Remove list's node located at specified position.
// Arguments:
//  head -- list's head
//  pos -- index of a node to be removed (1-based!!!)

struct node* DeleteNode(struct node* head, int pos) 
{

    struct node* node;
    struct node* prev;
    int length;
    int i;

    printf("DeleteNode: position = %d \nBefore: ", pos);
    PrintList(head);

    // Check position's lower bound. Should be >= 1
    if(pos <= 0) { //node does NOT exist
        printf("ERROR: Node does not exist!\n");
        return head;
    }

    // Seek to the specified node, and keep track of previous node.
    // We need previous node to remove specified node from the list.

    for(i=1, prev = 0, node = head; i < pos && node != 0; i++) {
        prev = node;
        node = node->next;
    }

    // Out of range
    if(0 == node) {
        printf("ERROR: Index out of bounds!\n");
        return head;
    }

    // @node points to a list's node located at index pos 
    // @prev points to a previous node.

    // Remove current node from the list.
    if(0 == prev) {
        head = node->next;
    }
    else {
        prev->next = node->next;
    }
    free(node);

    return head;   
}

【讨论】:

  • 不,它没有。该过程将节点从列表中断开,并将该节点返回给调用者。调用者将释放节点。至少这是原始代码所做的:返回断开连接的节点。无论如何,目的是演示循环的实现。
  • 查看用例。原始代码返回更新后的列表,而不是新删除的节点。否则他为什么要反复分配 llist 呢?
  • @Clark:对。根据“用例”修改代码。
  • nitpick:您正在用 C 语言编写。所有索引都从 0 开始。为什么要从 1 开始?另外,如果无符号值会出错,为什么要对位置进行签名?
  • 我的示例说明了在已发布问题的上下文中实现循环。在问题位置索引的上下文中,索引是从 1 开始的。
【解决方案4】:

您的 DeleteNode 不会删除节点,它会从列表的前面删除 pos 节点。因此,您尝试从仅包含 6 个的列表中删除 9 个项目,这当然会导致一个空列表 (NULL)。此外,您的代码过于复杂,并且包含以前尝试的残余。请不要对自己或对我们这样做;提供简单干净的代码,它会更容易理解和修复。

【讨论】:

    【解决方案5】:

    发现你的 for 循环没有到达你想要的位置。 更好地使用等于号来表示它将起作用的约束。 例如

    for (i=1;i<=position-1;i++)
    {
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-24
      • 1970-01-01
      • 2019-05-10
      • 2021-07-25
      • 1970-01-01
      • 1970-01-01
      • 2016-01-11
      相关资源
      最近更新 更多