gpt4 book ai didi

c - 纯 C 中的“多用途”链表实现

转载 作者:太空狗 更新时间:2023-10-29 16:23:19 25 4
gpt4 key购买 nike

这不完全是一个技术问题,因为我对 C 的了解足以完成我需要做的事情(我的意思是,就不要“让语言妨碍你”而言),所以这个问题基本上是一个“采取什么方向”的问题。

情况是:我目前正在上一门高级算法类(class),为了'成长为程序员',我需要使用纯C来实现实际作业(效果很好:几乎任何小错误你make 实际上迫使你完全理解你在做什么以便修复它)。在实现过程中,我显然遇到了必须从头开始实现“基本”数据结构的问题:实际上不仅是链表,还有堆栈、树等。

我在本主题中专注于列表,因为它通常是我最终在程序中大量使用的结构,作为“主要”结构或作为其他更大结构的“辅助”结构(例如,散列使用链表解决冲突的树)。

这要求列表存储许多不同类型的元素。我在这里假设我不想为每种类型重新编码列表。所以,我可以想出这些替代方案:

  • 制作一个空指针列表(有点不雅;更难调试)
  • 只制作一个列表,但将 union 作为“元素类型”,包含我将在程序中使用的所有元素类型(更易于调试;如果元素的大小不一致,则会浪费空间)
  • 使用预处理器宏以 SGLIB 的样式为每种类型重新生成代码,“模仿”C++ 的 STL(创造性的解决方案;不浪费空间;元素在返回时具有明确的类型;列表代码中的任何更改都可能非常显着)
  • 你的想法/解决方案

要明确问题:以上哪一个最好?

PS:由于我基本上处于学术背景,所以我也对业内使用纯 C 的人的观点非常感兴趣。我知道大多数纯 C 程序员都在嵌入式设备领域,我认为我面临的这种问题并不常见。但是,如果有人知道它在“现实世界”中是如何完成的,我会对您的意见非常感兴趣。

最佳答案

void * 在链表中有点麻烦,因为您必须单独管理它对链表本身的分配。我过去使用的一种方法是使用“可变大小”结构,例如:

typedef struct _tNode {
struct _tNode *prev;
struct _tNode *next;
int payloadType;
char payload[1]; // or use different type for alignment.
} tNode;

现在我意识到这不是看起来可变大小但让我们这样分配一个结构:

typedef struct {
char Name[30];
char Addr[50];
} tPerson;
tNode *node = malloc (sizeof (tNode) - 1 + sizeof (tPerson));

现在您有一个节点,就所有意图和目的而言,它看起来像这样:

typedef struct _tNode {
struct _tNode *prev;
struct _tNode *next;
int payloadType;
char Name[30];
char Addr[50];
} tNode;

或者,以图形形式(其中 [n] 表示 n 字节):

+----------------+
| prev[4] |
+----------------+
| next[4] |
+----------------+
| payloadType[4] |
+----------------+ +----------+
| payload[1] | <- overlap -> | Name[30] |
+----------------+ +----------+
| Addr[50] |
+----------+

也就是说,假设您知道如何正确处理负载。这可以按如下方式完成:

node->prev = NULL;
node->next = NULL;
node->payloadType = PLTYP_PERSON;
tPerson *person = &(node->payload); // cast for easy changes to payload.
strcpy (person->Name, "Bob Smith");
strcpy (person->Addr, "7 Station St");

该转换行只是将 payload 字符(在 tNode 类型中)的地址转换为实际 tPerson 有效负载的地址类型。

使用这种方法,您可以在一个节点中携带任何您想要的有效载荷类型,甚至每个节点中的不同有效载荷类型,而不会浪费 union 空间。这种浪费可以通过以下方式看出:

union {
int x;
char y[100];
} u;

每次在列表中存储整数类型时都会浪费 96 个字节(对于 4 字节整数)。

tNode 中的负载类型使您可以轻松检测此节点承载的负载类型,因此您的代码可以决定如何处理它。您可以使用以下内容:

#define PAYLOAD_UNKNOWN     0
#define PAYLOAD_MANAGER 1
#define PAYLOAD_EMPLOYEE 2
#define PAYLOAD_CONTRACTOR 3

或(可能更好):

typedef enum {
PAYLOAD_UNKNOWN,
PAYLOAD_MANAGER,
PAYLOAD_EMPLOYEE,
PAYLOAD_CONTRACTOR
} tPayLoad;

关于c - 纯 C 中的“多用途”链表实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/736307/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com