作用
将 实际的数据类型
和 链表
相分离,实现 实际的数据类型
和 链表
的解耦。
介绍
如果我们使用原始的C语言写链表的话,数据类型是被固定死的,如果业务换了 需要另一种数据类型,我们又得重新在写一个链表,这是十分“恶心”的!因此引出了本文的企业链表。
CompanyLinkList.h
#pragma once
#ifndef __COMPANY_LINKLIST_H__
#define __COMPANY_LINKLIST_H__
typedef enum { TRUE, FASLE } BOOLEAN;//成功状态 FALSE 不成功 TRUE成功
typedef enum { ERROR, OK } STATUS; //状态信息 ERROR 发生错误 OK 一切正常
typedef struct LinkNode
{
struct LinkNode* next;
}LinkNode;
typedef struct LinkList
{
LinkNode head;
int size;
}LinkList;
//创建链表并初始化
LinkList* Create_LinkList();
//插入数据 根据位置插入
int Insert_LinkList(LinkList* list, int pos, LinkNode* data);
//删除数据 根据位置删除
int Remove_LinkList(LinkList* list, int pos);
//查找数据,根据数据内容
int Find_LinkList(LinkList* list, LinkNode* data, int(*Compare_Function)(LinkNode*, LinkNode*));
//遍历链表
int Foreach_LinkList(LinkList* list, void(*Foreach_Function)(LinkNode*));
//清空数据 链表仍然可用
int Clear_LinkList(LinkList* list);
//销毁链表 链表不可用
int Destroy_LinkList(LinkList* list);
#endif // !__COMPANY_LINKLIST_H__
CompanyLinkList.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CompanyLinkList.h"
//创建链表并初始化
LinkList* Create_LinkList()
{
LinkList* list = (LinkList*)malloc(sizeof(LinkList));
list->size = 0;
list->head.next = NULL;
return list;
}
//插入结点数据的地址 根据位置插入,pos从1开始
int Insert_LinkList(LinkList* list, int pos, LinkNode* data)
{
if (NULL == list || NULL == data)
{
return ERROR;
}
//位置太小插入到第一个位置
if (pos < 1)
{
pos = 1;
}
//位置太大插入到 尾部
if (pos > list->size)
{
pos = list->size + 1;
}
//找到插入位置的前驱结点
LinkNode* pre = &list->head;
for (int i = 1; i < pos; i++)
{
pre = pre->next;
}
data->next = pre->next;
pre->next = data;
list->size++;
return OK;
}
//删除数据 根据位置删除 pos 从1 开始
int Remove_LinkList(LinkList* list, int pos)
{
//list为NULL 或者 位置非法, 直接返回
if (NULL == list || pos < 1 || pos > list->size)
{
return ERROR;
}
LinkNode* pre = &list->head;
//同样找到删除结点的前驱
for (int i = 1; i < pos; i++)
{
pre = pre->next;
}
//删除节点
//注意:我们不释放被删除节点的内存,被删除节点的内存由用户释放
pre->next = pre->next->next;
list->size--;
return OK;
}
//查找数据,根据数据内容,返回是链表中的第几个元素,从1开始计数 ,没找到返回-1
//Compare_Function 用户提供 结点元素比较的回调函数
int Find_LinkList(LinkList* list, LinkNode* data, int(*Compare_Function)(LinkNode*, LinkNode*))
{
if (NULL == list || NULL == data || NULL == Compare_Function)
{
return ERROR;
}
LinkNode* node = list->head.next;
int flag = 0;// 是否查找到的标志
int index = 1;
while (node != NULL)
{
if (Compare_Function(node, data))
{
flag = 1;
break;
}
node = node->next;
index++;
}
return flag ? index : -1;
}
//遍历链表
//Foreach_Function 用户提供的遍历链表元素的回调函数
int Foreach_LinkList(LinkList* list, void(*Foreach_Function)(LinkNode*))
{
if (NULL == list || NULL == Foreach_Function)
{
return ERROR;
}
LinkNode* node = list->head.next;
while (NULL != node)
{
Foreach_Function(node);
node = node->next;
}
return OK;
}
//清空数据 链表仍然可用
int Clear_LinkList(LinkList* list)
{
if (NULL == list)
{
return ERROR;
}
list->size = 0;
list->head.next = NULL;
return OK;
}
//销毁链表 链表不可用
int Destroy_LinkList(LinkList* list)
{
if (NULL == list)
{
return ERROR;
}
free(list);
list = NULL;
return OK;
}
main.cpp 企业链表的使用
#include"CompanyLinkList.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//用户使用企业级链表,只需要在自己定义的类型中将LinkNode 作为第一个成员即可使用
//这样就将 具体的业务和底层链表算法 进行分离了
typedef struct Student
{
LinkNode node; //第一个元素,必须是LinkNode
char name[64];
int age;
}Student;
//用户定义遍历的回调函数
void Print_Student(LinkNode* node)
{
Student* stu = (Student*)node; //将LinkNode*强转为Student*
printf("姓名:%s,年龄%d\n", stu->name, stu->age);
return;
}
//用户定义结点的比较回调函数
int Compare_Student(LinkNode* node1, LinkNode* node2)
{
Student* stu1 = (Student*)node1;
Student* stu2 = (Student*)node2;
//年龄和名字相同才相同
if (stu1->age == stu2->age && 0 == strcmp(stu1->name, stu2->name))
{
return 1;
}
return 0;
}
int main(int argc, char *argv[])
{
Student s1, s2, s3, s4, s5;
s1.age = 11; strcpy(s1.name, "aaa");
s2.age = 12; strcpy(s2.name, "bbb");
s3.age = 13; strcpy(s3.name, "ccc");
s4.age = 14; strcpy(s4.name, "ddd");
s5.age = 15; strcpy(s5.name, "eee");
//创建链表
LinkList* list = Create_LinkList();
//插入
Insert_LinkList(list, 1, (LinkNode*)&s1);
Insert_LinkList(list, 2, (LinkNode*)&s2);
Insert_LinkList(list, 3, (LinkNode*)&s3);
Insert_LinkList(list, 4, (LinkNode*)&s4);
Insert_LinkList(list, 5, (LinkNode*)&s5);
printf("插入5条数据后遍历:\n");
Foreach_LinkList(list, Print_Student);
//查找
Student s6;
s6.age = 15; strcpy(s6.name, "eee");
int index = Find_LinkList(list, (LinkNode*)&s6, Compare_Student);
printf("查找的元素name=eee,age=15,是链表中第%d个元素\n", index);
//删除元素
Remove_LinkList(list, 1);
printf("删除第1个结点后遍历:\n");
Foreach_LinkList(list, Print_Student);
system("pause");
return 0;
}