数据结构-3.单向链表的实现
节点结构体设计
struct LinkNode
{
// 数据域
void* data;
// 指针域
struct LinkNode * next;
};
data
:一个void*
类型的指针,指向节点存储的数据。使用void*
是为了链表能够存储不同类型的数据。next
:一个指向下一个LinkNode
结构体的指针,形成链表的链接。
链表结构体设计
struct LList
{
//头节点
struct LinkNode pHeader;
//链表长度
int m_size;
};
pHeader
:链表的头节点。虽然pHeader
本身也是LinkNode
类型,但它可以作为链表的起始节点,其next
指针指向第一个实际的数据节点。m_size
:一个整数,表示链表中节点的数量。
初始化链表
LinkList init_LinkList()
{
struct LList* myList = malloc(sizeof(struct LList));
if (myList == NULL)
{
return NULL;
}
myList->pHeader.data = NULL;
myList->pHeader.next = NULL;
myList->m_size = 0;
return myList;
}
- 使用
malloc
分配struct LList
的内存。 - 初始化头节点的
data
指针为NULL
,next
指针也为NULL
。 - 设置链表长度
m_size
为0
。
插入链表
void insert_LinkList(LinkList list, int pos, void* data)
{
if (list == NULL)
{
return;
}
if (data == NULL)
{
return;
}
// 将list还原成struct LList数据类型
struct LList * myList = list;
if (pos <0 || pos > myList->m_size)
{
//位置无效 强制尾插
pos = myList->m_size;
}
//找到插入节点的前驱
struct LinkNode * pCurrent = &myList->pHeader;
for (int i = 0; i < pos; i++)
{
pCurrent = pCurrent->next;
}
//创建新节点
struct LinkNode* newNode = malloc(sizeof(struct LinkNode));
newNode->data = data;
newNode->next = NULL;
//建立节点关系
newNode->next = pCurrent->next;
pCurrent->next = newNode;
//更新链表长度
myList->m_size++;
}
- 检查
list
和data
是否为空,若为空则返回。 - 如果位置
pos
无效(负数或超出链表当前大小),将位置设置为链表末尾。 - 通过遍历找到插入位置的前驱节点
pCurrent
。 - 创建新节点并插入链表中。
- 更新链表长度
m_size
。
遍历链表
void foreach_linkList(LinkList list,void(*myForeach)(void *))
{
if (list == NULL)
{
return;
}
struct LList* mylist = list;
struct LinkNode* pCurrent = mylist->pHeader.next;
for (int i = 0; i < mylist->m_size; i++)
{
myForeach(pCurrent->data);
pCurrent = pCurrent->next;
}
}
- 检查
list
是否为空,若为空则返回。 - 使用
pCurrent
遍历链表,从头节点的下一个节点开始。 - 对每个节点的数据调用
myForeach
,然后移动到下一个节点。
按位置删除链表数据
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;
}
// 记录待删除的节点
struct LinkNode* pDel = pCurrent->next;
//重新建立节点关系
pCurrent->next = pDel->next;
//释放删除节点
free(pDel);
pDel = NULL;
// 更新链表长度
mylist->m_size--;
}
- 检查链表是否为空,如果为空,直接返回。
- 检查
pos
是否有效(是否在范围0到m_size-1
之间),如果无效,直接返回。 - 遍历链表,找到位置为
pos
的节点的前驱节点。 - 记录待删除的节点,并重新建立前驱节点和待删除节点之后的节点之间的链接。
- 释放待删除节点的内存,将其指针置为
NULL
。 - 更新链表长度
按照值删除链表数据
int myComparePerson(void* data1, void* data2)
{
struct Person* p1 = data1;
struct Person* p2 = data2;
return strcmp(p1->name,p2->name) == 0 && p1->age == p2->age;
}
void removeByValue_LinkList(LinkList List, void* data, int(*myComparePerson)(void * , void *))
{
if (List == NULL)
{
return;
}
if (data == NULL)
{
return;
}
struct LList* mylist = List;
//创建两个辅助指针
struct LinkNode* pPrev = &mylist->pHeader;
struct LinkNode* pCurrent = pPrev->next;
for (int i = 0; i < mylist->m_size; i++)
{
//将两个指针的比较交给用户
if (myComparePerson(pCurrent->data, data))
{
pPrev->next = pCurrent->next;
free(pCurrent);
pCurrent = NULL;
mylist->m_size--;
break;
}
//辅助指针后移
pPrev = pCurrent;
pCurrent = pCurrent->next;
}
}
- 检查链表和数据是否为空,如果为空,直接返回。
- 初始化两个指针,
pPrev
指向当前节点的前一个节点,pCurrent
指向当前节点。 - 遍历链表,通过用户提供的比较函数匹配节点数据。
- 如果找到匹配节点,调整前驱节点的
next
指针,绕过当前节点。 - 释放匹配的节点内存,更新链表长度,结束循环。
清空链表
void clear_LinkList(LinkList list)
{
if (list == NULL)
{
return;
}
struct LList* mylist = list;
struct LinkNode* pCurrent = mylist->pHeader.next;
for (int i = 0; i < mylist->m_size; i++)
{
struct LinkNode* pNext = pCurrent->next;
free(pCurrent);
pCurrent = pNext;
}
mylist->pHeader.next == NULL;
mylist->m_size = 0;
}
- 检查链表是否为空,如果为空,直接返回。
- 遍历链表,从头节点开始,逐个删除所有节点。
- 每次删除节点后,更新指针指向下一个节点,直到删除完所有节点。
- 清空链表后,将链表头节点的
next
指针置为NULL
,并将链表长度设为0。
返回链表长度
int size_LinkList(LinkList list)
{
if (list == NULL)
{
return -1;
}
struct LList* mylist = list;
return mylist->m_size;
}
- 检查链表是否为空,如果为空,返回-1。
- 如果链表非空,返回链表的
m_size
成员,该成员保存了链表的节点数量。
销毁链表
void destroy_linkList(LinkList list)
{
if (list == NULL)
{
return;
}
//清空链表
clear_LinkList(list);
free(list);
list = NULL;
}
- 首先调用
clear_LinkList
函数,删除链表中的所有节点。 - 释放链表本身的内存。
- 将链表指针置为
NULL
,防止悬挂指针的使用。
本文来自博客园,作者:ffff5,转载请注明原文链接:https://www.cnblogs.com/ffff5/p/18343309