【笔记】链表(C语言)(指针)

话不多说先上代码
code

这是一个链表的基本操作,主要功能有链表的添加、删除某个节点、添加某个节点。

#include<stdio.h>  // 引入标准输入输出库  
#include<stdlib.h> // 引入标准库,用于内存分配等操作  
  
// 定义一个结构体,表示链表的节点  
struct node{  
    int data;  // 节点中存储的数据  
    struct node* next;  // 指向下一个节点的指针  
};  
  
// 创建一个新的节点  
struct node* createnode(int data){  
    struct node* newnode = (struct node*)malloc(sizeof(struct node));  // 使用malloc分配内存  
    newnode->data = data;  // 设置节点的数据  
    newnode->next = NULL;  // 设置节点的指针为NULL  
    return newnode;  // 返回新创建的节点  
}  
  
// 在链表的头部插入一个新节点  
void insertnode(struct node** head,int data){  
    struct node* newnode = createnode(data);  // 创建新节点  
    if(*head == NULL){  // 如果链表为空  
        *head = newnode;  // 将新节点设置为链表的头部  
    } else {  
        struct node* temp = *head;  // 定义一个临时指针,指向链表的头部  
        while(temp->next!=NULL){  // 当临时指针的下一个节点不为空时,继续移动临时指针  
            temp = temp->next;  
        }  
        temp->next = newnode;  // 将临时指针的下一个节点设置为新节点  
    }  
}  
  
// 打印链表的所有节点数据  
void printlist(struct node* head){  
    while(head != NULL){  // 当链表不为空时  
        printf("%d ",head->data);  // 打印当前节点的数据  
        head = head->next;  // 将头指针移动到下一个节点  
    }  
    printf("\n");  // 打印换行符,结束输出  
}  
  
// 释放链表所占用的动态内存  
void freelist(struct node* head){  
    struct node* temp;  
    while(head != NULL){  // 当链表不为空时  
        temp = head;  // 定义一个临时指针,指向链表的头部  
        head = head->next;  // 将头指针移动到下一个节点  
        free(temp);  // 释放临时指针所指向的内存空间  
    }  
}  
  
// 删除指定值的节点  
void deletanode(struct node* head,int insertv){  
    struct node* current = head;  // 定义一个指针,指向链表的头部  
    struct node* prev = NULL;  // 定义一个指针,用于保存上一个节点的地址  
    while(current->data!=insertv&&current!=NULL){  // 当当前节点的数据不等于要删除的值且当前节点不为空时  
        prev = current;  // 保存当前节点的地址到prev指针中  
        current = current->next;  // 将指针移动到下一个节点  
    }  
     if (current != NULL) {  // 如果找到了要删除的节点  
        if (prev == NULL) {  // 如果要删除的是头节点  
            head = current->next;  // 将头指针移动到下一个节点,即删除节点后的头节点  
        } else {  
            prev->next = current->next;  // 将prev指针所指向的节点的下一个节点设置为要删除节点的下一个节点,即删除该节点  
        }  
        free(current);  // 释放要删除节点的内存空间  
    }  
}  
// 插入节点的函数  
void insertnode2(struct node* head, int data1, int data2) {  
    struct node* current = head;  
    struct node* prev = NULL;  
    struct node* newnode = createnode(data2);  // 创建新节点  
    while (current != NULL && current->data != data1) {  
        prev = current;  
        current = current->next;  
    }  
  
    if (current != NULL) {  
        if (prev == NULL) {  
            head = newnode;  // 如果要插入的是头节点,更新头节点指针  
        } else {  
            prev->next = newnode;  // 插入中间节点,更新前一个节点的指针  
        }  
        newnode->next = current;  // 新节点的指针指向当前节点,完成插入操作  
    } else {  
        printf("Node not found.\n");  // 如果找不到指定节点,则输出错误信息  
    }  
}  
  
// 主函数  
int main()  
{  
    struct node* head = NULL;  // 初始化链表头节点为空  
    int n, r, f = 1, insertv, newnodev;  
    printf("请输入你要创建的节点长度:\n");  
    scanf("%d",&n);  // 读取用户输入的节点数量  
    for(int i = 0; i < n; i++){  
        int data;  
        printf("请输入第%d个节点的数据\n",i+1);  
        scanf("%d",&data);  // 读取用户输入的节点数据  
        insertnode(&head,data);  // 插入新节点到链表头部  
    }  
    printf("链表数据为:\n");  
    printlist(head);  // 打印链表数据  
    while(f){  
        printf("是否有其他操作(1删除节点/2添加节点/输入其他结束)\n");  
        scanf("%d",&r);  // 读取用户选择的操作类型  
        if(r == 1){  // 如果选择删除节点  
            printf("请输入要删除的节点值\n");  
            scanf("%d", &insertv);  // 读取用户输入的待删除节点的值  
            deletanode(head,insertv);  // 删除指定节点  
            printlist(head);  // 打印链表数据,确认节点已被删除  
        }  
        else if(r == 2){  // 如果选择添加节点  
            printf("请输入要添加在那个节点以后(节点的值以后)和添加节点的值\n");  
            scanf("%d%d",&insertv,&newnodev);  // 读取用户输入的待插入位置和新的节点值  
            insertnode2(head,insertv,newnodev);  // 在指定位置插入新节点  
            printlist(head);  // 打印链表数据,确认新节点已插入  
        }  
        else {  // 如果选择结束操作或输入其他数字,则结束循环  
            break;  
        }  
    }  
    freelist(head);  // 释放链表内存空间  
    return 0;  // 程序结束并返回0,表示成功执行  
}

