【问题标题】:C - Merge Two Linked ListsC - 合并两个链表
【发布时间】:2016-09-14 21:20:00
【问题描述】:

问题

我正在尝试合并两个链表。它们每个都有包含开始和结束节点的标题。这就是功能。它返回一个带有新合并链表的标题;它将两个将要合并的链表作为参数。

我找不到我做错了什么。当返回合并的标头并使用函数从其标头打印链接列表时,它将永远在循环中打印两个节点。代码中使用的所有功能都运行良好;已经在软件的其余部分中进行了测试。

合并函数

header * merge_lists (header * h1, header * h2) {
  header * h3 = init_header();
  node * curr1 = h1->first;
  node * curr2 = h2->first;
  node * result;

  while (1) {
    if (curr1 == NULL && curr2 == NULL) break;
    if (curr1 == NULL){
      result = curr2;
      curr2 = curr2->next;
    }
    else if (curr2 == NULL){
      result = curr1;
      curr1 = curr1->next;
    }
    else if (curr1->name[0] > curr2->name[0]){
      result = curr1;
      curr1 = curr1->next;
    }
    else if (curr1->name[0] <= curr2->name[0]) {
      result = curr2;
      curr2 = curr2->next;
    }
    insert_beginning(h3, result);
  }
  return h3;
}

打印功能

void print_list (header * head) {
  node * current = head->first;
  while (current != NULL){
    printf("%s %d\n", current->name, current->age);
    current = current->next;
  }
}

在开头插入函数

void insert_beginning (header * head, node * new_node) {
  if (head->quantity == 0){
    head->first = new_node;
    head->last = new_node;
    head->quantity++;
    return;
  }

  new_node->next = head->first;
  head->first = new_node;
  new_node->next->prev = new_node;
  head->quantity++;
}

节点结构

typedef struct node_struct {
  char name[30];
  int age;
  struct node_struct * prev;
  struct node_struct * next;
} node;

