动态单向链表的增删改查

学习建议:

1、看完一节视频,立即去实践,随学随练。

2、优秀的视频比自己去看书,更能消化理解

3、学习效果的检验方法是独立实现功能,实现后对比视频中的教学代码,查漏补缺。

4、独立编写过程中记录。

教学视频:https://www.bilibili.com/video/BV1yv411y7AW?p=5&vd_source=da60f9e1bc3321cae28c29fe80e9b078

REAME 如下:

2024/04/30
-目标:独立实现动态单向链表的增删改查
-编译方式:gcc -g link_list.c

迭代如下:
版本1:link_list.c-v0.1:
    step1.[链表初始化],也就是创建链表,也就是创建一个头节点,并且使 next = NULL;
        注意:初始化函数不需要形参(和大多数初始化函数一样),只需要返回值是一个指针即可。
    step2.链表节点的增加,也就是链表节点的插入。
            -[尾插法]:借助尾指针prear 该指针始终指向尾节点。
                存在问题:函数设计的参数列表设计有问题。
            -头插法:待增加。
    step3.[链表的遍历]。借助辅助指针 current。
            -存在的问题:尾节点的数据未打印出来。解决:正确的循环条件是 while(current != NULL)

版本2:
link_list.c-v0.2:
    
    step1.继续完成使用[头插法完成在某个节点前面插入新节点]。
        -使用两个辅助指针pre、current, 同时移动两个指针。
        -初始时,pre指向头节点, current 指向头节点的下一个节点。
        存在的问题:1、注意while 循环的条件; 查找到数据后应退出循环
                  2、需要考虑没有找到带查找节点。
    step2.[清空链表],只保留头节点。记录释放节点的下一个节点。
          -存在问题: 别忘了最后要把头节点指向NULL。
    step3.[删除某节点] 修改指向; 释放空间
            注意: 释放空间后,需要将该指针变量指向NULL。
    step4.[销毁链表],头节点都释放了。
            存在的问题: 销毁链表后进行遍历链表,遍历出来的头节点的数据是随机值,不正常,因此将销毁链表函数的形参修改为了二级指针。



存在的问题:
-1、看教学视频中老师是先在.h 文件中先声明函数,然后再在.c 文件中编写函数。
    而我只在.h 文件中声明了一个结构体,然后只顾着在.c 文件中写函数了。


参考连接:
    https://www.bilibili.com/video/BV1yv411y7AW?p=5&vd_source=da60f9e1bc3321cae28c29fe80e9b078

头文件:link_list.h

typedef struct _link_node{

    int value;
    struct _link_node* next;
}link_node;

源文件:版本1:link_list.c-v0.1

#include <stdio.h>
#include <stdlib.h>
#include "link_list.h"

/*链表的遍历*/
void traverse_link_list(link_node* phead)
{
    link_node* current = phead;
    
    if(phead->next == NULL)
        printf("link list is null!\n");
    
    while(current != NULL)
    {
        printf("%d\n", current->value);
        current = current -> next;
    }   
}

/*链表的插入-尾插法*/
void tail_insert_link_list(link_node* current, link_node** rear, int value)
{
    link_node* new = NULL;
    
    new = (link_node*)malloc(sizeof(link_node));
    new->value = value;
    new->next = NULL;
    
    current->next = new;
    
    rear = &new;
}

/*链表初始化*/
link_node* init_link_list()
{
    link_node* node = (link_node*)malloc(sizeof(link_node));
    node -> next = NULL;
    node -> value = -1;
    
    return node;
}

int main()
{
    link_node* phead;
    link_node* rear = NULL;
    link_node* current;
    
    /*链表初始化*/ 
    phead = init_link_list();
    
    int i = 0;
    current = phead; 
    /*使用尾插法填充链表*/
    for(i = 1; i < 6; i++)
    {
        tail_insert_link_list(current, &rear, i);
        current = current -> next;
    }
    
    /*遍历链表*/ 
    traverse_link_list(phead);   
    
    return 0; 
}

版本2:link_list.c-v0.2

#include <stdio.h>
#include <stdlib.h>
#include "link_list.h"

/*销毁链表*/
void destory_link_list(link_node** phead)
{
    if(*phead == NULL)
        return;
    
    link_node* current = *phead;
    link_node* pnext;
    
    while(current != NULL)
    {
        pnext = current->next;
        free(current);
        current = pnext;   
    }
    
    *phead = NULL;   
}

/*删除某节点*/
void remove_node(link_node* phead, int value)
{
    if(phead == NULL)
        return;
    
    link_node* pre = phead;
    link_node* current = pre->next;
    while(current != NULL)
    {
        if(current->value == value)
            break;
        
        pre = current;
        current = current->next;   
    }
    
    /*没找到*/
    if(current == NULL)
        return;    
    
    pre->next = current->next;
    free(current);
    current = NULL;/*释放后仍要让该指针变量指向NULL*/   
}


