文件:main.c
#include "linkedList.h"int main(int argc, char *argv[]) {// 创建头结点NODE *head = NULL;// 创建链表if (llist_create(&head, 666) < 0){perror("链表创建失败!");return -1;}// 向链表插入数据llist_addTail(&head, 777);llist_addTail(&head, 888);llist_addTail(&head, 999); // 666 777 888 999llist_addHead(&head, 7777);llist_addHead(&head, 8888);llist_addHead(&head, 9999); // 9999 8888 7777 666 777 888 999llist_insert(&head, 888, 1024); // 9999 8888 7777 666 777 1024 888 999// 测试遍历数据llist_showAll(head);// 更新数据llist_update(head, 999, 99999);llist_showAll(head); // 9999 8888 7777 666 777 1024 888 99999// 删除数据llist_delete(&head, 777);llist_showAll(head); // 9999 8888 7777 666 1024 888 99999// 销毁链表llist_destroy(&head);return 0;
}
文件:linkedList
#include "linkedList.h"/*** @brief 创建一个节点(私有函数)** @param head* @param data** @return*/
static NODE* __node_create(NODE **head, DATA data)
{// 创建一个新节点NODE *p = (NODE*)malloc(sizeof(NODE));// 校验是否创建成功if (!p) return NULL;// 初始化节点p->data = data; // 将外部插入的数据存储到当前节点的data成员p->next = NULL; // 节点默认指向NULLreturn p;
}/*** @brief 链表的创建(没有指定头结点的前提下进行(本案例涉及的是无头节点))* @param head 待操作链表,如果是改变链表结构,使用二级指针* @param data 待插入数据* @return 创建成功返回0,否则返回-1*/
int llist_create(NODE **head, DATA data)
{// 校验链表是否存在if (*head != NULL) return -1;// 创建一个新节点NODE *p = (NODE*)malloc(sizeof(NODE));// 校验是否创建成功if (!p) return -1;// 初始化节点p->data = data; // 将外部插入的数据存储到当前节点的data成员p->next = NULL; // 节点默认指向NULL// 将创建的新节点作为链表的头节点*head = p; // 就是让链表指针指向第一个节点return 0;
}/*** @brief 向链表头部插入一个节点数据(头插法)* @param head 待操作链表,如果是改变链表结构,使用二级指针* @param data 待插入数据* @return 创建成功返回0,否则返回-1*/
int llist_addHead(NODE **head, DATA data)
{// 创建一个新节点NODE *p = (NODE*)malloc(sizeof(NODE));// 校验是否创建成功if (!p) return -1;// 初始化节点p->data = data; // 存放插入的数据p->next = *head; // 让头指针指向新创建的节点p// 将当前的新节点作为头节点(更新头指针)*head = p;return 0;
}/*** @brief 向链表尾部插入一个节点数据(尾插法)* @param head 待操作链表,如果是改变链表结构,使用二级指针* @param data 待插入数据* @return 创建成功返回0,否则返回-1*/
int llist_addTail(NODE **head, DATA data)
{// 创建一个新节点NODE *pNew = (NODE*)malloc(sizeof(NODE));// 校验是否创建成功if (!pNew) return -1;// 初始化节点pNew->data = data;pNew->next = NULL;// 接收链表NODE *p = *head, *q = NULL;// 如果*p不存在,说明这是一个空链表if (!p){*head = pNew; // 更新头指针,让头指针指向pNewreturn 0;}// 如果是非空链表,使用循环查找尾结点// 指针尾速法遍历链表while (p){q = p; // q记录p偏移之前的位置p = p->next;// 指针偏移,得到尾结点}// 此时p指向NULL,q指向尾节点// 让原链表的尾节点指向pNewq->next = pNew;return 0;
}/*** @brief 向链表指定位置插入一个节点数据(中间插法)* @param head 待操作链表,如果是改变链表结构,使用二级指针* @param pos 待插入位置数据* @param data 待插入数据* @return 创建成功返回0,否则返回-1*/
int llist_insert(NODE **head, DATA pos, DATA data)
{// 创建一个新节点// NODE *pNew = __node_create(head,data);NODE *pNew = (NODE*)malloc(sizeof(NODE));// 校验是否创建成功if (!pNew) return -1;// 初始化节点pNew->data = data;pNew->next = NULL;// 因为需要遍历链表得到前后两个位置,所以可以使用指针尾随法NODE *p = *head, *q = NULL;// 情景1:空链表if (!p){*head = pNew; // 更新头指针return 0;}// 情景2:pos是头节点if (memcmp(&(p->data), &pos, sizeof(DATA)) == 0){// 头插法pNew->next = *head;*head = pNew; // 更新头指针return 0;}// 情景3:pos是非头节点while (p){// 校验是否是posif (memcmp(&(p->data), &pos, sizeof(DATA)) == 0){// 插入到目标节点pos前面pNew->next = p; // p就是pos对应的节点q->next = pNew; // q就是pos的上一个节点return 0;}q = p;p = p->next;}// 情景4:找不到pos的位置(使用尾插法,大家也可以选择不插入)q->next = pNew;return 0;
}/*** @brief 遍历链表数据* @param head 待遍历的链表** @return*/
void llist_showAll(const NODE *head)
{// 首先使用一个指针变量接受形参const NODE *p = head;while (p){printf("%d\t", p->data);p = p->next; // 类似与顺序表中的p++,实现相邻节点之间的指针偏移}printf("\n");
}/*** @brief 根据data返回其对应的节点* @param head 待查找的链表* @param data 待查找的节点数据(相同数据只匹配第一个)* * @return 成功返回节点指针,失败返回NULL*/
NODE *llist_find(const NODE *head, DATA data)
{const NODE *p = head;while(p){if (memcmp(&(p->data), &data, sizeof(DATA)) == 0){return (NODE*)p;}p = p->next;}return NULL;
}/*** @brief 更新链表节点数据old为newdata* @param head 待更新的链表* @param old 待更新节点的数据* @param newdata 节点需要更新的数据* * @return 修改成功返回0,否则返回-1*/
int llist_update(const NODE *head, DATA old, DATA newdata)
{NODE *p = NULL;// 找到old对应的NODEif (!(p = llist_find(head,old))){return -1;}// 更新数据p->data = newdata;return 0;
}/*** @brief 删除链表中节点值为data的节点* @param head 待删除节点链表* @param data 待删除节点数据* * @return 删除成功返回0,否则返回-1*/
int llist_delete(NODE **head, DATA data)
{NODE *p = *head, *q = NULL;// 情景1:空链表if (!p) return -1;// 情景2:头节点if (memcmp(&(p->data), &data, sizeof(DATA)) == 0){*head = p->next;// 回收节点free(p);return 0;}// 情景3:非头节点(含尾节点)while(p){if (memcmp(&(p->data), &data, sizeof(DATA)) == 0){q->next = p->next;// 让p的上一个节点的next指向p的下一个节点,实际上就是从链表中将p剔除free(p);return 0;}// 指针偏移q = p;p = p->next;}return -1;
}/*** @brief 销毁链表* @param head 待销毁的链表* * @return */
void llist_destroy(NODE **head)
{NODE *p = *head, *q = NULL;while (p){q = p;p = p->next;free(q);}// 重置头指针*head = NULL;
}
文件:linkedList.h
#ifndef LINKEDLIST_H
#define LINKEDLIST_H// 引用相关头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 给数据设置一个别名,本次涉及的所有数据结构的存储数据的类型都是int,大家做项目的时候,可以替换成相应的结构体
typedef int DATA;// 创建链表的节点结构体
typedef struct node
{DATA data; // 数据域:存放节点数据struct node *next; // 指针域:指向下一个同类型节点
} NODE;/*** @brief 链表的创建(没有指定头结点的前提下进行(本案例涉及的是无头节点))* @param head 待操作链表,如果是改变链表结构,使用二级指针* @param data 待插入数据* @return 创建成功返回0,否则返回-1*/
extern int llist_create(NODE **head, DATA data); /*** @brief 向链表头部插入一个节点数据(头插法)* @param head 待操作链表,如果是改变链表结构,使用二级指针* @param data 待插入数据* @return 创建成功返回0,否则返回-1*/
extern int llist_addHead(NODE **head, DATA data);/*** @brief 向链表尾部插入一个节点数据(尾插法)* @param head 待操作链表,如果是改变链表结构,使用二级指针* @param data 待插入数据* @return 创建成功返回0,否则返回-1*/
extern int llist_addTail(NODE **head, DATA data);/*** @brief 向链表指定位置插入一个节点数据(中间插法)* @param head 待操作链表,如果是改变链表结构,使用二级指针* @param pos 待插入位置数据* @param data 待插入数据* @return 创建成功返回0,否则返回-1*/
extern int llist_insert(NODE **head, DATA pos, DATA data);/*** @brief 遍历链表数据* @param head 待遍历的链表* * @return */
extern void llist_showAll(const NODE *head);/*** @brief 根据data返回其对应的节点* @param head 待查找的链表* @param data 待查找的节点数据(相同数据只匹配第一个)* * @return 成功返回节点指针,失败返回NULL*/
extern NODE *llist_find(const NODE *head, DATA data);/*** @brief 更新链表节点数据old为newdata* @param head 待更新的链表* @param old 待更新节点的数据* @param newdata 节点需要更新的数据* * @return 修改成功返回0,否则返回-1*/
extern int llist_update(const NODE *head, DATA old, DATA newdata);/*** @brief 删除链表中节点值为data的节点* @param head 待删除节点链表* @param data 待删除节点数据* * @return 删除成功返回0,否则返回-1*/
extern int llist_delete(NODE **head, DATA data);/*** @brief 销毁链表* @param head 待销毁的链表* * @return */
extern void llist_destroy(NODE **head);#endif