概括不同节点类型的链表

时间:2018-03-06 10:40:56

标签: c linked-list

我有两种或更多种不同类型的结构使用它们自己的节点类型的链表,以及我注意到检索,删除,插入和检查节点是否存在的代码在所有结构中是相同的代码越来越复杂。还有更好的方法吗?

Cat House

typedef struct Cat Cat;
struct Cat {};

typedef struct CatNode CatNode;
struct CatNode {
    char *name;
    Cat *cat;
    CatNode *next;
};

typedef struct CatHouse CatHouse;
struct CatHouse {
    CatNode *cats;
    Proxy *(*getCat)(const CatHouse *self, const char *name);
    bool (*hasCat)(const CatHouse *self, const char *name);
    Proxy *(*remove)(CatHouse *self, const char *name);
};

狗屋

typedef struct Dog Dog;
struct Dog {};

typedef struct DogNode DogNode;
struct DogNode {
    char *name;
    Dog *dog;
    DogNode *next;
};

typedef struct DogHouse DogHouse;
struct DogHouse {
    DogNode *dogs;
    Dog *(*getDog)(const DogHouse *self, const char *name);
    bool (*hasDog)(const DogHouse *self, const char *name);
    Dog *(*remove)(DogHouse *self, const char *name);
};

以下是两个实体之间重复实施的部分内容。

我很好,如果复制是如何完成的,我也想知道如何在商业项目中处理链接列表,他们有多个实体结构,每个都有自己的链接列表,可能还有多个?

static bool hasCat(const Cat *self, const char *name) {
    CatNode *cursor = self->cats;
    while (cursor != NULL && strcmp(cursor->name, name) != 0)
        cursor = cursor->next;
    return cursor != NULL;
}


static bool hasDog(const Dog *self, const char *name) {
    DogNode *cursor = self->dogs;
    while (cursor != NULL && strcmp(cursor->name, name) != 0)
        cursor = cursor->next;
    return cursor != NULL;
}

除了类型不同之外,其他功能也同样重复。

1 个答案:

答案 0 :(得分:1)

您可以使用C通用性来拥有一个可以容纳您想要的任何内容的链接列表。

这样做的一种方法是:

typedef struct link {
    void        *data;
    struct link *previous;
    struct link *next;
} link_s;

typedef struct list {
    link_s *head;
    link_s *tail;
    size_t nbLink;

    /* function pointer */
    int    (*Data_Compare)(const void *data1, const void *data2);
    void   (*Data_Destructor)(void *data);
} list_s;

然后,你必须提供一个用来知道哪些"数据"是低于,等于或高于另一个(Data_Compare函数指针,就像strcmp一样),并且你可以提供一个能够" destroy"您的数据(例如,您进行了内存分配)。

之后,你可以拥有一个"数据"成为你" cat"的联盟和#34;狗"结构,允许有一个链接列表阻止所有,或者你可以有两个链表,一个用于" cat",另一个用于" dog" (介意为两者提供良好的Data_Compare。)

在我的实现中,我提供了以下函数来操作list_s:

void List_Constructor(list_s *self, int (*Data_Compare)(const void *data1, const void *data2), void (*Data_Destructor)(void *data));
void List_Destructor(list_s *self);

bool List_Add(list_s *self, void *data);

void *List_RemoveByLink(list_s *self, link_s *link);
void *List_RemoveByData(list_s *self, void *data);
void *List_RemoveByCondition(list_s *self, bool (*Data_Condition)(const void *data));

void List_DestroyByLink(list_s *self, link_s *link);
/* Delete all the link corresponding to data */
void List_DestroyByData(list_s *self, void *data);
/* Delete all the link which condition is true */
void List_DestroyByCondition(list_s *self, bool (*Data_Condition)(const void *data));

void List_Sort(list_s *self);
void List_Merge(list_s *to, list_s *from);
void List_Reverse(list_s *self);

编辑:

为了通过以下示例获得线程安全功能,您可以这样做:

typedef struct ts_list {
  list_s          list;
  pthread_mutex_t mutex;
} ts_list_s;

void TsList_Constructor(ts_list_s *self, int (*Data_Compare)(const void *data1, const void *data2), void (*Data_Destructor)(void *data));
void TsList_Destructor(ts_list_s *self);

bool TsList_Add(ts_list_s *self, void *data);

void *TsList_RemoveByLink(ts_list_s *self, link_s *link);
void *TsList_RemoveByData(ts_list_s *self, void *data);
void *TsList_RemoveByCondition(ts_list_s *self, bool (*Data_Condition)(const void *data));

void TsList_DestroyByLink(ts_list_s *self, link_s *link);
void TsList_DestroyByData(ts_list_s *self, void *data);
void TsList_DestroyByCondition(ts_list_s *self, bool (*Data_Condition)(const void *data));

void TsList_Sort(ts_list_s *self);
void TsList_Merge(ts_list_s *to, ts_list_s *from);
void TsList_Reverse(ts_list_s *self);

// Addtionnal function, for comfort
bool TsList_LockMutex(ts_list_s *self);
bool TsList_UnlockMutex(ts_list_s *self);

所有TsList_ *函数看起来像:

bool TsList_Add(ts_list_s *self, void *data)
{
  bool returnFunction;

  if (!TsList_LockMutex(self)) {
    return (false);
  }

  returnFunction = List_Add(&self->list, data);

  if (!TsList_UnlockMutex(self)) {
    // Big critical log, because from this point, there will be deadlock
  }
  return (returnFunction);
}

当然,你必须非常谨慎,特别是对于" List_Merge"函数,因为你必须在合并之前锁定两个列表。