用C语言实现一个链表(二)
在上期内容中,我们探讨了实现一个链表的准备工作以及一些功能——创建新结点,尾插数据,尾删数据,遍历的代码。其中,详细说明了结构体以及二级指针的使用,本期内容,我们将继续讨论其他一些功能的代码实现。
一、链表的实现(代码+分析)
1.链表的头部数据插入(头插)
头部插入数据相对轻松,只要理解指针的链接关系即可,创建的新结点的指针域(next)应当指向头结点,而原来指向头结点的指针需要指向新结点,代码如下:
void LinkPushFront(LinkNode** pphead, DataType x)
{
assert(pphead);
LinkNode* newnode = CreateLinkNode(x);//创建新结点,将其赋给同型结构体指针newnode
newnode->next = *pphead;//这时新节点的指针域应该指向传入的头部指针*pphead
*pphead = newnode;//此时头部就是刚插入的新结点newnode,*pphead改变指向,指向链表的头——newnode
}
2.链表的头部数据删除(头删)
在删除头部数据时,需要注意的,如果直接把头指针指向的空间释放掉,那么后面的一串结点就找不到了,因为后面一串结点的起始位置是由头结点的next找到的,因此先要用一个临时的指针tmp保存一下头结点后面的next,代码如下:
void LinkPopFront(LinkNode** pphead)
{
assert(pphead);//首先,头指针的地址不能为空
assert(*pphead);//其次,头指针本身不能是空指针
LinkNode* tmp =(*pphead)->next;//临时变量将头结点后面的结点保护起来
free(*pphead);//这样在释放头指针指向的空间后还能找到后面的结点在哪里
*pphead = tmp;//最后头指针指向第二个结点
}
3.链表特定位置的寻找
根据结点的数据域,通过链表的遍历,找到结点所在的位置,返回一个指针,代码如下:
LinkNode* LinkFind(LinkNode* phead, DataType x)
{
LinkNode* cur = phead;//创建一个同型结构体指针变量用于遍历查找
while (cur != NULL)
{
if (cur->data == x)
{
return cur;//返回的是一个指针,指向要查找的结构体
}
cur = cur->next;//cur移向下一个结点
}
return NULL;//如果没有找到,返回空指针
}
4.链表特定位置之前的数据插入
链表数据插入于删除,关键还是要理清楚指针的链接关系,控制循环条件。在这里,之前写的LinkFind函数就起到了作用,比如说想在链表数据3之前插入一个数据6,就要先调用LinkFind函数,找到数据域为3 的结点所在地址,然后传给这里的LinkInsertFront插入函数,代码如下:
void LinkInsertFront(LinkNode** pphead, LinkNode* pos, DataType x)
{
assert(pphead);
assert(pos);
if (pos == *pphead)
{
LinkPushFront(pphead, x);//如果刚好是在首元素前插入,调用之前的头插函数即可
}
else
{
LinkNode* newnode = CreateLinkNode(x);//插入数据就要创建新结点
LinkNode* front = *pphead;//创建同型指针变量front,寻找pos之前的那个结点
while (front->next != pos)//pos前一个结点的特征就是它的指针域(next)指向的是pos
{
front = front->next;//向后遍历
}
front->next = newnode;//前一个结点的指针域不再指向pos,而是指向新插入的结点
newnode->next = pos;//新插入的结点的指针域指向的是pos
}
}
5.链表特定位置数据的删除
这里还是指针的链接关系,往往和LinkFind函数一起使用,代码如下:
void LinkErase(LinkNode** pphead, LinkNode* pos)
{
assert(pphead);
assert(pos);
if (*pphead == pos)
{
LinkPopFront(pphead);//刚好是第一个结点,调用之前的头部数据删除函数
}
else
{
LinkNode* front = *pphead;//创建一个同型结构体指针变量,用于寻找pos之前的结点
while (front->next != pos)
{
front = front->next;//向后查找
}
front->next = pos->next