概述
NULL
code
#include "LinkList.h"
// 自定义数据类型
typedef struct PERSON{
char name[64];
int age;
int score;
}Person;
// test 函数
void test02();
void test03();
void test04();
// 用户自定义 打印函数
void myPrint(void*);
int main(int argc, char **argv){
test04();
return 0;
}
void test02(){
// 1. 创建一个链表
LinkList* list = Init_LinkList();
// 2. 插入数据
// 2-1 创建数据
Person p1 = {"aaa", 18, 100};
Person p2 = {"bbb", 17, 90};
Person p3 = {"ccc", 16, 80};
Person p4 = {"ddd", 15, 70};
Person p5 = {"eee", 14, 60};
// 2-2 数据插入链表 都插入第一个
Insert_LinkList(list, 0, &p1);
Insert_LinkList(list, 0, &p2);
Insert_LinkList(list, 0, &p3);
Insert_LinkList(list, 0, &p4);
Insert_LinkList(list, 0, &p5);
// 3 打印数据
Print_LinkList(list, myPrint);
// 4 销毁链表
FreeSpace_LinkList(list);
}
void test03(){
// 1. 创建一个链表
LinkList* list = Init_LinkList();
// 2. 插入数据
// 2-1 创建数据
Person p1 = {"aaa", 18, 100};
Person p2 = {"bbb", 17, 90};
Person p3 = {"ccc", 16, 80};
Person p4 = {"ddd", 15, 70};
Person p5 = {"eee", 14, 60};
// 2-2 数据插入链表 都插入第一个
Insert_LinkList(list, 0, &p1);
Insert_LinkList(list, 0, &p2);
Insert_LinkList(list, 0, &p3);
Insert_LinkList(list, 0, &p4);
Insert_LinkList(list, 0, &p5);
// 3 打印数据
Print_LinkList(list, myPrint);
// 4 删除数据 - 3号数据
RemoveByPos_LinkList(list, 3);
// 5 打印数据
Print_LinkList(list, myPrint);
// 6 销毁链表
FreeSpace_LinkList(list);
}
void test04(){
// 1. 创建一个链表
LinkList* list = Init_LinkList();
// 2. 插入数据
// 2-1 创建数据
Person p1 = {"aaa", 18, 100};
Person p2 = {"bbb", 17, 90};
Person p3 = {"ccc", 16, 80};
Person p4 = {"ddd", 15, 70};
Person p5 = {"eee", 14, 60};
// 2-2 数据插入链表 都插入第一个
Insert_LinkList(list, 0, &p1);
Insert_LinkList(list, 0, &p2);
Insert_LinkList(list, 0, &p3);
Insert_LinkList(list, 0, &p4);
Insert_LinkList(list, 0, &p5);
// 3 打印数据
Print_LinkList(list, myPrint);
// Person* pe = (Person*)Front_LinkList(list);
myPrint(Front_LinkList(list));
// 4 销毁链表
FreeSpace_LinkList(list);
}
void myPrint(void* data){
// 1. 将数据data进行类型转换
Person* p = (Person*)data;
// 2. 打印数据
printf("Name: %s\t Age: %d\t Score: %d\n", p->name, p->age, p->score);
}
#include "LinkList.h"
// 1. 初始化链表
LinkList* Init_LinkList(){
// 1-1 分配内存
LinkList* list = (LinkList*)malloc(sizeof(LinkList));
list->size = 0;
// 1-2 保证头节点存在性:如果没有头节点需要考虑数据是否插入到头节点了;如果有头结点就不需要考虑这个问题;为了
// 为了让链表实现起来思路更加清晰简单;带不带都可以,只不过是说带了头结点问题会变得简单
list->head = (LinkNode*)malloc(sizeof(LinkNode));
list->head->data = NULL;
list->head->next = NULL;
return list;
}
// 2. 在指定位置插入 链表的位置是从0开始的
void Insert_LinkList(LinkList* list, int pos, void* data){
// 2-1 判断输入的有效性
if(list == NULL){
return;
}
if(data == NULL){
return;
}
// 2-1 判断位置:pos 越界;pos < 0; 的时候,默认插入尾部
if(pos < 0 || pos > list->size){
pos = list->size;
}
// 2-2 创建新的节点
LinkNode* newnode = (LinkNode*)malloc(sizeof(LinkNode));
newnode->data = data;
newnode->next = NULL;
// 2-3 寻找 pos 的前一个节点
LinkNode* pCurrent = list->head; // 辅助指针变量; 先让它指向list的头结点
for(int i = 0; i < pos; i++){
pCurrent = pCurrent->next;
}
// 2-4 新节点入列表
newnode->next = pCurrent->next;
pCurrent->next = newnode;
list->size++;
}
// 3. 删除指定位置的值
void RemoveByPos_LinkList(LinkList* list, int pos){
// 3-1 判断输入的有效性
if(list == NULL){
return;
}
// 3-1 判断位置:pos 越界;pos < 0;
if(pos < 0 || pos >= list->size){
return;
}
// 3-2 寻找位置的前一个节点
LinkNode* pCurrent = list->head;
for(int i = 0; i < pos; i++){
pCurrent = pCurrent->next;
}
// 3-3 删除节点
LinkNode* pDel = pCurrent->next;
pCurrent->next = pDel->next;
// 3-4 释放空间
free(pDel);
list->size--;
}
// 4. 获得链表的长度
int Size_LineList(LinkList* list){
if(list == NULL){
return -1;
}
return list->size;
}
// 5. 返回第一个节点
void* Front_LinkList(LinkList* list){
return list->head->next->data; // 若该链表为空,那么就返回NULL
}
// 6. 释放链表内存
void FreeSpace_LinkList(LinkList* list){
if(list == NULL){
return;
}
// 6-1 释放内存; 每一个节点的内存都是手动分配,所以每一个节点都需要手动释放,需要变量
LinkNode* pCurrent = list->head;
LinkNode* pNext = NULL;
while(pCurrent != NULL){
pNext = pCurrent->next;
free(pCurrent);
pCurrent = pNext;
}
// 6-2 释放链表内存
free(pNext);
list->size = 0; // 可写可不写,习惯写上
free(list);
}
// 7. 查找某个值 根据指针(地址)来查找某个值
int Find_LinkList(LinkList* list, void* data){
// 7-1 有效性判断
if(list == NULL){
return -1;
}
if(data == NULL){
return -1;
}
// 7-2 遍历查找
LinkNode* pCurrent = list->head->next; // 因为head不保存数据,所以将其执行head的下一个节点
int i = 0;
for(; i < list->size; i++){
if(pCurrent->data == data)
break;
pCurrent = pCurrent->next;
}
return i;
}
// 8. 打印链表节点 事先不知道data是什么类型的;开发者不确定的事情,让用户去完成
// 这样每一次打印的时候,调用用户传递进来的函数即可 print 是打印函数指针
void Print_LinkList(LinkList* list, PRINTLINKNODE print){
if(list == NULL){
return;
}
// 打印数据
LinkNode* pCurrent = list->head->next;
while(pCurrent != NULL){
// 打印数据,因为不知道数据类型,调用用户传进来的函数
print(pCurrent->data);
pCurrent = pCurrent->next;
}
printf("---------------------------------------\n");
}
#ifndef LINK_LIST_H
#define LINK_LIST_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* @brief 线性表的链式存储:用不连续的内存空间、
*
* 链表是由一系列的节点组成,每个节点包括两个域,指针域和数字域;需要指针域保存下一个节点的地址;
* 当指针域指向为NULL,代表链表结束
*
* 若想要插入一个新的节点。首先需要找到该位置的前一个节点,使用新的节点的指针域指向前一个节点的后一个节点;最后将前一个节点的指针域指向新的节点的首地址
*
* 若想要删除一个节点,首先需要找到该节点和它前一个节点,其次让前一个节点的指针域指向该节点的下一个节点,最后让该节点的指针域设置为空,释放该节点的内存
*/
// 0-1. 链表节点
typedef struct LINKNODE{
void* data; // 无类型指针:使用无类型指针指向任意数据类型的数据
struct LINKNODE* next;
}LinkNode;
// 0-2. 建立链表
typedef struct LINKLIST{
LinkNode* head; // 头节点
int size; // 链表的大小
// 不需要容量
}LinkList;
// 0-3 打印函数指针: 形参类型是 void*, 返回值是 void
typedef void(*PRINTLINKNODE)(void *);
// 1. 初始化链表
LinkList* Init_LinkList();
// 2. 在指定位置插入
void Insert_LinkList(LinkList* list, int pos, void* data);
// 3. 删除指定位置的值
void RemoveByPos_LinkList(LinkList* list, int pos);
// 4. 获得链表的长度
int Size_LineList(LinkList* list);
// 5. 返回第一个节点
void* Front_LinkList(LinkList* list);
// 6. 释放链表内存
void FreeSpace_LinkList(LinkList* list);
// 7. 查找某个值 根据指针来查找某个值
int Find_LinkList(LinkList* list, void* data);
// 8. 打印链表节点 事先不知道data是什么类型的;开发者不确定的事情,让用户去完成
// 这样每一次打印的时候,调用用户传递进来的函数即可 print 是打印函数指针
void Print_LinkList(LinkList* list, PRINTLINKNODE print);
#endif
# 执行指令
gcc -fPIC -shared LinkList.c -o liblinkList.so
gcc main.c -o main -L ./ -llinkList -Wl,-rpath ./