操作结果与演示

请输入你要创建的节点长度:
5
请输入第1个节点的数据
1
请输入第2个节点的数据
2
请输入第3个节点的数据
3
请输入第4个节点的数据
4
请输入第5个节点的数据
5
链表数据为:
1 2 3 4 5
是否有其他操作(1删除节点/2添加节点/输入其他结束)
1
请输入要删除的节点值
3
1 2 4 5
是否有其他操作(1删除节点/2添加节点/输入其他结束)
2
请输入要添加在那个节点以后(节点的值以后)和添加节点的值
4 3
1 2 3 4 5
是否有其他操作(1删除节点/2添加节点/输入其他结束)
3

Process returned 0 (0x0)   execution time : 16.983 s
Press any key to continue.

每个函数功能的解释与实现

结构体

struct node{//定义结构体
    int data;//存结构点的值
    struct node* next;//指针方便指向下一个节点
};

head节点、设置下一个节点节点

create/创造 data/数据

// 定义一个创建节点的函数,接受要存储的数据  
struct node* createnode(int data){  
    // 分配动态内存以存储节点结构体  
    struct node* newnode = (struct node*)malloc(sizeof(struct node));     
    // 将传入的data存储到新节点的data成员中  
    newnode->data = data;  
    // 将新节点的next指针初始化为NULL  
    newnode->next = NULL;  
    // 返回新节点的地址  
    return newnode;  
}

在最后一位增加一个节点

insert/插入、嵌入 这个函数用于创建一个新的链表节点,并为该节点分配动态内存。新节点的数据成员被设置为传入的data参数,而next指针被初始化为NULL。最后,函数返回新节点的地址,以便在其他函数中使用。

// 定义一个插入节点的函数,接受链表头指针的地址和要插入的数据  
void insertnode(struct node** head, int data){  
    // 创建一个新节点,并将数据放入节点  
    struct node* newnode = createnode(data);  
    // 如果链表为空,即头节点为NULL  
    if(*head == NULL){  
        // 将新节点的地址赋给头指针,即设置头节点  
        *head = newnode;  
    } else {  
        // 定义一个临时指针,指向链表的头节点  
        struct node* temp = *head;  
        // 遍历链表,直到找到最后一个节点(即next指针为NULL的节点)  
        while(temp->next!=NULL){  
            // 将临时指针移动到下一个节点  
            temp = temp->next;  
        }  
        // 将最后一个节点的next指针指向新节点,完成插入操作  
        temp->next = newnode;  
    }  
}

输出

这个函数通过遍历链表,逐个打印每个节点的数据。当遍历到链表的末尾(即头节点为NULL)时,循环结束。最后,打印一个换行符,使输出结果更整齐。

// 定义一个打印链表的函数,接受链表的头节点  
void printlist(struct node* head){  
    // 当头节点不为NULL时,继续循环  
    while(head != NULL){  
        // 打印当前节点的数据  
        printf("%d ",head->data);  
        // 将头节点更新为下一个节点  
        head = head->next;  
    }  
    // 打印换行符,使输出更整齐  
    printf("\n");  
}

释放内存

这个函数通过遍历链表,逐个释放每个节点所占用的动态内存。在释放当前节点内存之前,需要先将头节点更新为下一个节点,以免在释放内存后访问已经无效的内存区域。最后,当遍历到链表的末尾时,循环结束。

// 定义一个释放链表的函数,接受链表的头节点  
void freelist(struct node* head){  
    // 定义一个临时指针,用于遍历链表  
    struct node* temp;  
    // 当头节点不为NULL时,继续循环  
    while(head != NULL){  
        // 将临时指针指向当前节点  
        temp = head;  
        // 将头节点更新为下一个节点  
        head = head->next;  
        // 释放当前节点所占用的动态内存  
        free(temp);  
    }  
}

删除节点

这个函数通过遍历链表,查找并删除指定数据的节点。如果找到了要删除的节点,它会更新链表中的链接以删除该节点,并释放该节点所占用的动态内存。

