3

我正在尝试设计一个通用链表,其中每个节点可以存储多个项目,例如颜色、形状和大小。

这就是我的 .h 文件的样子

typedef struct linked{
    char type;
    void * item;
    struct linked * next;
    struct linked * prev;
}LinkedList;

LinkedList * NewLinkedList();
LinkedList * next(Iterator **I);
int hasNext(Iterator *I);
void insertion(LinkedList **a, void *b);
void printStringList(LinkedList *L);
void printIntList(LinkedList *L);
void printDoubleList(LinkedList *L);
void delete(LinkedList *L, void *n);

我应该通过添加 void * item2 和 void * item3 ...来修改结构吗?或者有没有更好的方法来做到这一点。

我的第二个问题是:每次使用 void 指针时都必须对它们进行类型转换吗?这是我的代码printIntList

void printList(LinkedList *L)
{
    LinkedList *tmp = NULL;
    tmp = L;
    while(L)
    {
        printf("%d\n",*(int*)L->item);
        L=L->next;
    }
}

我有printIntList和。有什么办法可以将它们结合起来吗?printDoubleListprintStringList

谢谢!

4

5 回答 5

1

是的,您可能应该使用三个指针,或者某些形状可以没有颜色或大小?如果没有,您应该考虑创建三个指针,每个指针都有它们指向的类型,这样您就不必强制转换和删除类型。

该结构可能如下所示:

typedef struct linked{
    Size * size;
    Color* color;
    Shape* shape;
    struct linked * next;
    struct linked * prev;
}LinkedList;

如果您确实想在一个节点中存储更多相同类型的项目(例如两种颜色......),您应该考虑使用union

要回答第二个问题......是的,你应该在void每次使用它们时都投射指针(至少在你的情况下=)。您应该再次考虑 union 以获得更漂亮的代码......

于 2013-04-02T00:15:14.417 回答
1

我应该通过添加 void * item2 和 void * item3 ...来修改结构吗?或者有没有更好的方法来做到这一点。

这取决于您的列表的通用性。如果它用于保存一些特定的值,您可以创建它们全部,或者为它们创建一个结构,如果它可能保存不同类型的值,您可能想要创建一个联合,如果它可能在一个节点中保存许多值,您可能最好创建一些值数组。

每次使用 void 指针时都必须对它们进行类型转换吗?

当您分配给他们/从他们(int * a = a_void_pointer/ a_void_pointer = an_int_pointer)时 - 否

当您取消引用这样的指针 ( *a_void_pointer) - 是的。

于 2013-04-02T00:15:23.387 回答
1

您可以使用可区分的联合类型制作通用列表:

typedef struct listitem
{
  char type;
  union
  {
    integer i;
    double d;
    char *s;
    // etc.
  } u;
} Listitem;

在您的 LinkedList 中使用此列表项。

于 2013-04-02T00:18:16.290 回答
1

你可以这样做:

typedef struct links {
    struct links * next;
    struct links * prev;
} links;

typedef struct outer_node {
  links l; // links to outer_node.l
  struct inner_node * children;
} outer_node;

typedef struct inner_node {
  links l; // links to inner_node.l
  char type;
  void * item;
} inner_node;

基本上,你有一个链表,它的每个节点都是它自己的链表。

两个列表都使用相同类型的链接进行组织,因此您无需复制链接/取消链接代码。

您将需要使用offsetof()宏从指向links其容器的指针inner_nodeouter_node.

这是一个完整的演示:

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

typedef struct links {
    struct links * next;
    struct links * prev;
} links;

typedef struct outer_node {
  links l; // links to outer_node.l
  struct inner_node * children;
} outer_node;

typedef struct inner_node {
  links l; // links to inner_node.l
  char type;
  void * item;
} inner_node;

void linkNodes(links* l1, links* l2)
{
  links* tmp = l1->prev;
  l1->next->prev = l2->prev;
  l1->next = l2;

  l2->prev->next = tmp;
  l2->prev = l1;
}

inner_node* createNode(char type, void* item, inner_node* sibling)
{
  inner_node* n = malloc(sizeof(*n));
  n->type = type;
  n->item = item;
  n->l.prev = &n->l;
  n->l.next = &n->l;
  if (sibling != NULL)
    linkNodes(&n->l, &sibling->l);
  return n;
}

outer_node* createOuterNode(inner_node* child, outer_node* sibling)
{
  outer_node* n = malloc(sizeof(*n));
  n->l.prev = &n->l;
  n->l.next = &n->l;
  n->children = child;
  if (sibling != NULL)
    linkNodes(&n->l, &sibling->l);
  return n;  
}

void PrintList(links* l, int level)
{
  links* l2 = l;
  do
  {
    if (level == 0)
    {
      outer_node* n = (void*)((char*)l2 + offsetof(outer_node, l));
      printf("{\n");
      PrintList(&n->children->l, level + 1);
      printf("}\n");
    }
    else
    {
      inner_node* n = (void*)((char*)l2 + offsetof(inner_node, l));
      printf("  type: %d, item: %s\n", n->type, (char*)n->item);
    }
    l2 = l2->next;
  } while (l2 != l);
}

int main(void)
{
  outer_node* root = 
    createOuterNode(
      createNode(0, "something",
        NULL
      ),
      createOuterNode(
        createNode(1, "foo",
          createNode(2, "bar",
            NULL
          )
        ),
        createOuterNode(
          createNode(3, "red",
            createNode(3, "green",
              createNode(3, "blue",
                NULL
              )
            )
          ),
          createOuterNode(
            createNode(4, "cat",
              createNode(5, "dog",
                createNode(6, "raven",
                  createNode(7, "shark",
                    NULL
                  )
                )
              )
            ),
            NULL
          )
        )
      )
    );

  PrintList(&root->l, 0);

  return 0;
}

输出(ideone):

{
  type: 0, item: something
}
{
  type: 1, item: foo
  type: 2, item: bar
}
{
  type: 3, item: red
  type: 3, item: green
  type: 3, item: blue
}
{
  type: 4, item: cat
  type: 5, item: dog
  type: 6, item: raven
  type: 7, item: shark
}
于 2013-04-02T00:20:59.007 回答
1

您需要考虑每个元素定义的项目是否真的是动态的。颜色、尺寸、形状是否限制了您需要存储的物品?

如果这就是您真正需要的,为什么不保持简单并最小化间接/内存分配:

enum ShapeFlags { sizeDefined = 0x01, colorDefined = 0x02, shapeDefined = 0x04 };

typedef struct shapeList {
    ShapeFlags shapeFlags;
    Size  size;
    Color color;
    Shape shape;
    struct Linked * next;
    struct Linked * prev;
} ShapeList;

另一方面,如果您确实拥有一组非常动态的属性,则列表列表的替代方法可能是拥有一个带有哨兵的列表。

enum FieldFlag { terminator = 0x01, size = 0x02, color = 0x04, shape = 0x08 };

typedef struct list
{
  FieldFlag type;
  void* value;
  struct list* next;
  struct list* previous;
} List;

然后,您可以正常迭代并使用terminator标志来了解对象的结尾。

于 2013-04-02T00:37:15.393 回答