结构设计
传统的单向链表是根据结点开始书写的,数据域存放用户创建数据的指针,假设用户创建的数据仍然是 Person 类型的结构体,传统链表的结构如下图。
typedef struct person {char name [64];int age;} Person;
链表的功能就是将数据连接起来,那么我们不需要非得依托于创建结点来实现数据结构。我们可以在用户端的数据上进行连接(Person 结构体),这样就可以避免多使用一个 void* 指针来指向数据,同时也可以将任意类型的数据连接起来。
typedef struct linkNode {struct linkNode * next;} LinkNode;typedef struct person {struct LinkNode node; // 任意指针都可char name[64];int age;} Person;
用户所做的就是在每个数据顶部上空出一个指针的大小(通常是一个只有一个指针的结构体,指针指向下一块数据,是否取结构体指针不重要),在书写链表的 API 时,我们只假设我们拿到的前四/八个字节,其他字节为用户自定义的区域。
typedef struct {LinkNode node;char name [64];int age;} Person;
我们仍然需要一个结构体来表示整个链表,LList 的头结点尽量不要是指针,不然还得额外初始化头结点。
typedef struct linkNode {struct linkNode * next;} LinkNode;typedef struct {LinkNode pHeader;int size;} LList;typedef void* LinkList;
初始化
LinkList init() {LList* llist = (LList*)malloc(sizeof(LList));if (llist == NULL) {return NULL;}llist->pHeader.next = NULL;llist->size = 0;return (LinkList)llist;}
插入
void insert(LinkList list, void* data, int index) {if (data == NULL || list == NULL || index < 0) {return;}LList* llist = (LList*)list;if (index > llist->size) {return;}LinkNode * myNode = (LinkNode*)data; // 取出前四个字节来用LinkNode* pCurrent = &(llist->pHeader);for (int i = 0; i<index; i++) {pCurrent = pCurrent->next;}myNode->next = pCurrent->next;pCurrent->next = myNode;llist->size += 1;}
遍历
void travel(LinkList list, void (*callback)(void*)) {if (list == NULL) {return;}LList* llist = (LList*)list;LinkNode* pCurrent = llist->pHeader.next;for (int i = 0; i<llist->size; i++) {callback(pCurrent);pCurrent = pCurrent->next;}}
删除
void remove(LinkList list, int index) {if (list == NULL) {return;}LList* llist = (LList*)list;if (index < 0 || index > llist->size-1) {return;}LinkNode* pCurrent = &(llist->pHeader);for (int i = 0; i < index; i++) {pCurrent = pCurrent->next;}LinkNode* pDel = pCurrent->next;pCurrent->next = pDel->next; // 不要 free 掉 pDel 这是用户数据pDel->next = NULL;llist->size -= 1;}
销毁
void destory(LinkList * list) {if (list == NULL) {return;}LList* llist = (LList*)(*list);LinkNode* pCurrent = &(llist->pHeader);LinkNode* pNext = llist->pHeader.next;while (pNext != NULL) {pCurrent->next = NULL;pCurrent = pNext;pNext = pNext -> next;}pCurrent->next = NULL;free(*list);*list = NULL;}
测试
void myPrintf(void* data) {Person* person = (Person*)data;printf("%s,%d\n", person->name, person->age);}
