结构设计
传统的单向链表是根据结点开始书写的,数据域存放用户创建数据的指针,假设用户创建的数据仍然是 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);
}