1.链表的概念
链表也叫链式存储结构或单链表,它用于存储逻辑关系为 "一对一" 的数据。
使用链表存储的数据元素,其物理存储位置是随机的。
链表中每个数据元素在存储时都配备一个指针,用于指向自己的直接后继元素。
链表中的节点包含有:数据域和指针域
顾名思义,数据域就是存放数据的,指针域用于存放后继元素地址
链表分为:静态链表和动态链表
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
//1、静态链表
//节点的声明
struct LinkNode
{
int num;
struct LinkNode* next;//指针域
};
static void test01()
{
//创建节点
struct LinkNode node1 = { 10,NULL };
struct LinkNode node2 = { 20,NULL };
struct LinkNode node3 = { 30,NULL };
struct LinkNode node4 = { 40,NULL };
struct LinkNode node5 = { 50,NULL };
//建立关系
node1.next = &node2;
node2.next = &node3;
node3.next = &node4;
node4.next = &node5;
//如何遍历这个链表
struct LinkNode* pCurrent = &node1;
while (pCurrent != NULL)
{
printf("%d\n", pCurrent->num);
pCurrent = pCurrent->next;
}
}
//2、动态链表
static void test02()
{
struct LinkNode* node1 = malloc(sizeof(struct LinkNode));
struct LinkNode* node2 = malloc(sizeof(struct LinkNode));
struct LinkNode* node3 = malloc(sizeof(struct LinkNode));
struct LinkNode* node4 = malloc(sizeof(struct LinkNode));
struct LinkNode* node5 = malloc(sizeof(struct LinkNode));
node1->num = 10;
node2->num = 20;
node3->num = 30;
node4->num = 40;
node5->num = 50;
//建立关系
node1->next = &node2;
node2->next = &node3;
node3->next = &node4;
node4->next = &node5;
node5->next = NULL;
//遍历链表
struct LinkNode* pCurrent = node1;
while (pCurrent != NULL)
{
printf(":::%d\n", pCurrent->num);
pCurrent = pCurrent->next;
}
//释放节点
free(node1);
free(node2);
free(node3);
free(node4);
free(node5);
}
int main01()
{
//test01();
test02();
return 0;
}
2.链表的基础使用
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include "02_linklist.h"
static void test01()
{
//初始化链表
struct LinkNode* pHeader = init_LinkList();
//遍历链表
printf("遍历链表的结果为\n");
foreach_LinkList(pHeader);
//插入数据
// 100 10 200 20 30 300
insert_LinkList(pHeader, 10, 100);
insert_LinkList(pHeader, 20, 200);
insert_LinkList(pHeader, -1, 300);
printf("插入数据后,遍历链表的结果为\n");
foreach_LinkList(pHeader);
//测试 删除
delete_LinkList(pHeader, 30);
delete_LinkList(pHeader, 100);
delete_LinkList(pHeader, 1000);
// 10 200 20 300
printf("删除数据后,遍历链表的结果为\n");
foreach_LinkList(pHeader);
//清空链表
clear_LinkList(pHeader);
printf("清空数据后,遍历链表的结果为\n");
foreach_LinkList(pHeader);
insert_LinkList(pHeader, 111, 111);
insert_LinkList(pHeader, 222, 222);
insert_LinkList(pHeader, 333, 333);
printf("清空后再次使用链表,遍历链表的结果为\n");
foreach_LinkList(pHeader);
//销毁链表
destroy_LinkList(pHeader);
pHeader = NULL;
}
int main02()
{
test01();
system("pause");
return EXIT_SUCCESS;
}
#include "02_linklist.h"
//初始化链表
struct LinkNode* init_LinkList()
{
struct LinkNode* pHeader = malloc(sizeof(struct LinkNode));
if (pHeader == NULL)
{
return NULL;
}
//pHeader->num = -1; 头节点不维护数据域
pHeader->next = NULL; //头节点初始化指针域为NULL
//创建一个尾节点,利用后期添加新的数据
struct LinkNode* pTail = pHeader;
int val = -1;
while (1)
{
printf("请插入数据 -1代表输入结束:\n");
scanf("%d", &val);
if (val == -1)
{
break;
}
//创建新节点
struct LinkNode* newNode = malloc(sizeof(struct LinkNode));
newNode->num = val;
newNode->next = NULL;
//建立关系
pTail->next = newNode;
//更新新的尾节点
pTail = newNode;
}
return pHeader;
}
//遍历链表
void foreach_LinkList(struct LinkNode* pHeader)
{
if (pHeader == NULL)
{
return;
}
//pCurrent 起始指向的是第一个有真实数据的节点
struct LinkNode* pCurrent = pHeader->next;
while (pCurrent != NULL)
{
printf("%d\n", pCurrent->num);
pCurrent = pCurrent->next;
}
}
//插入链表
void insert_LinkList(struct LinkNode* pHeader, int oldVal, int newVal)
{
if (pHeader == NULL)
{
return;
}
//创建两个辅助指针变量
struct LinkNode* pPrev = pHeader;
struct LinkNode* pCurrent = pHeader->next;
while (pCurrent != NULL)
{
if (pCurrent->num == oldVal) //找到插入位置
{
break;
}
//如果没有找到位置,让辅助指针后移
pPrev = pCurrent;
pCurrent = pCurrent->next;
}
//创建新节点
struct LinkNode* newNode = malloc(sizeof(struct LinkNode));
newNode->num = newVal;
newNode->next = NULL;
//建立关系 更新指针的指向
newNode->next = pCurrent;
pPrev->next = newNode;
}
//删除链表
void delete_LinkList(struct LinkNode* pHeader, int val)
{
if (pHeader == NULL)
{
return;
}
//创建两个辅助指针变量
struct LinkNode* pPrve = pHeader;
struct LinkNode* pCurrent = pHeader->next;
while (pCurrent != NULL)
{
if (pCurrent->num == val)
{
break;
}
pPrve = pCurrent;
pCurrent = pCurrent->next;
}
//无效数据 就直接return
if (pCurrent == NULL)
{
return;
}
//更改指针的指向
pPrve->next = pCurrent->next;
//删除节点
free(pCurrent);
pCurrent = NULL;
}
//清空链表
void clear_LinkList(struct LinkNode* pHeader)
{
if (pHeader == NULL)
{
return;
}
//创建临时指针
struct LinkNode* pCurrent = pHeader->next;
while (pCurrent != NULL)
{
//先保存住待删除节点的后面的节点
struct LinkNode* nextNode = pCurrent->next;
free(pCurrent);
pCurrent = nextNode;
}
//头节点的next置空
pHeader->next = NULL;
}
//销毁链表
void destroy_LinkList(struct LinkNode* pHeader)
{
if (pHeader == NULL)
{
return;
}
//先清空链表
clear_LinkList(pHeader);
//再释放头节点
free(pHeader);
pHeader = NULL;
}
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//节点声明
struct LinkNode
{
int num;
struct LinkNode* next;
};
//初始化链表
struct LinkNode* init_LinkList();
//遍历链表
void foreach_LinkList(struct LinkNode* pHeader);
//插入链表
void insert_LinkList(struct LinkNode* pHeader, int oldVal, int newVal);
//删除链表
void delete_LinkList(struct LinkNode* pHeader, int val);
//清空链表
void clear_LinkList(struct LinkNode* pHeader);
//销毁链表
void destroy_LinkList(struct LinkNode* pHeader);
3.函数指针的定义
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
static void func()
{
printf("hello world\n");
}
//函数指针的定义方式
static void test01()
{
//先定义出函数类型,再通过类型定义出函数指针
typedef void(FUNC_TYPE)();
FUNC_TYPE* pFunc = func;
pFunc();
}
static void test02()
{
//先定义出函数指针类型,再定义函数指针
typedef void(*FUNC_TYPE)();
FUNC_TYPE pFunc = func;
pFunc();
}
static void test03()//通常使用第三种
{
//直接定义函数指针变量
void(*pFunc)() = func;//void 是func的返回值 (*pFunc)是函数名称 ()是函数参数列表
pFunc();
}
//函数指针的数组
static void func1()
{
printf("func1的调用\n");
}
static void func2()
{
printf("func2的调用\n");
}
static void func3()
{
printf("func3的调用\n");
}
static void test04()
{
//函数指针数组的定义
void(*pFunc[3])();
pFunc[0] = func1;
pFunc[1] = func2;
pFunc[2] = func3;
for (int i = 0; i < 3; i++)
{
pFunc[i]();
}
}
//函数指针 和 指针函数 的区别
//函数指针 是指向函数的指针
//指针函数 是函数的返回值是一个指针的函数
int main03()
{
//test01();
//test02();
test03();
return 0;
}
4.函数指针作为函数参数
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//提供一个函数,可以将任意的数据类型 打印出来
static void printText(void* a, void(*myPrint)(void*))
{
myPrint(a);
}
static void myPrintInt(void* data)
{
int* num = data;
printf("%d\n", *num);
}
static void test01()
{
int a = 100;
printText(&a, myPrintInt);
}
struct Person
{
char name[64];
int age;
};
static void myPrintPerson(void* data)
{
struct Person* p = data;
printf("姓名: %s 年龄: %d\n", p->name, p->age);
}
static void test02()
{
struct Person p = { "aaa", 10 };
printText(&p, myPrintPerson);
}
int main04()
{
//test01();
test02();
system("pause");
return EXIT_SUCCESS;
}
5.回调函数
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//1、提供一个函数,可以打印任意类型的数组
static void printAllArray(void* arr, int eleSize, int len, void(*myFunc)(void*))
{
char* p = arr;
for (int i = 0; i < len; i++)
{
char* eleAddr = p + i * eleSize; //计算每个元素首地址
//printf("%d\n", *(int*)eleAddr);
myFunc(eleAddr);
}
}
static void myPrintInt(void* data)
{
int* num = data;
printf("%d\n", *num);
}
static void test01()
{
int arr[6] = { 1,2, 3, 4, 5, 6 };
int len = sizeof(arr) / sizeof(int);
printAllArray(arr, sizeof(int), len, myPrintInt);
}
struct Person
{
char name[64];
int age;
};
static void myPrintPerson(void* data)
{
struct Person* p = data;
printf("姓名: %s 年龄: %d\n", p->name, p->age);
}
static void test02()
{
struct Person pArray[] =
{
{ "aaa", 10 },
{ "bbb", 20 },
{ "ccc", 30 },
{ "ddd", 40 },
};
int len = sizeof(pArray) / sizeof(struct Person);
printAllArray(pArray, sizeof(struct Person), len, myPrintPerson);
}
// 参数1 数组首地址 参数2 每个元素占的内存空间 参数3 元素个数 参数4 查找的元素的地址 参数5 回调函数
int myFindPerson(void* arr, int eleSize, int len, void* data, int (*myCompare)(void*, void*))
{
char* p = arr;
for (int i = 0; i < len; i++)
{
char* eleAddr = p + i * eleSize; //获取每个元素的首地址
//if ( eleAddr 和 data 的元素 相等 )
if (myCompare(eleAddr, data))
{
return 1;
}
}
return 0;
}
int myComparePerson(void* data1, void* data2)
{
struct Person* p1 = data1;
struct Person* p2 = data2;
if (strcmp(p1->name, p2->name) == 0 && p1->age == p2->age)
{
return 1;
}
return 0;
}
static void test03()
{
struct Person pArray[] =
{
{ "aaa", 10 },
{ "bbb", 20 },
{ "ccc", 30 },
{ "ddd", 40 },
};
struct Person p = { "ccc", 30 };
int len = sizeof(pArray) / sizeof(struct Person);
//查找数组中的元素,如果查找到返回1 ,找不到返回0
int ret = myFindPerson(pArray, sizeof(struct Person), len, &p, myComparePerson);
if (ret)
{
printf("找到了元素\n");
}
else
{
printf("未找到元素\n");
}
}
int main() {
//test01();
//test02();
test03();
system("pause");
return EXIT_SUCCESS;
}