我无法在 C 中创建链表

I cannot create a linked list in C

基本上,对于我的作业,我需要实现代码来进行霍夫曼编码。为此,我需要将输入作为一个字符串,然后创建一个字符列表及其频率。当有新角色时,我需要创建一个新节点。我试过用 C 来做,但没有结果。当我尝试打印我的链接列表时,我根本无法获得任何输出。我相信我从一开始就没有创建列表。 我的 C 代码如下:

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

struct node {
    char character;
    int frequency;
    struct node *next;
}head;

struct node *insert(int frequency, char character) {
    struct node *newNode = malloc(sizeof(struct node));
    newNode->character = frequency;
    newNode->character = character;
    return newNode;
}

void create_freq_list(struct node *initial, int str_size, char str[]) {
    int i;
    struct node *temp;
    bool has_node;
    for (i = 0; i < str_size; i++) {
        temp = initial;
        has_node = false;
        while (temp->next != NULL) {
            if (temp->character == str[i]) {
                has_node = true;
                temp->frequency++;
            }
            temp = temp->next;
        }

        if (has_node == false) {
            while (temp->next != NULL) {
                temp = temp->next;
                if (temp->next == NULL) {
                    temp->next = insert(0, str[i]);
                }
            }
        }
    }
}

int main() {
    struct node *temp;
    char str[100];
    gets_s(str, 100);
    create_freq_list(&head, 100, str);

    temp = &head;
    while (temp->next != NULL) {
        printf("'%c' : %d", temp->character, temp->frequency);
        temp = temp->next;
    }

    getch();
    exit(0);
}

您的代码中存在多个问题:

  • 您对 head 节点的处理不正确:head 应定义为 node * 并且您应将其地址传递给 create_freq_list().
  • insert()函数中有错别字:newNode->character = frequency;
  • 您不应迭代字符串中超出空终止符的字符。
  • 输出循环不正确:它应该迭代 while (head),而不是 while (head->next)。按照编码,输出初始节点但无意义,最后一个节点被忽略。

这是修改后的版本:

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

struct node {
    char character;
    int frequency;
    struct node *next;
};

struct node *insert(int frequency, char character) {
    struct node *newNode = malloc(sizeof(struct node));
    if (newNode != NULL) {
        newNode->frequency = frequency;
        newNode->character = character;
    }
    return newNode;
}

void create_freq_list(struct node **headp, const char str[]) {
    for (int i = 0; str[i]; i++) {
        struct node **tailp = *headp;
        struct node *temp;
        while ((temp = *tailp) != NULL) {
            if (temp->character == str[i]) {
                temp->frequency++;
                break;
            }
            tailp = &temp->next;
        }
        if (temp == NULL) {
            *tailp = insert(1, str[i]);
        }
    }
}

int main() {
    struct node *head = NULL;
    char str[100];
    gets_s(str, 100);
    create_freq_list(&head, str);

    for (struct node *temp = head; temp != NULL; temp = temp->next) {
        printf("'%c': %d\n", temp->character, temp->frequency);
    }

    getch();
    return 0;
}

请注意,使用包含 256 个元素的数组来计算字符频率要简单得多。

我可以提出一个变体,使用优秀的宏<sys/queue.h> 这不是一个标准的包含,但每个打包好的系统都应该有它。 好吧,它可能不如手动编写链表编码那么具有教学意义,但它更安全;-) 查看 man queue(或 man LIST_INIT)以查看功能。

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

#include <sys/queue.h>

typedef LIST_HEAD(listhead, entry) nodes_t;

typedef struct entry {
  char character;
  int frequency;
  LIST_ENTRY(entry) entries;
} node_t;


void insert(nodes_t *list, char character) {
  node_t *newNode = malloc(sizeof(node_t));
  if (newNode != NULL) {
    newNode->frequency = 1;
    newNode->character = character;
    LIST_INSERT_HEAD(list, newNode, entries);
  }
}

node_t *get_node(nodes_t *list, char character) {
  node_t *n;
  LIST_FOREACH(n, list, entries)
    if (n->character == character)
      return n;
  return NULL;
}

void create_freq_list(nodes_t *list, const char str[]) {
  node_t *n;
  for (int i = 0; str[i]; i++) {
    n = get_node(list, str[i]);
    if (n == NULL)
      insert(list, str[i]);
    else
      n->frequency++;
  }
}

void print_list(nodes_t *list) {
  node_t *n;
  LIST_FOREACH(n, list, entries)
    printf("'%c': %d\n", n->character, n->frequency);
}


int main(int argc, char* argv[]) {
  nodes_t list;

  if (argc != 2) {
    fprintf(stderr, "Usage: %s <string>\n", argv[0]);
    return -1;
  }
  
  LIST_INIT(&list);
  
  create_freq_list(&list, argv[1]);

  print_list(&list);
  
  return 0;
}