【问题标题】:Delete a string out of a linked list of strings从字符串链表中删除一个字符串
【发布时间】:2019-10-21 08:05:57
【问题描述】:

我正在开发一个文字处理器,它被要求能够从单词列表中删除一个单词。

基本上,用户输入单词(因此,字符串),然后将其存储在链表中(这里是dico,这要归功于表示用户输入的所有单词的结构字典)。

不幸的是,我被卡住了:我写的代码似乎只删除了第二个字符,而我希望它能够删除用户请求的单词(这里:str)。

例如,如果用户之前输入了:“hello world”,而他们现在想删除世界“world”,那么 dico 现在应该是“hello”。

typedef struct dll {
    char data;
    int count;      //not needed here
    struct dll* next;
} dll;  //linked list of each character : dll represents one word

typedef struct dictionary {
    dll * data;
    struct dictionary* next;
    struct dictionary* prev;
} dictionary;  //linked list of all the words

dll* entry(){
    char data = getc(stdin);
    if (data != '\n'){
        dll* curr = create_dico(data);
        curr->next=entry();
        return curr;
    }
    return NULL;
}


void suppression(dictionary** dico) {
    printf("Please enter what you wish to remove out of the list: \n");
    dictionary *str = malloc(sizeof(dictionary));
    str->data = entry();
    str->next = NULL;

    dictionary* temp = *dico;

    if (str->data == NULL){
        *dico = temp->next;
        free(temp);
        return;
    }
    while (temp != NULL && temp->data->data == str->data->data) {
        temp = temp->next;
    }
    dictionary *next = temp->next->next;
    free(temp->next);
    temp->next = next;
}

【问题讨论】:

  • 与您的问题无关,但请注意 getc 返回 int 值。这样您就可以检查EOF,它表示文件结束或错误。你真的应该检查一下。
  • 你需要两个循环,一个循环dictionary,另一个循环word in dictionary
  • 建议:与其在循环中创建条目,不如在循环中创建条目 (while(data != \n) { ... })。提示:你需要两个指针,一个指向当前正在创建的列表的头部,一个指向尾部。

标签: c string linked-list


【解决方案1】:

您的删除功能不反映您正在使用的数据结构:链表的链表!

您需要做的第一件事是检测 单词 所在的位置,为此您需要比较两个链表:

// notice: pointer to dll, not dictionary!
dll* str = entry();

dictionary* temp = *dico;
while(temp)
{
    dll* s = str; // you yet need original str for deletion!
    dll* word = temp->data;
    while(word && s && word->data == s->data)
    {
        word = word->next;
        s = s->next;
    }
    // OK, now we need to know if we reached the ends of BOTH word and s
    // -> in that case, both are equal!
    if(!word && !s)
        break;
}

所以我们现在迭代了单词列表。如果我们在里面找到了字符串,我们会提前停止,否则我们会在最后到达空元素。所以:

if(temp)
{
    // we didn't reach end of the words' list -> we found an equal element

    // at first, we'd remove the current word from the linked simply by
    // re-linking predecessor and successor nodes
    // the nice thing about is that you created a doubly linked list
    // so we have both of them available from current node, so:

    if(temp->prev)
        temp->prev->next = temp->next;
    else
        // special case: we are deleting the head node!
        *dico = temp->next;

    if(temp->next)
        temp->next->prev = temp->prev;
    // no else needed, as we haven't a dedicated tail node

    // now we need to delete the word's characters!
    dll* word = temp->data;
    while(word)
    {
        dll* next = word->next;
        free(word);
        word = next;
    }

    // now we yet need to delete the word node itself!
    free(temp);
}

到目前为止很好,列表已调整。不过,我们创建了一个临时引用字符串,它本身也需要再次释放:

while(str)
    // well, just the same as when deleting the word...

当您两次执行相同的操作时,您可能会为...创建一个通用函数

请注意,以上是未经测试的代码,不能保证它没有错误。但它应该足以表明你必须关注的地方......也请注意,这个答案是基于相当多的假设,主要是之前正确创建的列表,如你没有提供minimal reproducible example

【讨论】:

    猜你喜欢
    • 2023-03-14
    • 1970-01-01
    • 2013-03-02
    • 2023-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-24
    相关资源
    最近更新 更多