单链表的增、删、改、查(图解)

本文详细介绍了链表的基本概念,对比了链表与数组的特点,并提供了单链表的创建、插入、查找、修改及删除等核心操作的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、链表简介

1、链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,有一系列结点(地址)组成,结点可动态的生成。

2、结点包括两个部分:(1)存储数据元素的数据域(内存空间),(2)存储指向下一个结点地址的指针域。类似如下:

二、链表和数组的区别

参考博客:链表(图文详解)_糊涂糖僧的博客-优快云博客_链表

1、数组静态分配内存,链表动态分配内存。故链表内存利用率高,不会浪费内存,可以使用内存中细小的不连续的空间,只有在需要的时候才去创建空间。大小不固定,拓展很灵活。

2、数组在内存中是连续的,链表是不连续的。

3、数组利用下标定位,查找的时间复杂度是O(1),链表通过遍历定位元素,查找的时间复杂度是O(N)。

4、数组插入和删除需要移动其他元素,时间复杂度是O(N),链表的插入或删除不需要移动其他元素,时间复杂度是O(1)。

数组优点:

1、随机访问性比较强,可以通过下标进行快速定位。

2、查找速度快

数组缺点:

1、插入和删除的效率低,需要移动其他元素。

2、会造成内存的浪费,因为内存是连续的,所以在申请数组的时候就必须规定七内存的大小,如果不合适,就会造成内存的浪费。

3、内存空间要求高,创建一个数组,必须要有足够的连续内存空间。

4、数组的大小是固定的,在创建数组的时候就已经规定好,不能动态拓展。

链表优点:

1、插入和删除的效率高,只需要改变指针的指向就可以进行插入和删除。

2、内存利用率高,不会浪费内存,可以使用内存中细小的不连续的空间,只有在需要的时候才去创建空间。大小不固定,拓展很灵活。

链表缺点:

查找的效率低,因为链表是从第一个节点向后遍历查找。

三、单链表操作

参考博客:什么是链表?(图解)_十二匹的博客-优快云博客_什么是链表

单链表例:

1、链表结构体

struct node
{
        int data;              //存放数据
        struct node *next;     //存放下一个节点地址  
};

 2、头尾节点

//开头定义为全局变量即可
struct node *head = NULL;  // 头节点
struct node *end = NULL;   // 尾节点

3、创建节点

struct node *creat_node(int data)
{
        struct node *new = malloc(sizeof(struct node));
        new->data = data;
        new->next = NULL;

        if (head == NULL)   //链表为空
        {
                head = new;
                end  = new;
        }

        return new;    //返回节点指针
}

4、按顺序插入节点 (链接节点)

struct node *insert_node(struct node *old,struct node *new)
{
        old->next = new;        //链接节点

        end = new;              //尾指针赋值
}

5、通过index查找节点

struct node *find_node(struct node *linklist,int index)
{
        int current_index = 1;

        if (linklist == NULL)
        {
                printf("链表为空!\n");
                return NULL;
        }

        while (linklist != NULL)
        {
                if (index == current_index)
                {
                        return linklist;
                }

                linklist = linklist->next;
                current_index++;
        }

        return NULL;
}

6、通过数据查找节点

struct node *find_node_position(struct node *linklist,int data)
{
        int position=1;

        if (linklist == NULL)
        {
                printf("链表为空!\n");
                return NULL;
        }

        while (linklist != NULL)
        {
                if ( data == linklist->data )
                {
                        //printf("data %d position=%d\n",linklist->data,position);
                        return linklist;
                }

                linklist = linklist->next;
                position++;
        }

        return NULL;
}

7、指定位置后一位插入节点

void insert_node_purpose(struct node *linklist,int index, int data)
{
        struct node *temp = creat_node(data);
        struct node *find = find_node(linklist,index);

        if (linklist == NULL)
        {
                printf("链表为空!\n");
                return;
        }
        else if (find == NULL)
        {
                printf("无此节点!\n");
                return;
        }
        else
        {
                // 将新节点的next 设置为 当前插入位置节点 的 下一个节点
                temp->next = find->next;

                // 将 当前插入位置节点的next 设置为新节点
                find->next = temp;
        }
}

8、改指定节点数据

void set_node(struct node *linklist, int index, int data)
{
        struct node *find  = find_node(linklist,index);   // 查找节点

        if (find == NULL)
        {
                printf("无此节点!\n");
                return;
        }

        find->data = data;
}

 9、通过index删除指定节点

void delete_node(struct node *linklist,int index)
{
        struct node *find = find_node(linklist,index);   // 查找节点

        if (find == NULL)  // 无此节点
        {
                printf("index error,can't find the node\n");
                return ;
        }
        else
        {
                struct node *node = head;

                if (head == end)    // 只有一个节点
                {
                        free(head);
                        head = NULL;
                        end = NULL;
                }
                else    // 大于一个节点
                {

                        if (find == head) // 删除头节点
                        {
                                struct node *old = head;   // 暂存旧节点
                                head = head->next;         // 将第二个节点设置为新头节点                             
                                free(old);                 // 释放头旧节点的内存                              
                        }
                        else if (find == end)   // 删除尾节点
                        {
                                while (node->next != find) // 找到要删除的节点
                                {
                                        node = node->next;
                                }

                                // 将倒数第二个节点的next置为NULL后就相当于设置为尾节点
                                node->next = NULL;
                                end = node;    //将倒数第二个节点设置为尾节点
                                free(find);    //释放被删节点的内存
                        }
                        else    // 删除中间个某节点,和删除尾节点类似
                        {
                                while (node->next != find) // 找到要删除的节点
                                {
                                        node = node->next;
                                }

                                // 将被删节点的上一个节点的next设置为被删节点的下一个节点
                                node->next = find->next;
                                free(find);    //释放被删节点的内存
                        }
                }
        }

        printf("index %d has deleted!\n", index);
}

 

 

 10、删除整个链表

void delete_list(struct node *linklist)
{
        struct node *node = head;

        if (linklist == NULL)
        {
                printf("链表为空!\n");
                return;
        }

        while (linklist != NULL)
        {
                struct node *old = linklist;        //暂存旧节点
                linklist = linklist->next;
                free(old);
        }

        head = NULL;
        end = NULL;

        printf("Delete linklist successfully!\n", __FUNCTION__);
}

11、显示节点数据  (遍历节点)

void show(struct node  *linklist)
{
        while(1)
        {
                if(linklist == NULL)        //假设链表已经为NULL则返回
                {
                        return ;
                }
                printf("linklist=%d\n",linklist->data);
                
                linklist = linklist->next;  //遍历节点,指向下一个节点
        }
}

四、测试代码

main:

int main(int argc, char *argv[])
{
        struct node  *a0 = creat_node(10);
        struct node  *a1 = creat_node(20);
        struct node  *a2 = creat_node(30);


        insert_node(a0,a1);
        insert_node(a1,a2);

        show(a0);

        printf("head=%d\n",head->data);
        printf("end=%d\n\n",end->data);

        /*      在20后插入25    */
        printf("在20后插入25:\n");
        insert_node_purpose(a0,2,25);
        show(a0);
        printf("\n");

        /*      把20改为15      */
        printf("把20改为15:\n");
        set_node(a0,2,15);
        show(a0);
        printf("\n");

        /*      删除15          */
        printf("删除15:\n");
        delete_node(a0,2);
        show(a0);
        printf("\n");

        return 0;
}

结果:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值