我正在创建一个链接列表,就像我上一个问题一样.我发现开发链表的最好方法是将头部和尾部放在另一个结构中.我的产品结构将嵌套在这个结构中.我应该将列表传递给添加和删除功能.我发现这个概念令人困惑.
我已经实现了initialize,add和clean_up.但是,我不确定我是否正确地做到了这一点.
当我将产品添加到列表中时,我使用calloc声明了一些内存.但我想我不应该为产品声明内存.我对此添加感到困惑.
非常感谢任何建议,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PRODUCT_NAME_LEN 128
typedef struct product_data
{
int product_code;
char product_name[PRODUCT_NAME_LEN];
int product_cost;
struct product_data_t *next;
}product_data_t;
typedef struct list
{
product_data_t *head;
product_data_t *tail;
}list_t;
void add(list_t *list, int code, char name[], int cost);
void initialize(list_t *list);
void clean_up(list_t *list);
int main(void)
{
list_t *list = NULL;
initialize(list);
add(list, 10, "Dell Inspiron", 1500);
clean_up(list);
getchar();
return 0;
}
void add(list_t *list, int code, char name[], int cost)
{
// Allocate memory for the new product
list = calloc(1, sizeof(list_t));
if(!list)
{
fprintf(stderr, "Cannot allocated memory");
exit(1);
}
if(list)
{
// First item to add to the list
list->head->product_code = code;
list->head->product_cost = cost;
strncpy(list->head->product_name, name, sizeof(list->head->product_name));
// Terminate the string
list->head->product_name[127] = '/0';
}
}
// Initialize linked list
void initialize(list_t *list)
{
// Set list node to null
list = NULL;
list = NULL;
}
// Release all resources
void clean_up(list_t *list)
{
list_t *temp = NULL;
while(list)
{
temp = list->head;
list->head = list->head->next;
free(temp);
}
list = NULL;
list = NULL;
temp = NULL;
}
Run Code Online (Sandbox Code Playgroud)
==============================编辑=================== =========
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PRODUCT_NAME_LEN 64
// typedef struct product_data product_data_t;
typedef struct product_data
{
int product_code;
char product_name[PRODUCT_NAME_LEN];
int product_cost;
}product_data_t;
typedef struct list
{
struct list *head;
struct list *tail;
struct list *next;
struct list *current_node;
product_data_t *data;
}list_t;
void add(list_t *list, int code, char name[], int cost);
int main(void)
{
list_t *list = NULL;
list = initialize(list);
add(list, 1001, "Dell Inspiron 2.66", 1299);
add(list, 1002, "Macbook Pro 2.66", 1499);
clean_up(list);
getchar();
return 0;
}
void add(list_t *list, int code, char name[], int cost)
{
/* Allocate memory for the new product */
product_data_t *product = (product_data_t*) calloc(1, sizeof(*product));
if(!product)
{
fprintf(stderr, "Cannot allocate memory.");
exit(1);
}
/* This is the first item in the list */
product->product_code = code;
product->product_cost = cost;
strncpy(product->product_name, name, sizeof(product->product_name));
product->product_name[PRODUCT_NAME_LEN - 1] = '\0';
if(!list->head)
{
/* Assign the address of the product. */
list = (list_t*) product;
/* Set the head and tail to this product */
list->head = (list_t*) product;
list->tail = (list_t*) product;
}
else
{
/* Append to the tail of the list. */
list->tail->next = (list_t*) product;
list->tail = (list_t*) product;
}
/* Assign the address of the product to the data on the list. */
list->data = (list_t*) product;
}
Run Code Online (Sandbox Code Playgroud)
可以说,您希望列表数据结构在其存储的数据外部.
说你有:
struct Whatever
{
int x_;
}
然后你的列表结构如下所示:
struct Whatever_Node
{
Whatever_Node* next_
Whatever* data_
}
Ryan Oberoi同样评论,但没有例子.
在您的情况下,头和尾可以简单地指向链表的开头和结尾。对于单链表,实际上只需要头。最基本的是,可以仅使用如下结构来创建链接列表:
typedef struct listnode
{
//some data
struct listnode *next;
}listnodeT;
listnodeT *list;
listnodeT *current_node;
list = (listnodeT*)malloc(sizeof(listnodeT));
current_node = list;
Run Code Online (Sandbox Code Playgroud)
只要 list 始终指向列表的开头并且最后一项的 next 设置为 NULL,就可以使用 current_node 来遍历列表。但有时为了使遍历列表更容易并存储有关列表的任何其他数据,会使用头标记和尾标记,并将其包装到它们自己的结构中,就像您所做的那样。那么你的添加和初始化函数将类似于(减去错误检测)
// Initialize linked list
void initialize(list_t *list)
{
list->head = NULL;
list->tail = NULL;
}
void add(list_t *list, int code, char name[], int cost)
{
// set up the new node
product_data_t *node = (product_data_t*)malloc(sizeof(product_data_t));
node->code = code;
node->cost = cost;
strncpy(node->product_name, name, sizeof(node->product_name));
node->next = NULL;
if(list->head == NULL){ // if this is the first node, gotta point head to it
list->head = node;
list->tail = node; // for the first node, head and tail point to the same node
}else{
tail->next = node; // append the node
tail = node; // point the tail at the end
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,由于它是一个单链表,因此尾部仅在将项目附加到列表时才真正有用。要插入一个项目,您必须从头部开始遍历列表。尾部真正派上用场的是双向链表,它允许您从任一端开始遍历列表。你可以像这样遍历这个列表
// return a pointer to element with product code
product_data_t* seek(list_t *list, int code){
product_data_t* iter = list->head;
while(iter != NULL)
if(iter->code == code)
return iter;
iter = iter->next;
}
return NULL; // element with code doesn't exist
}
Run Code Online (Sandbox Code Playgroud)
很多时候,头和尾是完全构造的节点,它们本身用作标记来表示列表的开始和结束。它们本身不存储数据(更确切地说,它们的数据代表哨兵令牌),它们只是正面和背面的占位符。这可以更轻松地编写一些处理链表的算法,但代价是必须有两个额外的元素。总的来说,链表是灵活的数据结构,有多种实现方法。
哦,是的,尼克是对的,使用链表是掌握指针和间接的好方法。它们也是练习递归的好方法!熟练使用链表后,接下来尝试构建一棵树并使用递归来遍历树。