【问题标题】:Move node to a new index in a linked list将节点移动到链表中的新索引
【发布时间】:2020-06-29 14:53:54
【问题描述】:

我正在尝试更改链表中的索引.... 就像是: 我有链表:1->2->3->4->END,用户插入第二个节点(2)和索引 4。

函数会给我们结果:1->3->4->2->END。

我知道算法是:

  1. 找到节点
  2. 剪掉它
  3. 找到插入的地方
  4. 插入

但我不能让它工作...... 到目前为止,我的函数代码是:

void changeIndex(FrameNode** head, char* name, int index)
{
    FrameNode* temp = NULL;
    FrameNode* curr = *head;
    FrameNode* node = *head;

    int counter = 1;
    int flag = 0;


    while (node && flag == 0)
    {
        if (strcmp(node->frame->name, name) == 0)
        {
            flag = 1;
        
        }
        else
        {
            node = node->next;
        }
    }

    
    while (counter != index)
    {

        counter++;
        temp = curr;
        curr = curr->next;
    }

    
    temp->next = node;
    curr->next = node->next;
    node->next = curr;
}

我找不到问题所在... 我搜索并找到了这个- Change index in a linked list in c 但它只提供算法,我无法编码。 请帮忙...

【问题讨论】:

  • 你能展示一些失败的例子吗?也许描述你的逻辑/方法。如果存在与节点名称匹配的重复项会怎样?谢谢。

标签: c linked-list


【解决方案1】:

对于初学者,我建议使用 0 索引而不是 1 索引,因此我在整个示例中进行了逻辑修改。

我建议将问题分解为几个步骤:

  1. 编写一个函数来删除并返回给定name 字符串的节点。
  2. 编写一个函数以在索引处添加一个节点。

这样,每个函数都更容易编写和验证。

删除节点的逻辑涉及遍历列表以使用strcmp(如您所做的那样)查找节点并跟踪前一个节点。一旦循环终止,如果前一个节点存在,则将其next 设置为下一个节点。如果不存在prev 节点,那么我们有一个空列表,或者我们正在尝试移除头部,这分别涉及什么都不做或将*head 设置为下一个。

在索引处添加节点的逻辑类似:将带有prev 节点的列表遍历到索引或运行器节点为空(不清楚要对索引超出范围错误采取什么操作)。当循环终止时,我们再次根据是否有prev 移动指针,如果没有,是否有*head

这里有一个完整的例子来说明如何处理这个问题:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Node {
    char *name;
    struct Node *next;
};

void print_list(struct Node *head) {
    for (; head; head = head->next) {
        printf("%s->", head->name);
    }

    puts("");
}

struct Node *remove_node_by_name(struct Node **head, char *name) {
    struct Node *prev = NULL;
    struct Node *curr = *head;

    for (; curr && strcmp(curr->name, name); prev = curr, curr = curr->next);

    if (curr && prev) {
        prev->next = curr->next;
    }
    else if (curr) {
        *head = (*head)->next;
    }

    return curr;
}

void add_node_at_index(struct Node **head, struct Node *to_add, int index) {
    struct Node *prev = NULL;
    struct Node *curr = *head;

    for (; curr && index--; prev = curr, curr = curr->next);

    if (prev) {
        prev->next = to_add;
        to_add->next = curr;
    }
    else if (*head) {
        to_add->next = *head;
        *head = to_add;
    }
}

void change_index(struct Node **head, char *name, int index) {
    struct Node *removed = remove_node_by_name(head, name);

    if (removed && *head) {
        add_node_at_index(head, removed, index);
    }
    else if (removed) {
        *head = removed;
    }
}

