用C语言实现链表(增删改查)

用C语言实现链表(增删改查)

今天是第二次发记录,加油💪

定义节点类型
typedef struct Node {
    ElemType data;
    struct Node *p_next;
} linkList;

解释:起一个linkList的别名是为了方便后面直接用linkList来直接代替struct Node

初始化链表
//初始化头节点函数
void initLinkList(linkList *L) {
    L = (linkList *) malloc(sizeof(linkList));  //为头节点分配空间
    L->p_next = NULL;   //将头节点指针置空
}

解释:也就是初始化头节点,给头节点分配一个内存然后将其指针域指向NULL

创造链表函数
void createLinkList(linkList *L) {
    struct Node *p_now; //声明当前指针
    struct Node *p_new; //声明新指针
    int num;
    p_now = L;  //将当前指针从头节点开始
    printf("请问你想要创建多少数据\n");
    scanf("%d", &num);

    for (int i = 0; i < num; ++i) {
        printf("请输入第%d条数据", i + 1);
        p_new = (struct Node *) malloc(sizeof(struct Node *));//给新指针分配内存
        scanf("%d", &p_new->data);  //设置新节点数据
        p_new->p_next = NULL;             //设置新节点指针
        p_now->p_next = p_new;            //将新建节点链接到当前节点的尾部
        p_now = p_new;                    //改变当前节点
    }
    printf("创建成功\n");
}

解释:询问用户想要创建多少个节点对象,然后开始创建链表,p_now指向当前节点的一个指针(用来遍历) p_new代表新创建出来的节点,给p_new分配好内存后,先完善这个p_new节点(也就是先将这个节点的数据域和指针域完善),然后这里用的是前插法来插入节点的,最后改变p_now指针使得其一直指向的是当前的节点

输出链表函数
void printLinkList(linkList *L) {
    struct Node *p_now;
    int count = 0;

    p_now = L->p_next;  //因为头节点不放数据,所以直接将当前节点改变为头节点后的一个节点
    while (p_now) {
        printf("%d\n", p_now->data);
        p_now = p_now->p_next;
        count++;
    }
    printf("当前链表中共有%d个节点数据", count);
}

解释:先声明一个p_now作为“当前指针”,用count来记录这个链表中一共有多少个节点,然后用while循环进行遍历,如果存在这个当前节点就输出当前节点的数据,count++,然后不断的移动当前节点

插入元素函数
//pos代表第几个元素不是下标
void insertLinkList(linkList *L, int pos, struct Node *new_node) {
    struct Node *p_now;
    p_now = L;
    for (int i = 0; i < pos - 1; ++i) {
        p_now = p_now->p_next;
    }
    new_node->p_next = p_now->p_next;
    p_now->p_next = new_node;
}

解释:先用p_now指向头节点或第一个存储数据的节点(如果是头节点想下面的i就从0开始,如果是第一个节点,下面的i就从1开始)。 一直将p_now移向要插入位置的前一个节点的位置,然后将要插入节点的指针域指向原本在这个位置的节点,然后将前一个节点的指针域里的后继指针指向这个新节点

查找元素位置函数
//查找元素位置
int findElem(linkList *L, ElemType e) {
    struct Node *p_now;
    p_now = L->p_next;  //从第一个元素开始
    int pos = 1;
    while (p_now) {
        if (p_now->data == e) {
            return pos;
        } else {
            pos++;
            p_now = p_now->p_next;
        }
    }
    return -1;
}

解释:p_now指向第一个存储数据的元素,然后开始遍历,如果当前节点的值等于传入的e就输出当前pos值,如果不相等就让pos自增然后不断移动p_now指针来遍历

更新元素函数
void updateLinkList(linkList *L, int pos, ElemType e) {
    struct Node *p_now;
    p_now = L;
    for (int i = 0; i < pos; ++i) {
        p_now = p_now->p_next;
    }
    p_now->data = e;
}

解释:根据传入的位置进行遍历,遍历到要改变位置的那个节点后直接改变值即可

删除元素函数
void deleteLinkList(linkList *L, int pos) {
    struct Node *p_now;
    struct Node *p_temp;  //用于记录被销毁的指针防止其变为野指针
    p_now = L;
    for (int i = 0; i < pos - 1; ++i) {
        p_now = p_now->p_next;
    }
    p_temp = p_now->p_next;   //保存被删除的那个节点
    p_now->p_next = p_temp->p_next;  //将前一个节点的指针指向被删除节点的后一个节点
    free(p_temp);   //释放内存

}

解释:p_now用来遍历,p_temp用来指向要被删除的那个节点(方便释放内存)防止这个被删除的节点变为野指针。

各个函数的测试用例
void testInsert(linkList *L) {
    struct Node newNode;
    newNode.data = 5;
    newNode.p_next = NULL;
    insertLinkList(L, 2, &newNode);
    printLinkList(L);
}

void testFindElem(linkList *L) {
    int pos;
    pos = findElem(L, 3);
    printf("\n这个元素的位置是%d", pos);

}

