一. 企业链表概述
① 企业链表简介
企业链表出现的原因:
我们在写传统的链表的时候,节点里面存放的有数据,如果数据的类型固定死了,再我们需要另外一种数据类型的时候,就需要重新写一个链表. 我们也可以使用void*万能指针不固定死数据类型,当然我们还有另外一种实现方式,就是使用企业链表,链表的node里面不存放具体的业务数据类型,这样我们的链表就不受业务数据的限制.
企业链表如何实现
- 业务数据分离出来,也就是说链表中的节点只保存指针域.
- 你定义的数据一般是一个结构体,要把结构体的第一个位置存放链表中的节点.
- 这样你的数据域的地址和链表节点的地址是一样的
- 所以你定义的数据的指针,可以当成链表的节点指针来使用.
typedef struct Student
{
LinkNode node;
char name[64];
int age;
} Student;
总结:
- 企业级链表的节点,不保存具体的数据域
- 业务数据中包含的第一个元素必须是链表的节点类型.
- 链表和业务数据的首地址相等
二. 企业链表的实现
- 将列表的节点当成业务数据结构体的第一个位置,然后业务数据,在转换之后可以当成节点来使用.
- 节点中存放的就是下一个节点的地址
实现的头文件
#ifndef COMPANY_LINK_LIST
#define COMPANY_LINK_LIST
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 链表节点,没有数据域,只保存下一个节点位置
typedef struct LINKNODE
{
struct LINKNODE *next;
} LinkNode;
// 链表结构体,存放节点和大小
typedef struct
{
LinkNode head; // 存放的是结构体
int size;
} LinkList;
// 声明打印的函数指针
typedef void (*PRINT_PTR)(LinkNode *);
// 比较函数指针
typedef int (*COMPARE_PTR)(LinkNode *, LinkNode *);
// 初始化链表
LinkList *init_linklist();
// 插入
void insert_linklist(LinkList *list, int pos, LinkNode *data);
// 删除根据位置去删除
void remove_linklist(LinkList *list, int pos);
// 查找
int find_linklist(LinkList *list, LinkNode *data, COMPARE_PTR compare);
// 链表大小
int get_size_linklist(LinkList *list);
// 清空数据 链表依然可以使用
void clear_linklist(LinkList *list);
// 销毁链表
void free_space_linklist(LinkList *list);
// 打印
void print_linklist(LinkList *list, PRINT_PTR print);
#endif // !COMPANY_LINK_LIST
具体实现
#include "CompanyLinkList.h"
// 初始化链表
LinkList *init_linklist()
{
// 为链表本身分配内存
LinkList *list = (LinkList *)malloc(sizeof(LinkList));
if (list != NULL)
{
list->head.next = NULL; // 下一个元素指向NULL
list->size = 0;
return list;
}
return NULL;
}
// 插入
void insert_linklist(LinkList *list, int pos, LinkNode *data)
{
if (pos <0 || pos > list->size)
{
pos = list->size;
}
// 插入操作,先遍历,然后插入
if (list != NULL && data != NULL)
{
// 找到插入位置的前驱结点
LinkNode* pre = &(list->head);
for (int i = 0; i < pos; i++)
{
pre = pre->next;
}
// 插入新节点,当新节点指向pos位置
data->next = pre->next;
// 将pos位置的前驱节点指向新节点
pre->next = data;
list->size++;
}
}
// 删除根据位置去删除
void remove_linklist(LinkList *list, int pos)
{
if (pos < 0 || pos >= list->size)
{
return;
}
if (list != NULL)
{
LinkNode *pCurrent = &(list->head);
for (int i = 0; i < pos; i++)
{
pCurrent = pCurrent->next; // 找到当前下标的指针
}
// pCurrent 是pos位置的前驱节点,将pos位置的指针删除掉,就相当于是
// pos的前驱节点指向pos的下一个节点,因为不是自己开辟的内存,不需要释放内存
pCurrent->next = pCurrent->next->next;
list->size--;
}
return;
}
// 查找
int find_linklist(LinkList *list, LinkNode *data, COMPARE_PTR compare)
{
if (list != NULL && data != NULL)
{
LinkNode *pCurrent = list->head.next; // 第一个节点(头节点的下一个)
int index = 0;
int indexFinded = -1;
while (pCurrent != NULL)
{
if (compare(data, pCurrent) == 0)
{
indexFinded = index;
break;
}
pCurrent = pCurrent->next;
index++;
}
return indexFinded;
}
}
// 链表大小
int get_size_linklist(LinkList *list)
{
if (list != NULL)
{
return list->size;
}
return -1;
}
// 清空数据 链表依然可以使用
void clear_linklist(LinkList *list)
{
if (list != NULL)
{
list->head.next = NULL;
list->size = 0;
}
return;
}
// 销毁链表
void free_space_linklist(LinkList *list)
{
if (list == NULL)
{
return;
}
free(list);
}
// 打印
void print_linklist(LinkList *list, PRINT_PTR print)
{
if (list != NULL)
{
// 辅助指针
LinkNode *pCurrent = list->head.next;
while (pCurrent != NULL)
{
print(pCurrent);
pCurrent = pCurrent->next;
}
}
return;
}
测试代码:
#include "CompanyLinkList.h"
// 业务数据中保存的是节点信息.
// 第一个是节点类型
// 节点里面存放的是下一个节点的地址.
typedef struct Person
{
LinkNode node;
char name[64];
int age;
} Person;
void my_print(LinkNode *data)
{
Person * p = (Person *)data;
printf("Name:%s, Age:%d\n",p->name,p->age);
}
int my_compare(LinkNode *node1, LinkNode *node2)
{
Person* p1 = (Person *)node1;
Person* p2 = (Person *)node2;
if (strcmp(p1->name, p2->name) == 0 && p1->age == p2->age)
{
return 0;
}
return -1;
}
int main()
{
LinkList *list = init_linklist();
// 创建数据
Person p1, p2, p3, p4, p5;
int charLen = sizeof(p1.name) / sizeof(p1.name[0]);
strcpy_s(p1.name, charLen, "aaaa");
strcpy_s(p2.name, charLen, "bbbb");
strcpy_s(p3.name, charLen, "cccc");
strcpy_s(p4.name, charLen, "dddd");
strcpy_s(p5.name, charLen, "eeee");
p1.age = 10;
p2.age = 20;
p3.age = 30;
p4.age = 40;
p5.age = 50;
insert_linklist(list, 0, (LinkNode *)&p1);
insert_linklist(list, 0, (LinkNode *)&p2);
insert_linklist(list, 0, (LinkNode *)&p3);
insert_linklist(list, 0, (LinkNode *)&p4);
insert_linklist(list, 0, (LinkNode *)&p5);
// 打印
print_linklist(list, my_print);
printf("_________________________________\n");
// 删除3位置的元素
remove_linklist(list, 3);
print_linklist(list, my_print);
// 查找一个数据是否存在
Person newP1;
strcpy_s(newP1.name, charLen, "aaaa");
newP1.age = 10;
int pos = find_linklist(list, (LinkNode *) &newP1, my_compare);
if (pos == -1)
{
printf("未找到!\n");
}
else
{
printf("找到了,位置: %d\n", pos);
}
newP1.age = 20;
pos = find_linklist(list, (LinkNode *)&newP1, my_compare);
if (pos == -1)
{
printf("未找到!\n");
}
else
{
printf("找到了,位置: %d\n", pos);
}
// 链表的大小
printf("链表大小为: %d\n", get_size_linklist(list));
// 清空链表
clear_linklist(list);
printf("清空后,链表大小: %d\n", get_size_linklist(list));
system("pause");
return 0;
}