【单链表增删插改查的函数编写】

文章目录

  • 一、单链表基础概念
    • 1.定义
  • 二、单链表操作
    • 1.定义节点结构体
    • 2.创建新节点函数
    • 3.创建单链表函数
    • 4.删除链表指定位置节点函数
    • 5.在链表指定位置插入节点函数
    • 6.在指定位置改变节点函数
    • 7.查找链表指定位置节点
    • 8.释放链表内存
    • 9.打印链表函数
  • 三.全部代码并main函数测验
  • 四.结语

本篇文章是作者对C语言链表学习一周后的独立编写代码,所以对于一些代码只会有文字解释,就不附图啦!!!(如果有看图理解的话就看另一篇博客吧)单链表增删改查的单独函数封装

之前又听到说尽量把输入不要写在函数里面,所以main函数会长些

一、单链表基础概念

1.定义

单链表是一种常见的数据结构,它由一系列节点组成,每个节点包含一个数据域和一个指向下一个节点的指针域。通过指针将各个节点连接起来,形成一个单链表。

二、单链表操作

1.定义节点结构体

typedef struct Node {
    int data;
    struct Node* next;
}Node;

定义了一个名为 Node 的结构体,它包含两个成员:一个是存储数据的整型类型 data,另一个是指向下一个节点的指针类型 next,通过这个指针可以将多个节点逐个连接起来形成单链表。

typedef语句定义新类型名:struct Node->Node:使代码更简洁明了,引用数据类型别名可增强程序的通用性、灵活性、可读性、可移植性。

2.创建新节点函数

Node* createNewnode(int value) {
    Node* newnode = (Node*)malloc(sizeof(Node));
    if (newnode == NULL) {
        return NULL;
    }

    newnode->data = value;
    newnode->next = NULL;
    return newnode;
}

这个函数接受一个整型参数 value,用于创建一个新的 newnode 节点。首先通过 malloc 函数为节点分配内存空间,如果分配失败则输出提示信息并返回 NULL。然后将传入的 value 赋值给新节点的 data 成员,并将 next 成员初始化为 NULL,最后返回创建好的新节点指针。

malloc是C语言中的库函数,要引用头文件#include <stdlib.h>

3.创建单链表函数

Node* createLinkedlist(Node** phead, Node** ptail, int value) {
    Node* newnode = createNewnode(value);
    if (*phead == NULL) {
        *phead = newnode;
        *ptail = newnode;
    }
    else {
        (*ptail)->next = newnode;
        (*ptail) = newnode;
    }
    return *phead;
}

该函数用于创建一个单链表,采用尾插法,即每次在链表的尾部添加新节点。首先首先传入头指针phead和尾指针ptail的地址。然后通过循环不断读取用户输入的值,只要输入的值不等于 -1,就创建一个新节点并将其添加到链表的尾部。如果链表为空(即 *pheadNULL),则新节点既是头节点也是尾节点;否则,将新节点添加到尾节点的后面,并更新尾节点指针。最后返回创建好的链表的头指针。

4.删除链表指定位置节点函数

void deleteAtposition(Node** phead, Node** ptail, int value) {
    Node* prev = NULL;
    Node* curr = *phead;

    while (curr != NULL && curr->data != value) {
        prev = curr;
        curr = curr->next;
    }
    if (curr == NULL) {
        printf("error!");
        return;
    }

    if (curr == *phead) {
        if (*phead == NULL) {
            printf("error!");
            return;
        }
        Node* temp = *phead;
        *phead = (*phead)->next;
        free(temp);
        return;
    }

    if (curr == *ptail) {
        Node* temp = *ptail;
        prev->next = NULL;
        *ptail = prev;
        free(temp);
        return;
    }

    prev->next = curr->next;
    free(curr);
    return;
}

这个函数用于删除链表指定位置的节点。首先判断如果要删除的位置是 头节点,则创建临时变量temp存储原本头指针,再将头指针指向下一个,最后释放临时变量节点。然后,如果删除为节点,则创建临时变量temp存储原本尾指针,让prev即尾指针上一个指向空,并让它为尾指针,最后释放临时变量节点。否则,通过循环遍历链表找到要删除位置的前一个节点 prev 和要删除位置的节点 curr。如果在遍历完链表后还没有找到指定位置(即 currNULL),则输出提示信息并返回。找到合适位置后,将 prevnext 指针指向 curr 的下一个节点(即 prev->next = curr->next),从而跳过 curr 节点,然后通过 free 函数释放 curr 节点所占用的内存。