void testUpdate(linkList *L) {
    updateLinkList(L, 3, 999);
    printLinkList(L);
}

void testDelete(linkList *L) {

    deleteLinkList(L, 3);
    printLinkList(L);
}

将各个函数封装成一个测试函数,到时候直接在主函数中调用即可

tips:如果用的话(,因为里面我提前设了一些值,)在创造链表的时候至少创建三个节点。

总代码
#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;

typedef struct Node {
    ElemType data;
    struct Node *p_next;
} linkList;

void initLinkList(linkList *L);  //初始化头节点函数

void createLinkList(linkList *L); //创建头节点函数

void printLinkList(linkList *L);  //输出链表

void insertLinkList(linkList *L, int pos, struct Node *new_node);  //插入数据

int findElem(linkList *L, ElemType e);   //查询数据返回元素位置

void updateLinkList(linkList *L, int pos, ElemType e);   //修改数据

void deleteLinkList(linkList *L, int pos);  //删除数据


void testInsert(linkList *L); //单元测试插入函数

void testFindElem(linkList *L);   //测试查询元素函数
void testUpdate(linkList *L);   //测试更新函数
void testDelete(linkList *L);   //测试删除函数



int main() {
    linkList L;   //创建头节点

    int pos;
    initLinkList(&L);
    createLinkList(&L);
    printLinkList(&L);

//    //测试插入函数
//    testInsert(&L);

//    //测试查询函数
//    testFindElem(&L);

//    //测试更新函数
//    testUpdate(&L);

//    printLinkList(&L);

//  //测试删除链表
//    testDelete(&L);

    return 0;
}

//初始化头节点函数
void initLinkList(linkList *L) {
    L = (linkList *) malloc(sizeof(linkList));  //为头节点分配空间
    L->p_next = NULL;   //将头节点指针置空
}

void createLinkList(linkList *L) {
    struct Node *p_now; //声明当前指针
    struct Node *p_new; //声明新指针
    int num;
    p_now = L;  //将当前指针从头节点开始
    printf("请问你想要创建多少数据\n");
    scanf("%d", &num);

    for (int i = 0; i < num; ++i) {
        printf("请输入第%d条数据", i + 1);
        p_new = (struct Node *) malloc(sizeof(struct Node *));//给新指针分配内存
        scanf("%d", &p_new->data);  //设置新节点数据
        p_new->p_next = NULL;             //设置新节点指针
        p_now->p_next = p_new;            //将新建节点链接到当前节点的尾部
        p_now = p_new;                    //改变当前节点
    }
    printf("创建成功\n");
}


void printLinkList(linkList *L) {
    struct Node *p_now;
    int count = 0;

    p_now = L->p_next;  //因为头节点不放数据,所以直接将当前节点改变为头节点后的一个节点
    while (p_now) {
        printf("%d\n", p_now->data);
        p_now = p_now->p_next;
        count++;
    }
    printf("当前链表中共有%d个节点数据", count);
}

//pos代表第几个元素不是下标
void insertLinkList(linkList *L, int pos, struct Node *new_node) {
    struct Node *p_now;
    p_now = L;
    for (int i = 0; i < pos - 1; ++i) {
        p_now = p_now->p_next;
    }
    new_node->p_next = p_now->p_next;
    p_now->p_next = new_node;
}

//查找元素位置
int findElem(linkList *L, ElemType e) {
    struct Node *p_now;
    p_now = L->p_next;  //从第一个元素开始
    int pos = 1;
    while (p_now) {
        if (p_now->data == e) {
            return pos;
        } else {
            pos++;
            p_now = p_now->p_next;
        }
    }
    return -1;
}

void updateLinkList(linkList *L, int pos, ElemType e) {
    struct Node *p_now;
    p_now = L;
    for (int i = 0; i < pos; ++i) {
        p_now = p_now->p_next;
    }
    p_now->data = e;
}

void deleteLinkList(linkList *L, int pos) {
    struct Node *p_now;
    struct Node *p_temp;  //用于记录被销毁的指针防止其变为野指针
    p_now = L;
    for (int i = 0; i < pos - 1; ++i) {
        p_now = p_now->p_next;
    }
    p_temp = p_now->p_next;   //保存被删除的那个节点
    p_now->p_next = p_temp->p_next;  //将前一个节点的指针指向被删除节点的后一个节点
    free(p_temp);   //释放内存

}


void testInsert(linkList *L) {
    struct Node newNode;
    newNode.data = 5;
    newNode.p_next = NULL;
    insertLinkList(L, 2, &newNode);
    printLinkList(L);
}

void testFindElem(linkList *L) {
    int pos;
    pos = findElem(L, 3);
    printf("\n这个元素的位置是%d", pos);

}

void testUpdate(linkList *L) {
    updateLinkList(L, 3, 999);
    printLinkList(L);
}

void testDelete(linkList *L) {

    deleteLinkList(L, 3);
    printLinkList(L);
}

谢谢查阅🙏

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

业精于勤荒于嬉,行成于思毁于随

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值