(7)单链表任意位置删除函数
一:什么是单链表 (1)单链表节点数据结构(2)单链表结构物理图解链表一般分成两块:一部分存储数据,另一部分存储下一个节点的地址。
二:单链表的几种接口函数的实现 (1)单链表的尾插函数(顺序插入)链表与顺序表不同,链表的存储形式不是一块物理地址连续的空间。而是在内存中随机存储。需要存入一个新的数据时,就malloc开辟一个新的节点。并将新开辟的空间的地址放置到上一个节点的指针中。 再将该节点的指针赋NULL。
而plist就是这个单链表的头,它存储的就是该链表的表头的地址。
1:因为是从该链表的尾部插入数据,所以先需要找到尾。(找尾)
尾部唯一的标识就是,该节点的指针域存储的数据为NULL(不指向任何空间)。那么我们可以通过这个条件,去遍历这个链表,找到尾。
void SList_push_tail(SList* *ps, SListdata tmp)
{
//如果该链表还是空的
SList* cur = (*ps);
SList* newnode = (SList*)malloc(sizeof(SList));
newnode->datd = tmp;
newnode->next = NULL;
if ((*ps) == NULL)
{
(*ps) = newnode;
return;
}
//说明已经有了一个或者多个节点
//此时就需要找尾
else
{
while (cur->next != NULL)
{
cur = cur->next;
}//出这个循环时,说明cur->next中存储的是NULL
//找到尾了
cur->next = newnode;
}
}
(2)单链表的尾删函数
将该链表的最后一个节点删除,那么同样的,我们也需要遍历该链表,找到尾。!!
但是在删除的同时,也需要将表尾的前一个节点的指针置NULL。但是对于单链表来说,如果我使用一个指针,遍历到了链表尾部,那就不能通过尾部的这个节点,找到上一个节点。
所以我们使用两个指针去遍历这个顺序表,指针ptr向后遍历,发现这个节点不是表尾,就将这个节点地址交给cur,自己去下一个节点。当ptr->next==NULL时,直接释放该空间,并将cur->next置空。(当然还需要考虑只有一个节点,或者没有节点的情况。)
void SList_pop_tail(SList* *ps)
{
SList* cur = *ps;
SList* perv = *ps;
if (*ps == NULL)
{
return;
}
else
{
if ((*ps)->next == NULL)
{//只有一个节点
free(*ps);
*ps = NULL;
}
//找尾
else
{
while (perv->next != NULL)
{
cur = perv;
perv = perv->next;
}
free(perv);
cur->next = NULL;
}
}
}
(3)单链表的头增函数
单链表的头增,因为在定义时,我们始终有一个指针,指向该链表的表头(我称其为表头指针)。所以我们只需要将新生成的空间地址传给这个表头即可,并将刚才的表头指针指向的那个节点地址,交给现在的表头。
//头增
void SList_push_head(SList* * ps, SListdata tmp)
{
SList* cur = *ps;
SList* newnode = (SList*)malloc(sizeof(SList));
newnode->datd = tmp;
newnode->next = NULL;
if (cur == NULL)
{//没有节点
(*ps) = newnode;
}
else
{
newnode->next = cur;
(*ps) = newnode;
}
}
(4)单链表的头删函数
先将表头指针指向该链表的第一个节点,然后将第一个节点的空间直接释放掉。就可以完成操作。
//头删
void SList_pop_head(SList* * ps)
{
SList* cur = *ps;
if (cur == NULL)
{//如果没有节点
return;
}
//如果只有一个节点
else if (cur->next == NULL)
{
free(cur);
(*ps) = NULL;
}
else//有一个以上节点
{
(*ps) = cur->next;
free(cur);
}
}
(5)单链表查询函数
遍历查询单链表中的数据,查询到了,返回该数据的地址,否则返回空指针。
//查询函数,查询到这个数据的节点,返回该节点的地址
SList* SList_chage(SList* ps, SListdata tmp)
{
if (ps == NULL)
{
return NULL;
}
else
{
while (ps->next != NULL)
{//有多个节点
if (ps->datd == tmp)
{
return ps;
}
ps = ps->next;
}
if (ps->datd == tmp)
{//最后一个节点前面插入
return ps;
}
}
return NULL;
}
(6)单链表任意位置插入数据
根据上面的查询函数去实现,先找到哪个数据前面插入数据。找到了就插入,找不到默认尾插。(当然可以自己设置
//在数据3前面插入一个10
SList* pos=SList_chage(plist, 3);
if (pos != NULL)
{
SList_push_any(&plist, pos, 10);
}
else
{
SList_push_tail(&plist, 10);
}
//上面是主函数中的代码,找到了就在该数据前面插入,找不到默认尾插。
//下面是任意插入函数的代码
void SList_push_any(SList* * ps, SList* pos, SListdata tmp)
{
SList* cur = *ps;
SList* ptr = *ps;
SList* newnode = (SList*)malloc(sizeof(SList));
newnode->datd = tmp;
newnode->next = NULL;
if (cur == NULL)
{
printf("目的空间地址错误n");
return;
}
else
{
if (cur == pos)
{//头插
SList_push_head(ps, tmp);
return;
}
else
{
while (cur->next != NULL)
{
if (cur->next == pos)
{
newnode->next = pos;
cur->next = newnode;
return;
}
ptr = cur;
cur = cur->next;
}
}
}
}
(7)单链表任意位置删除函数
还是需要利用到之前的数据查询函数,当查询到了那个数据,就去删除那个节点,并将该节点前后两个节点链接起来。
//查询函数,写在主函数中测试的
pos = SList_chage(plist, 18);
if (pos != NULL)
{
SList_pop_any(&plist, pos);
}
//删除任意位置
void SList_pop_any(SList** ps, SList* pos)
{
SList* cur = *ps;
SList* ptr = *ps;
if (cur == NULL)
{//空链表
printf("目的空间地址错误n");
return;
}
else
{
if (cur == pos)
{ //头删
SList_pop_head(ps);
}
else
{
while (cur->next != pos)
{
ptr = cur;
cur = cur->next;
}
ptr = cur;
cur = cur->next;
ptr->next = cur->next;
free(cur);
}
}
}



