参考王道的《数据结构》考研复习指导书(2021年)中的代码(P47),实现了在C语言中,借助一个递归工作栈,删除单链表中所有值为x的元素的功能,由于C语言中没有引用(&)传参这个概念,故需借助二级指针来实现。
代码运行结果如下图所示:代码如下:
# include <stdio.h>
# include <stdlib.h>
# include <stdbool.h>
//定义结点
typedef struct _node {
int value;
struct _node * next;
} Node;
//定义结构体List存放链表的信息,如:头结点(如果有的话)或首结点、尾结点、链表长度等等
typedef struct _list
{
Node* head;//始终指向首结点
Node* tail;//始终指向尾结点
} List;
//初始化
bool InitList(List* pList)
{
pList->head = pList->tail = NULL;
return true;
}
//判空
bool Empty(List* pList)
{
return (pList->head==NULL);
}
//结点添加(尾添加)
Node* List_AddOnTail(List* pList, int number)//传入指针的指针
{
//分配结点空间,并写入p->value
Node* p = (Node*)malloc(sizeof(Node));
p->value = number;
p->next = NULL;
if(pList->head == NULL)//如果链表是空的,最新分配的结点(p)既是head,也是tail
{
pList->head = p;
pList->tail = p;
}
else//如果链表不是空的,只需要处理tail
{
pList->tail->next = p;//此时链表的尾结点要指向新分配的结点
pList->tail = p;//新分配的结点成为链表的tail
}
pList->tail->next = NULL;//tail的后继指针必须是NULL
return pList->head;
}
//遍历输出链表
void List_Print(List* pList)
{
Node* p;
for(p=pList->head; p; p=p->next)
{
printf("%-6d", p->value);
}
printf("\n");
}
/*
删除链表中所有值为x的结点
借助一个递归工作栈 O(n)
需要使用二级指针Node** L
第1层递归中*L是链表list的头指针,即*L==list.head;
第n(n>1)层递归中*L指向的是第n-1层递归中的*L指向的结点的后继结点,即*L(n)==*L(n-1)->next
*/
void List_Delete_AllTargetNode_ByValue(Node** L, int x)//形参L是结点的指针的指针
{
Node* p;
if(*L == NULL)//终止条件是指针为空,尾结点的next指针为NULL
return;
if((*L)->value == x)//当前结点的元素为x,为要删除的目标结点
{
//删除当前(目标)结点
p = *L;//临时指针p指向当前结点
*L = (*L)->next;//*L指向下一个结点
free(p);//释放当前结点所占的内存空间
List_Delete_AllTargetNode_ByValue(L, x);//递归,进行下一个结点的处理
}
else//当前结点不是目标结点,则处理后继结点,这里后继结点的表示方法有点绕
{
List_Delete_AllTargetNode_ByValue(&((*L)->next), x);//(*L)->next是指向后继结点的指针,需要对其取地址后传回
}
}
int main(void)
{
//创建并初始化,输入元素
List list;
InitList(&list);
int number;
printf("请输入整数(输入-1结束):\n");
do
{
scanf("%d", &number);
if(number != -1)
{
list.head = List_AddOnTail(&list, number);//注意这里要传入head的地址
//list.head = List_AddOnHead(&list, number);
}
}while(number != -1);
//遍历并输出链表
printf("链表中的元素为:");
List_Print(&list);
int x;
printf("请输入您要删除的元素:");
scanf("%d", &x);
List_Delete_AllTargetNode_ByValue(&(list.head), x);//list.head是头指针,这里传入其地址
printf("当前链表中的元素是:\n");
List_Print(&list);
return 0;
}