概括不同节点类型的链表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了概括不同节点类型的链表相关的知识,希望对你有一定的参考价值。

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

猫屋

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;
}

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

答案

您可以使用C genericity以获得可以保存任何内容的链接列表。

一种方法是这样的:

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一样),你可以提供一个“破坏”你的数据的函数(如果通过例如,你做了内存分配)。

在那之后,你可以让“数据”成为你的“猫”和“狗”结构的联合,从而允许一个链表保持全部,或者你可以有两个链表,一个用于“猫”,和其他一个“狗”(介意为两者提供良好的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”函数,因为你必须在合并之前锁定两个列表。

以上是关于概括不同节点类型的链表的主要内容,如果未能解决你的问题,请参考以下文章

一文讲透链表操作,看完你也能轻松写出正确的链表代码

一文讲透链表操作,看完你也能轻松写出正确的链表代码

一文讲透链表操作,看完你也能轻松写出正确的链表代码

C - 堆栈分配的链表

windows内核驱动中的链表结构

异质链表