包括 新增节点,头插,尾插,头删,尾删,打印链表,删除指定节点,替换数据。
声明结构体如下👇
typedef struct stu {
int value;
struct stu* next;
}stu;//结点声明如此;
具体的函数声明及包含参数;
stu* Buy_list_haednode(stu** head, int n);
//创建 单链表(头)
stu* Buy_list_node(int n);
//创建单链表节点
stu* head_insert_list(stu** head, int n);
//单链表-头插
stu* head_delete_list(stu** head);
//单链表-头删
stu* tail_insert_list(stu* head, int n);
//单链表-尾插
stu* tail_delete_list(stu* head);
//单链表-尾删
stu* specified_value_revise_list(stu* head, int target, int new_value);
//替换指定的值
stu* specified_node_delete_list(stu* head, int target);
//删除 指定的节点
void print_list(stu* first);
//顺序打印单链表
此处的函数声明返回值大都是(stu*)类型,目的是每次操作都会返回该链表的头节点(返回值可用可不用)
在声明链表之前,须声明一个该结构体的指针 指向NULL,从而开始创建单链表;(给这个单链表起个名?hh)
int main()
{
stu* head=NULL;
/*..具体操作..*/
/*..具体操作..*/
/*..具体操作..*/
return 0;
}
注意 不是头(哨兵位)节点声明;
1)创建单链表
stu* Buy_list_haednode(stu** head, int n)
{
*head = (stu*)malloc(sizeof(stu));
(*head)->next = NULL;
(*head)->value = n;
return (*head);//返不返回(stu*)类型没必要,把函数写成void类型也可,这里只是为了和其他操作函数整齐。
}
将 传入的空指针指向一个malloc开辟的内存块,存储内容( n ),指向NULL。
将创建头节点单独写出可以方便头插尾插时直接调用;
使用二级指针是因为改变了 传入的head节点指针的指向 ,若用一级指针接收 则形参只是临时拷贝 不能改变实际(stu*head)的指向;
所以 在使用时传参须传(&head);
下同.....
2)创建节点
stu* Buy_list_node(int n)
{
stu* a = (stu*)malloc(sizeof(stu));
a->next = NULL;
a->value = n;
return a;
}
创建一个存有目标值的 指向为空的节点;
将创建节点单独写出可以方便头插尾插时直接调用;
3)头插-单链表
stu* head_insert_list(stu**head, int n)
{
if (!(*head))
{
return Buy_list_haednode(head, n);
}
else if (*head)
{ stu* a = NULL;
a = Buy_list_node(n);
a->next = *head;
*head = a;
}
return *head;
}
若传入的链表为空,则创建一个该指针指向存入目标值的链表头;
若传入的链表不为空,则创建一个存有目标值的节点,使其内部next指向链表头,之后将该节点作链表头;
4)尾插-单链表
stu* tail_insert_list(stu*head,int n)
{
if (!head)
{
return Buy_list_haednode(&head, n);
}
else if (head)
{
stu* hhead = head;
for(;hhead->next;hhead = hhead->next);
hhead->next = Buy_list_node(n);//返回类型为stu*的方便之处
return head;
}
}
若传入的链表为空,则创建一个该指针指向存入目标值的链表头;
若传入的链表不为空,创建一个临时的结构体指针变量=head,for循环到链表尾,将链表尾节点的next指向 创建的含有目标值的节点;
5)头删-单链表
stu* head_delete_list(stu** head)
{
assert(head);
if (!(*head)->next)
{
free(head);
return NULL;
}
stu* a = *head;
*head = (*head)->next;
free(a);
return *head;
}
若传入的链表为空,assert报错 若链表仅一个节点,销毁链表 若链表多个节点,将第一个节点free掉,并将第二个节点作链表头;
6)尾删-单链表
stu* tail_delete_list(stu* head)
{
assert(head);
if (!head->next)
{
free(head);
return NULL;
}
stu* a = head;
for (; a->next->next; a = a->next);
free(a->next);
a->next = NULL;
return head;
}
若传入的链表为空,assert报错 若链表仅一个节点,销毁链表 若链表多个节点,创建一个临时节点通过for循环指向倒数第二个节点 free掉最后一个节点 后将倒数第二个节点的next=NULL;
7)替换节点内容
stu* specified_value_revise_list(stu* head, int target, int new_value)
{
assert(head);
stu* a = head;
while (a->value != target)
{
a = a->next;
if (!a)
{
puts("wrong target!");
return head;
}
}
a->value = new_value;
return head;
}
找到目标值所在的节点,替换。
8)删除特定节点
stu* specified_node_delete_list(stu*head,int target)
{
assert(head);
if (!head->next)//一位节点的单链表
{
if (target == head->value)
{
free(head);
return NULL;
}
else puts("worng target!");
return head;
}
//多位节点的链表
stu* a = head;
stu* b = head->next;/*双指针*/
if(a->value==target)
{
stu* q = head_delete_list(&head);
return q;
}
while (b->value != target)
{ //双指针同时前移
a = b;
b = b->next;
if (!b)
{
puts("worng target!");
break;
return head;
}
}
if (!(b->next))
{
stu* q = tail_delete_list(head);
return q;
}
a->next = b->next;
free(b);
return head;
}
这个我实现的有点冗杂 欢迎指正,
双指针a b是为了只遍历一遍就可以进行目标操作 , a b指针同时前移 在b找到目标值时a指向b的上一个节点。