【问题讨论】:

  • curr-&gt;name 属于什么类型?如果NULL 中的任何一个是NULLif (curr1 == NULL &amp;&amp; curr2 == NULL) break 就会中断,因此您最终可能会在表格中留下一些数据。
  • curr1 的情况为 NULL,curr2 不为 NULL:if (curr1 == NULL &amp;&amp; curr2 == NULL) break; ==> if (curr2 == NULL || curr1-&gt;name[0] &gt; curr2-&gt;name[0]){curr1(NULL)-&gt;name[0] 哎呀!
  • @Vitor 通过更改您的代码,我们有一个移动的目标,这会使您的帖子不清楚您在问什么。建议恢复到原来的代码。
  • still looping forever : 也许,我认为链接的创建有问题。
  • @VitorCosta 您需要发布minimal, complete, and verifiable example“side bugs”,和“copy wrong in post”,还有丢失的代码只是浪费大家的时间。

标签: c linked-list


【解决方案1】:

您的插入代码似乎至少有一个错误:

void insert_beginning (header * head, node * new_node) {
  if (head->quantity == 0){
    head->first = new_node;
    head->last = new_node;
    head->quantity++;
    return;
  }

  // NOTE/BUG: this links new_node to itself
#if 0
  head->first = new_node;
  new_node->next = head->first;
  // NOTE/FIX: this is the correct way
#else
  new_node->next = head->first;
  head->first = new_node;
#endif

  // NOTE/BUG?: what about end of list?
#if 0
  new_node->next->prev = new_node;
#else
  if (new_node->next != NULL)
    new_node->next->prev = new_node;
#endif

  head->quantity++;
}

更新:

我刚刚在帖子中复制错误的第一个错误,对不起。

好吧,够公平的。

但第二个:此时new_node-&gt;next 不可能是NULL,因为它总是会在开头插入,并且下一个节点总是已经有另一个节点。

我认为这是问题的间接部分。

我已经让您的代码工作并生成了一个测试程序。我不得不创建一些缺少的函数和结构。

我编写了一个不同的合并函数:merge_lists2。最大的区别之一是它不只是(例如)curr1 = curr1-&gt;next,而是调用一个新函数,该函数会移出第一个元素 [如果需要] 删除所有旧的 next/prev 链接。

这是在一个新函数list_shift 中完成的。特别是,请参阅该函数中的 NOTE/BUG 注释。

无论如何,这是更新后的工作代码:

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

typedef struct node_struct {
    char name[30];
    int age;
    struct node_struct *prev;
    struct node_struct *next;
} node;

typedef struct header_struct {
    node *first;
    node *last;
    int quantity;
} header;

void
print_list(header * head, const char *sym)
{
    node *current = head->first;

    printf("%s [fwd]:\n", sym);

    while (current != NULL) {
        printf("  %s %d\n", current->name, current->age);
        current = current->next;
    }
}

void
print_rlist(header * head, const char *sym)
{
    node *current = head->last;

    printf("%s [rev]:\n", sym);

    while (current != NULL) {
        printf("  %s %d\n", current->name, current->age);
        current = current->prev;
    }
}

void
insert_beginning(header * head, node * new_node)
{

#if 1
    new_node->prev = NULL;
#endif

    if (head->quantity == 0) {
        head->first = new_node;
        head->last = new_node;
        head->quantity++;
        return;
    }

    // NOTE/BUG: this links new_node to itself
#if 0
    head->first = new_node;
    new_node->next = head->first;
    // NOTE/FIX: this is the correct way
#else
    new_node->next = head->first;
    head->first = new_node;
#endif

    // NOTE/BUG?: what about end of list?
#if 0
    new_node->next->prev = new_node;
#else
    if (new_node->next != NULL)
        new_node->next->prev = new_node;
#endif

    head->quantity++;
}

void
insert_string(header * h, const char *str)
{
    node *ptr = calloc(1, sizeof(*ptr));

    strcpy(ptr->name, str);

    insert_beginning(h, ptr);
}

header *
init_header(void)
{
    header *h = calloc(1, sizeof(*h));

    return h;
}

header *
merge_lists1(header * h1, header * h2)
{
    header *h3 = init_header();
    node *curr1 = h1->first;
    node *curr2 = h2->first;
    node *result;

    while (1) {
        if (curr1 == NULL && curr2 == NULL)
            break;
        if (curr1 == NULL) {
            result = curr2;
            curr2 = curr2->next;
        }
        else if (curr2 == NULL) {
            result = curr1;
            curr1 = curr1->next;
        }
        else if (curr1->name[0] > curr2->name[0]) {
            result = curr1;
            curr1 = curr1->next;
        }
        else if (curr1->name[0] <= curr2->name[0]) {
            result = curr2;
            curr2 = curr2->next;
        }
        insert_beginning(h3, result);
    }
    return h3;
}

node *
list_shift(header * h, node * cur)
{

    do {
        // bug out if we do _not_ yet need to dequeue an element from this list
        if (cur != NULL)
            break;

        // bug out if we're at the end of the list
        cur = h->first;
        if (cur == NULL)
            break;

        // fix the head chain pointer
        h->first = cur->next;

        // fix the tail chain pointer
        if (cur == h->last)
            h->last = NULL;

        cur->prev = NULL;

        // NOTE/BUG: the smoking gun -- adding this fixed things
        cur->next = NULL;
    } while (0);

    return cur;
}

header *
merge_lists2(header * h1, header * h2)
{
    header *h3 = init_header();
    node *curr1 = NULL;
    node *curr2 = NULL;
    node *result;

    while (1) {
        curr1 = list_shift(h1, curr1);
        curr2 = list_shift(h2, curr2);

        if ((curr1 == NULL) && (curr2 == NULL))
            break;

        if (curr1 == NULL) {
            result = curr2;
            curr2 = NULL;
        }
        else if (curr2 == NULL) {
            result = curr1;
            curr1 = NULL;
        }
        else if (curr1->name[0] > curr2->name[0]) {
            result = curr1;
            curr1 = NULL;
        }
        else {
            result = curr2;
            curr2 = NULL;
        }

        insert_beginning(h3, result);
    }

    return h3;
}

// main -- main program
int
main(int argc, char **argv)
{
    char *cp;

    --argc;
    ++argv;

    for (; argc > 0; --argc, ++argv) {
        cp = *argv;
        if (*cp != '-')
            break;

        switch (cp[1]) {
        default:
            break;
        }
    }

    header *h1 = init_header();

    insert_string(h1, "jkl");
    insert_string(h1, "def");
    print_list(h1, "h1");
    print_rlist(h1, "h1");

#if 1
    header *h2 = init_header();

    insert_string(h2, "ttt");
    insert_string(h2, "ghi");
    insert_string(h2, "abc");
    print_list(h2, "h2");
    print_rlist(h2, "h2");
#endif

#if 0
    header *h3 = merge_lists1(h1, h2);

    print_list(h3, "h3");
    print_rlist(h3, "h3");
#endif

#if 1
    header *h3 = merge_lists2(h1, h2);

    print_list(h3, "h3");
    print_rlist(h3, "h3");
#endif

    return 0;
}

旁注:你只是比较字符串的第一个字符,所以你可能想使用strcmp

【讨论】:

  • 第一个bug我刚刚在帖子里复制错了,对不起。但是第二个:此时 new_node->next 不可能为 NULL,因为它总是会在开头插入,并且下一个总是已经有另一个节点。
猜你喜欢
  • 1970-01-01
  • 2021-02-26
  • 1970-01-01
  • 1970-01-01
  • 2011-01-21
相关资源
最近更新 更多