C语言 -- 链表(企业级,侵入式链表)

本文介绍了如何实现侵入式单链表,包括结构体定义、初始化链表、插入节点、遍历链表以及按位置删除节点。通过实例展示了如何使用这个链表结构存储和操作用户自定义的`Person`结构,并提供了相关函数如获取链表长度和删除节点的示例。
摘要由CSDN通过智能技术生成

目录

节点结构体的实现

初始化链表

插入链表

遍历链表

删除节点、销毁链表

用户test


侵入式链表,内核链表

普通单链表和侵入式单链表的区别在于:

  • 普通的单链表的结点指针域指向的是下一个结点的内存首地址;
  • 侵入式单链表的结点指针域指向的是下一个结点的指针域成员变量的内存首地址。

 

节点结构体的实现

节点结构体只维护指针域,用户需预留4个字节空间,供我们帮助连接数据。

//节点结构体
struct LinkNode
{
	//只维护指针域
	struct LinkNode* next;
};
//链表结构体
struct LList
{
	struct LinkNode pHeader; //头结点
	int m_size;  //链表长度
};
//暴露给用户的
typedef void* LinkList;

初始化链表

//初始化链表
LinkList init_LinkList()
{
	struct LList* mylist = malloc(sizeof(struct LList));
	if (mylist == NULL)
		return NULL;

	mylist->m_size = 0;
	mylist->pHeader.next = NULL;

	return mylist;
}

插入链表

//插入链表
void insert_LinkList(LinkList list, int pos, void* data)
{
	if (list == NULL)
		return;
	if (data == NULL)
		return;
	
	struct LList* mylist = list;
	if (pos<0 || pos>mylist->m_size - 1)
		pos = mylist->m_size;

	//取出用户数据的前四个字节空间
	struct LinkNode* myNode = data; //把void*类型的data转为一个指针,即4个字节大小

	//找到待插入位置的前驱节点
	struct LinkNode* pCurrent = &mylist->pHeader;

	for (int i = 0; i < pos; i++)
	{
		pCurrent = pCurrent->next;
	}
	//更新指针指向
	myNode->next = pCurrent->next;
	pCurrent->next = myNode;
	mylist->m_size++;
}

遍历链表

//遍历链表
void foreach_LinkList(LinkList list, void(*myPrint)(void*))
{
	if (NULL == list)
		return;
	struct LList* mylist = list;
	struct LinkNode* pCurrent = mylist->pHeader.next;  //指向第一个有真实数据的节点

	for (int i = 0; i < mylist->m_size; i++)
	{
		//pCurrent就是用户数据的首地址
		myPrint(pCurrent);
		pCurrent = pCurrent->next;
	}
}

删除节点、销毁链表

//删除链表节点之按位置删除
void removeByPos_LinkList(LinkList list, int pos)
{
	if (list == NULL)
		return;
	struct LList* mylist = list;
	if (pos<0 || pos>mylist->m_size - 1)
		return; //无效位置直接返回
	//找到待删除位置的前驱节点的位置
	struct LinkNode* pCurrent = &mylist->pHeader;
	for (int i = 0; i < pos; i++)
	{
		pCurrent = pCurrent->next;
	}
	//PCurrent就是待删除节点的前驱节点
	//利用一个指针记录待删除节点
	struct LinkNode* pDel = pCurrent->next;
	//更改指针的指向
	pCurrent->next = pDel->next;
	
	//free(pDel); //数据本身是用户开辟的,由用户自己管理释放
	mylist->m_size--;
}

//清空链表
// 用户的数据不需要我们来释放,只需要把头结点指向空即可
void clear_LinkList(LinkList list)
{
	if (list == NULL)
		return;
	struct LList* mylist = list;

	mylist->pHeader.next = NULL;
	mylist->m_size = 0;
}

//销毁链表
void destory_LinkList(LinkList list)
{
	if (list == NULL)
		return;

	free(list);
	list = NULL;
}

用户test

//给用户提供接口获取链表长度
int size_LinkList(LinkList list)
{
	if (list == NULL)
		return -1;
	struct LList* mylist = list;
	return mylist->m_size;
}


struct Person
{
	struct LinkNode node; //占用用户数据的前四个字节
	char name[32];
	int age;
};
//回调函数打印
void printPerson(void* data)
{
	struct Person* person = data;
	printf("Name:%s, Age:%d\n", person->name, person->age);
}


void test03()
{
	//初始化链表
	LinkList mylist = init_LinkList();
	//创建数据
	struct Person p1 = { NULL,"aaa",12 };
	struct Person p2 = { NULL,"bbb",13 };
	struct Person p3 = { NULL,"ccc",14 };
	struct Person p4 = { NULL,"ddd",15 };

	//插入数据
	insert_LinkList(mylist, 0, &p1);
	insert_LinkList(mylist, 0, &p2);
	insert_LinkList(mylist, 1, &p3);
	insert_LinkList(mylist, -1, &p4);

	foreach_LinkList(mylist,printPerson);
	printf("--------------------\n");
	removeByPos_LinkList(mylist,1);
	foreach_LinkList(mylist, printPerson);
	printf("--------------------\n");
	printf("链表长度 = %d\n",size_LinkList(mylist));
	clear_LinkList(mylist);
	printf("链表长度 = %d\n", size_LinkList(mylist));
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值