// 定义一个删除节点的函数,接受链表的头节点和要删除的数据  
void deletanode(struct node* head, int insertv) {  
    // 定义一个指针,指向链表的头节点  
    struct node* current = head;  
    // 定义一个指针,用于保存上一个节点的地址  
    struct node* prev = NULL;  
    // 遍历链表,查找要删除的节点  
    while(current->data != insertv && current != NULL) {  
        // 如果当前节点不是要删除的节点,则保存当前节点的地址  
        prev = current;  
        // 将指针移动到下一个节点  
        current = current->next;  
    }  
    // 如果找到了要删除的节点  
    if (current != NULL) {  
        // 如果上一个节点是头节点,则将头节点更新为下一个节点  
        if (prev == NULL) {  
            head = current->next;  
        // 否则,将上一个节点的next指针更新为要删除节点的下一个节点  
        } else {  
            prev->next = current->next;  
        }  
        // 释放要删除节点的动态内存  
        free(current);  
    }  
}

插入

这个函数的功能是在链表中查找特定数据的位置,并在该位置插入一个新的节点。如果找到了要插入的位置,它会更新链表中的链接以插入新节点。如果找不到指定节点,则输出错误信息。

// 定义一个插入节点的函数,接受链表的头节点和要插入的数据  
void insertnode2(struct node* head, int data1, int data2) {  
    // 定义一个指针,指向链表的头节点  
    struct node* current = head;  
    // 定义一个指针,用于保存上一个节点的地址  
    struct node* prev = NULL;  
    // 创建一个新节点,并存储数据data2  
    struct node* newnode = createnode(data2);  // 创建新节点  
    // 遍历链表,查找要插入的位置  
    while (current != NULL && current->data != data1) {  
        // 如果当前节点不是要插入的位置,则保存当前节点的地址  
        prev = current;  
        // 将指针移动到下一个节点  
        current = current->next;  
    }  
  
    // 如果找到了要插入的位置  
    if (current != NULL) {  
        // 如果要插入的是头节点,更新头节点指针  
        if (prev == NULL) {  
            head = newnode;  // 如果要插入的是头节点,更新头节点指针  
        // 否则,将上一个节点的next指针更新为要插入节点的next指针  
        } else {  
            prev->next = newnode;  // 插入中间节点,更新前一个节点的指针  
        }  
        // 新节点的next指针指向当前节点,完成插入操作  
        newnode->next = current;  // 新节点的指针指向当前节点,完成插入操作  
    } else {  
        // 如果找不到指定节点,则输出错误信息  
        printf("Node not found.\n");  // 如果找不到指定节点,则输出错误信息  
    }  
}

主函数

这个程序通过定义一个链表结构和一个主函数来执行一系列的操作。它首先要求用户输入要创建的节点数量,然后循环n次来创建这些节点并插入到链表的头部。接下来,它打印链表的所有节点数据。然后它进入一个循环,等待用户选择操作。用户可以选择删除一个节点或添加一个新节点到链表的指定位置。最后,它释放链表所占用的动态内存并结束程序。

int main() // 主函数开始  
{  
    struct node* head = NULL; // 定义一个指向链表头节点的指针,初始化为NULL  
    int n, r, f = 1, insertv, newnodev; // 定义多个变量,包括节点数量n、操作选择r、循环标志f以及两个用于插入和删除节点的值  
    printf("请输入你要创建的节点长度:\n"); // 提示用户输入要创建的节点数量  
    scanf("%d",&n); // 从标准输入读取节点数量  
    for(int i = 0; i < n; i++){ // 循环n次,每次创建一个新节点并输入数据  
        int data;  
        printf("请输入第%d个节点的数据\n",i+1); // 提示用户输入当前节点的数据  
        scanf("%d",&data); // 从标准输入读取节点数据  
        insertnode(&head,data); // 调用insertnode函数,将新节点插入到链表的头部  
    }  
    printf("链表数据为:\n"); // 打印提示信息  
    printlist(head); // 调用printlist函数,打印链表的所有节点数据  
    while(f){ // 当f为1时,进入循环,等待用户选择操作  
        printf("是否有其他操作(1删除节点/2添加节点/输入其他结束)\n"); // 提示用户选择操作  
        scanf("%d",&r); // 从标准输入读取用户的选择  
        if(r == 1){ // 如果用户选择删除节点  
            printf("请输入要删除的节点值\n"); // 提示用户输入要删除的节点的值  
            scanf("%d", &insertv); // 从标准输入读取要删除的节点的值  
            deletanode(head,insertv); // 调用deletanode函数,删除指定值的节点  
            printlist(head); // 打印链表的所有节点数据,以确认删除操作  
        }  
        else if(r == 2){ // 如果用户选择添加节点  
            printf("请输入要添加在那个节点以后(节点的值以后)和添加节点的值\n"); // 提示用户输入要插入的位置和要插入的数据  
            scanf("%d%d",&insertv,&newnodev); // 从标准输入读取位置和数据  
            insertnode2(head,insertv,newnodev); // 调用insertnode2函数,在指定位置插入新节点  
            printlist(head); // 打印链表的所有节点数据,以确认插入操作  
        }  
        else  
            break; // 如果用户选择结束操作,跳出循环  
    }  
    freelist(head); // 调用freelist函数,释放链表所占用的动态内存  
    return 0; // 主函数返回0,表示程序正常结束  
}
  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值