5.在链表指定位置插入节点函数

void insertAtposition(Node** phead, Node** ptail, int pos, int value) {
    //pos为指定结点指向的值,pos = 0指在头节点插入,随后依从1排序,value为修改后的值。
    Node* curr = *phead;
    if (curr == NULL) {
        printf("error!");
        return;
    }
    if (pos == 0) {
        if (*phead == NULL) {
            printf("error!");
            return;
        }
        Node* newnode = createNewnode(value);
        newnode->next = *phead;
        *phead = newnode;
        return;
    }

    while (curr != NULL && curr->data != pos) {
        curr = curr->next;
    }
    if (curr == NULL) {
        printf("error!");
        return;
    }

    if (curr == *ptail) {
        Node* newnode = createNewnode(value);
        (*ptail)->next = newnode;
        return;
    }

    Node* newnode = createNewnode(value);
    newnode->next = curr->next;
    curr->next = newnode;

    return;
}

此函数用于在链表的指定位置插入一个新节点。首先判断如果pos = 0,则在头部插入节点。判断如果curr == *ptail,则在尾部插入节点。否则,通过循环遍历链表找到要插入位置的前一个节点 prev 和要插入位置的节点 curr。如果在遍历完链表后还没有找到指定位置(即 currNULLcurr->data != pos),则输出提示信息error!并返回。如果找到合适位置后,创建一个新节点并将其插入到 prevcurr 之间,即先将 newnodenext 指针指向curr->next,再将currnext指针指向 nenode

6.在指定位置改变节点函数

void changeAtposition(Node** phead, int pos, int value) {
    Node* curr = (*phead);
    if (curr == NULL) {
        return;
    }

    while (curr != NULL && curr->data != pos) {
        curr = curr->next;
    }
    if (curr == NULL) {
        printf("error!");
        return;
    }

    curr->data = value;
    return;
}

此函数用于修改链表指定位置节点的值。通过循环遍历链表找到要修改位置的节点 curr,如果在遍历完链表后还没有找到指定位置(即 currNULL),则输出提示信息并返回。找到合适位置后,将该节点的 data 成员的值更新为传入的新值 value

7.查找链表指定位置节点

int searchAtposition(Node** phead, int pos) {
    Node* curr = (*phead);
    if (curr == NULL) {
        printf("%d--error! ", pos);
        return 0;
    }

    while (curr != NULL && curr->data != pos) {
        curr = curr->next;
    }

    if (curr == NULL || curr->data != pos) {
        return 0;
    }
    else {
        return 1;
    }
}

此函数用于查找表指定位置节点。通过循环遍历链表找到要查找的位置的节点 curr,如果在遍历完链表后还没有找到指定位置(即 currNULL),则输出提示信息并返回。找到合适位置后,输出提示信息。

8.释放链表内存

void freeLinkedlist(Node* head) {
    Node* temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp);
    }
}

这个函数用于释放整个链表所占用的内存。通过循环遍历链表,每次先保存当前节点的指针到 temp 变量,然后将链表头指针更新为下一个节点(即 head = head->next),最后通过 free 函数释放 temp 所指向的节点所占用的内存,直到链表为空(即 headNULL)为止。

9.打印链表函数

void printfLinkedlist(Node* head) {
    Node* curr = head;
    while (curr != NULL) {
        printf("%d ", curr->data);
        curr = curr->next;
    }
    printf("\n");
}

该函数用于打印链表中所有节点的数据值。通过循环遍历链表,从链表头节点开始,每次输出当前节点的 data 成员的值,然后将指针移动到下一个节点,直到链表为空(即 currNULL)为止,最后输出一个换行符。

三.全部代码并main函数测验

#include<stdio.h>
#include<stdlib.h>
typedef struct Node {
    int data;
    struct Node* next;
}Node;

Node* createNewnode(int value) {
    Node* newnode = (Node*)malloc(sizeof(Node));
    if (newnode == NULL) {
        return NULL;
    }

    newnode->data = value;
    newnode->next = NULL;
    return newnode;
}

Node* createLinkedlist(Node** phead, Node** ptail, int value) {
    Node* newnode = createNewnode(value);
    if (*phead == NULL) {
        *phead = newnode;
        *ptail = newnode;
    }
    else {
        (*ptail)->next = newnode;
        (*ptail) = newnode;
    }
    return *phead;
}

