假设我想创建一个书籍列表,这些书籍有一个或多个作者,以及书中的主要角色。 为此创建结构的最佳方法是什么? 以下设置是准确的,还是不同的设置?
struct name
{
char prefix[5];
char first[50];
char middle[50];
char last[50];
char suffix[5];
struct name *next; /* linked list */
struct name *previous; /* linked list */
};
struct book
{
struct name authors;
struct name main_characters;
char title[100];
char publisher[100];
结构书 *下一页; 结构书 *以前;
};
我认为您的计划很好,使用指针进行authors
和main_characters
.当您对书籍、作者和主要角色使用侵入式链表时,您可能会发现分解链表结构和操作很有帮助。
如果你声明一个这样的结构:
struct node
{
struct node *next;
struct node *previous;
};
typedef struct node node;
您可以将其作为第一个元素嵌入到每个类型中:
struct name
{
node linked_list;
char name_prefix[10];
char name_first[50];
char name_middle[50];
char name_last[50];
char name_suffix[5];
};
struct book
{
node linked_list;
name *authors;
name *main_characters;
/* variables for book */
char title[100]; /* the title of the book */
char publisher[100]; /* publisher */
//etc.
};
这使您的类型可转换为node
类型。然后,您可以根据node
类型定义链表操作:
void
node_add_node(node **head, node *object)
{
if (*head == NULL) {
*head = object;
}
else {
node *current, *previous;
for (current = *head; current != NULL; current = current->next) {
previous = current;
}
previous->next = object;
}
}
然后定义类型安全操作以将书籍添加到书籍列表并将名称添加到书籍:
void
books_add_book(struct book **books, struct book *book)
{
node_add_node((node**)books, (node*)book);
}
void
book_add_author(struct book *book, struct name *author)
{
node_add_node((node**)&book->authors, (node*)author);
}
void
book_add_main_character(struct book *book, struct name *character)
{
node_add_node((node**)&book->main_characters, (node*)character);
}
然后,实现构造函数:
void node_init(node *node)
{
node->previous = NULL;
node->next = NULL;
}
struct book *
book_create(const char *title, const char *publisher)
{
struct book *b = malloc(sizeof(book));
if (b) {
node_init(&b->linked_list);
b->authors = NULL;
b->main_characters = NULL;
strcpy(b->title, title);
strcpy(b->publisher, publisher);
}
return b;
}
struct name *
name_create(const char *prefix, const char *first, const char *middle,
const char *last, const char *suffix)
{
name *n = malloc(sizeof(name));
if (n) {
node_init(&n->linked_list);
strcpy(n->name_prefix, prefix);
strcpy(n->name_first, first);
strcpy(n->name_middle, middle);
strcpy(n->name_last, last);
strcpy(n->name_suffix, suffix);
}
return n;
}
然后你可以创建这样的书(注意:我把你的name_prefix
的大小增加到10):
struct book *books = NULL;
struct book *b = book_create("War and Peace", "Wordsworth");
struct name *n = name_create("Count", "Lev", "Nikolayevich", "Tolstoy", "");
book_add_author(b, n);
n = name_create("Count", "Pyotr", "Kirillovich", "Bezukhov", "");
book_add_main_character(b, n);
n = name_create("Countess", "Natalya", "Ilyinichna", "Rostova", "");
book_add_main_character(b, n);
books_add_book(&books, b);
为此创建结构的最佳方法是什么?
什么是最好的取决于问题的细节,在某种程度上是一个意见问题。
以下设置是准确的,还是不同的设置?
您提出的两种选择看起来都很合理。
第一种选择,两个名字struct
本身就是书struct
的成员,在某些情况下可能更方便一些,因为需要较少的动态分配。 另一方面,它使每个内部链表的第一个元素成为特例,这可能会使您的代码整体上更加复杂。
第二种选择,书籍struct
包含指向两个名称struct
的指针,为您提供了更多的一致性,并且它更好地适应了一个或两个内部列表为空的可能性。 考虑到所有因素,这就是我可能会选择的。
您需要的数据结构大部分时间是根据您拥有的数据类型和要对其执行的操作来决定的。
链表适用于以下需求:
- 频繁插入和删除数据
- 数据量可能不适合一个地方/或第一次可用。
它带有以下问题:
- 搜索和检索数据缓慢
- 在代码中添加更多复杂性和间接性。
据我所知,字符串的动态数组(char 数组)足以满足authors
或者您可以使用指向struct name
的指针数组,如果您关心粒度,因为一本书可能有多个作者。
如果你想要静态数组,以下可以为你做:
#define MAX_AUTHOR_LIMIT 10
struct boook {
...
struct name *authors[MAX_AUTHOR_LIMIT];
int author_count;
...
}
或者,如果你想变得更好,你也可以使用动态数组。
链接列表也是一种替代方法,但是将链接用于不需要频繁插入删除的一小部分数据项并不是一个好主意,但再次根据我指出的那样,您知道应用程序需要做什么根据权衡来决定。