/*清空链表*/
void clean_link_list(link_node* phead)
{
    if(phead == NULL)
        return;
    
    link_node* current = phead->next;
    link_node* pnext;
    while(current != NULL)
    {
        pnext = current->next;  /*先记录当前节点的下一个节点*/
        printf("%d ", current->value);   
        free(current);          /*释放当前节点*/
        current = pnext;        /*让current指向下一节点*/
    }
    /*别忘了最后要将头节点指向NULL*/ 
    phead->next = NULL; 
    printf("节点已被删除\n");
}

/*插入节点-在某节点前插入新节点*/
void head_insert_link_list(link_node* phead, int cur_value, int new_value)
{
    if(phead == NULL)
    {   
        return;
    }
    
    link_node* pre = phead;
    link_node* current = pre->next;
    link_node* new = NULL;
    
    /*1.查找某节点*/
    while(current != NULL)
    {
        /*查找到节点后应立即退出循环*/
        if(current->value == cur_value)
            break;
        
        pre = current;  /*记录节点*/
        current = current->next;   
    }

#if 0
    /*注释掉该代码块,没找到节点,会将新节点追加在尾节点的后面*/    
    /*没有查找到节点立即退出*/
    if(current == NULL)
        return;
#endif    
     
    /*2.插入新节点*/
    new = (link_node*)malloc(sizeof(link_node));
    new->value = new_value;
     
    /*特别注意:下面的顺序不能颠倒*/ 
    new->next = current;
    pre->next = new;
}

/*链表的遍历*/
void traverse_link_list(link_node* phead)
{
    if(phead == NULL)
    {
        printf("该链表可能已经被销毁!\n");
        return;
    }
        
    link_node* current = phead;
    
    if(phead->next == NULL)
        printf("link list is null!\n");
    
    while(current != NULL)
    {
        printf("%d\n", current->value);
        current = current -> next;
    }   
}

/*链表的插入-尾插法*/
void tail_insert_link_list(link_node* current, link_node** rear, int value)
{
    link_node* new = NULL;
    
    new = (link_node*)malloc(sizeof(link_node));
    new->value = value;
    new->next = NULL;
    
    current->next = new;
    
    rear = &new;
}

/*链表初始化*/
link_node* init_link_list()
{
    link_node* node = (link_node*)malloc(sizeof(link_node));
    node -> next = NULL;
    node -> value = -1;
    
    return node;
}

int main()
{
    link_node* phead;
    link_node* rear = NULL;
    link_node* current;
    
    /*链表初始化*/ 
    phead = init_link_list();
    
    int i = 0;
    current = phead; 
    /*使用尾插法填充链表*/
    for(i = 1; i < 6; i++)
    {
        tail_insert_link_list(current, &rear, i);
        current = current -> next;
    }
    
    /*遍历链表*/ 
    traverse_link_list(phead);
    printf("链表填充完毕!\n");
    
    /*在某节点前插入新节点*/ 
    head_insert_link_list(phead, 10, 0);
    traverse_link_list(phead);
    
    /*删除某节点*/
    remove_node(phead, 3);
    printf("已删除节点!\n");
    traverse_link_list(phead);
    
    /*清空链表*/
    clean_link_list(phead);
    printf("已清空链表!\n");
    traverse_link_list(phead); 
   
    /*销毁链表*/
    destory_link_list(&phead);
    traverse_link_list(phead);   
     
    return 0; 
}

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
单向链表是由若干个节点组成的,每个节点都包含一个数据域和一个指向下一个节点的指针域。在单向链表中,只能从头节点开始遍历链表,每个节点只能访问其后继节点。下面是用单向链表实现增删改查的代码实现: ```python # 定义单向链表节点类 class ListNode: def __init__(self, val): self.val = val self.next = None # 定义单向链表类 class LinkedList: def __init__(self): self.head = None # 添加节点 def add_node(self, val): new_node = ListNode(val) if not self.head: self.head = new_node else: curr = self.head while curr.next: curr = curr.next curr.next = new_node # 删除节点 def delete_node(self, val): if not self.head: return if self.head.val == val: self.head = self.head.next else: curr = self.head while curr.next: if curr.next.val == val: curr.next = curr.next.next return curr = curr.next # 修改节点 def update_node(self, old_val, new_val): curr = self.head while curr: if curr.val == old_val: curr.val = new_val return curr = curr.next # 查找节点 def search_node(self, val): curr = self.head while curr: if curr.val == val: return True curr = curr.next return False ``` 在上面的代码中,我们定义了一个单向链表节点类 ListNode ,包含一个数据域 val 和一个指向下一个节点的指针域 next 。然后定义了单向链表类 LinkedList ,包含一个头节点 head 。在 LinkedList 中,我们实现了 add_node() 方法用于添加节点,delete_node() 方法用于删除节点,update_node() 方法用于修改节点,search_node() 方法用于查找节点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值