void deleteAtposition(Node** phead, Node** ptail, int value) {
    Node* prev = NULL;
    Node* curr = *phead;

    while (curr != NULL && curr->data != value) {
        prev = curr;
        curr = curr->next;
    }
    if (curr == NULL) {
        printf("error!");
        return;
    }

    if (curr == *phead) {
        if (*phead == NULL) {
            printf("error!");
            return;
        }
        Node* temp = *phead;
        *phead = (*phead)->next;
        free(temp);
        return;
    }

    if (curr == *ptail) {
        Node* temp = *ptail;
        prev->next = NULL;
        *ptail = prev;
        free(temp);
        return;
    }

    prev->next = curr->next;
    free(curr);
    return;
}

void insertAtposition(Node** phead, Node** ptail, int pos, int value) {
    Node* curr = *phead;
    if (curr == NULL) {
        printf("error!");
        return;
    }
    if (pos == 0) {
        if (*phead == NULL) {
            printf("error!");
            return;
        }
        Node* newnode = createNewnode(value);
        newnode->next = *phead;
        *phead = newnode;
        return;
    }

    while (curr != NULL && curr->data != pos) {
        curr = curr->next;
    }
    if (curr == NULL) {
        printf("error!");
        return;
    }

    if (curr == *ptail) {
        Node* newnode = createNewnode(value);
        (*ptail)->next = newnode;
        return;
    }

    Node* newnode = createNewnode(value);
    newnode->next = curr->next;
    curr->next = newnode;

    return;
}

void changeAtposition(Node** phead, int pos, int value) {
    Node* curr = (*phead);
    if (curr == NULL) {
        return;
    }

    while (curr != NULL && curr->data != pos) {
        curr = curr->next;
    }
    if (curr == NULL) {
        printf("error!");
        return;
    }

    curr->data = value;
    return;
}

int searchAtposition(Node** phead, int pos) {
    Node* curr = (*phead);
    if (curr == NULL) {
        printf("%d--error! ", pos);
        return 0;
    }

    while (curr != NULL && curr->data != pos) {
        curr = curr->next;
    }

    if (curr == NULL || curr->data != pos) {
        return 0;
    }
    else {
        return 1;
    }
}

void printfLinkedlist(Node* head) {
    Node* curr = head;
    while (curr != NULL) {
        printf("%d ", curr->data);
        curr = curr->next;
    }
    printf("\n");
}

void freeLinkedlist(Node* head) {
    Node* temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp);
    }
}

int main() {
    Node* head = NULL;
    Node* tail = NULL;
    int n;

    printf("请输入链表节点(以-1结束):");
    scanf("%d", &n);
    while (n != -1) {
        createLinkedlist(&head, &tail, n);
        scanf("%d", &n);
    }
    printf("实际链表:");
    printfLinkedlist(head);

    printf("请输入要删除的节点(以-1结束):");
    scanf("%d", &n);
    while (n != -1) {
        deleteAtposition(&head, &tail, n);
        scanf("%d", &n);
    }
    printf("删除后链表:");
    printfLinkedlist(head);
    
    int pos1;
    printf("请输入要插入的节点(以-1 -1结束):");
    scanf("%d%d", &pos1, &n);
    while (n != -1 && pos1 != -1) {     
        insertAtposition(&head, &tail, pos1, n);
        scanf("%d%d", &pos1, &n);
    }
    printf("插入后链表:");
    printfLinkedlist(head);

    int pos2;
    printf("请输入要改变的节点(以-1 -1结束):");
    scanf("%d%d", &pos2, &n);
    while (n != -1 && pos2 != -1) {
        changeAtposition(&head, pos2, n);
        scanf("%d%d", &pos2, &n);
    }
    printf("改变后链表:");
    printfLinkedlist(head);

    int pos3;
    printf("请输入要查找的节点(以-1结束):");
    scanf("%d", &pos3);
    while (pos3 != -1) {
        if (searchAtposition(&head, pos3)) {
            printf("%d找到了 ", pos3);
        }
        else {
            printf("%d没找到 ", pos3);
        }
        scanf("%d", &pos3);
    }

    freeLinkedlist(head);

    return 0;
}

main 函数中,首先调用 createLinkedList 函数创建一个单链表,然后依次调用各种操作函数对链表进行插入、删除、修改、查找等操作,并在每次操作后通过 printLinkedList 函数打印链表的当前状态,最后通过 freeLinkedList 函数释放链表所占用的内存,以避免内存泄漏。

四.结语

​ 经过一周的学习,能够基本上独立完成链表的增删改查的编写,对计算机的初步学习也有了较深的进步(如果有错的地方可以发给我T—T)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值