int main(int argc, char **argv) {
    if (argc != 4) {
        puts("usage: ./llswap [nodelist] [node name] [new index]"
             "\nex: ./llswap abc b 2");
        return 0;
    }

    struct Node *head = NULL;
    struct Node *curr = NULL;

    for (int i = 0; i < strlen(argv[1]); i++) {
        struct Node *node = malloc(sizeof(*node));

        if (!node) {
            fprintf(stdout, "%s:%d malloc failed\n", __FILE__, __LINE__);
            exit(1);
        }

        node->next = NULL;
        node->name = malloc(2);

        if (!node->name) {
            fprintf(stdout, "%s:%d malloc failed\n", __FILE__, __LINE__);
            exit(1);
        }

        node->name[1] = '\0';
        strncpy(node->name, &argv[1][i], 1);

        if (!head) {
            head = node;
        }
        else {
            curr->next = node;
        }

        curr = node;
    }
    
    printf("before: ");
    print_list(head);
    change_index(&head, argv[2], atoi(argv[3]));
    printf("after:  ");
    print_list(head);
    
    while (head) {
        struct Node *tmp = head;
        head = head->next;
        free(tmp->name);
        free(tmp);
    }

    return 0;
}

一些示例运行:

$ ./llswap abc b 2
before: a->b->c->
after:  a->c->b->
$ ./llswap abc a 2
before: a->b->c->
after:  b->c->a->
$ ./llswap abc a 3
before: a->b->c->
after:  b->c->a->
$ ./llswap abcd d 0
before: a->b->c->d->
after:  d->a->b->c->
$ ./llswap a d 0
before: a->
after:  a->
$ ./llswap a a 0
before: a->
after:  a->
$ ./llswap a a 2
before: a->
after:  a->
$ ./llswap ab a 2
before: a->b->
after:  b->a->
$ ./llswap ab a 1
before: a->b->
after:  b->a->
$ ./llswap ab b 1
before: a->b->
after:  a->b->

【讨论】:

    【解决方案2】:

    我没有运行这个,但我认为这是你需要做的......(另外,我建议使用对你正在做的操作更有意义的变量名。)

    您需要在您要移动的节点之前维护一个指向该节点的临时指针,以便您可以将它连接到您要移动的节点之后的节点。

    完成拼接后,使用beforeIndex 将节点插入到正确的索引处,然后将最初位于索引处的节点重新连接为刚刚移动的节点之后的下一个节点

    void changeIndex(FrameNode** head, char* name, int index)
    {
        FrameNode* beforeMoved = NULL;
        FrameNode* beforeIndex = NULL;
        FrameNode* atIndex = *head;
        FrameNode* toMove = *head;
    
        int counter = 0;
        int flag = 0;
    
    
        while (toMove && flag == 0)
        {
            if (strcmp(toMove->frame->name, name) == 0)
            {
                flag = 1;
            
            }
            else
            {
                beforeMoved = toMove;
                toMove = toMove->next;
            }
        }
    
        
        while (atIndex && (counter != index))
        {
    
            counter++;
            beforeIndex = atIndex;
            atIndex = atIndex->next;
        }
    
        if(toMove && (atIndex || index+1 == counter) && (toMove != atIndex))
        {
            if(beforeMoved == NULL)
                *head = (*head)->next;
            else
                beforeMoved->next = toMove->next;   // splice moving node out of linked list
            
            if(beforeIndex == NULL)
                *head = toMove;
            else
                beforeIndex->next = toMove;         // add moving node to correct location
    
            toMove->next = atIndex;             // reconnect node previously at index
        }
    }
    

    【讨论】:

    • 仅供参考,对于初学者来说,当您要交换的节点是头部时,这将不起作用。
    • 它非常接近我的需要。只是一点点改变..谢谢!
    • @ggorlen 很好,我没有考虑边缘情况。为了完整起见,我稍后会更新
    • 我希望您添加它。我正在为边缘情况尝试一些东西,但它似乎不起作用
    • @dolevtobii 我实际上会接受 ggorlen 的帖子作为答案。它可以更好地处理边缘情况......即使使用我的更新,创建小函数来完成单个任务(如删除节点和插入节点)确实是更好的做法
    猜你喜欢
    • 1970-01-01
    • 2014-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-05
    • 2015-05-08
    相关资源
    最近更新 更多