目录
上一节我们说了单链表的函数框架搭建;现在来说一下函数功能的代码实现;
每个功能函数都有一个LinkList* list的参数,因此要对list是否为空进行判断;
对于每个功能函数的参数,我们都要对其进行判断是否为空或者有效;
1. LinkList.c各种功能函数的实现;
1.1 初始化链表;
1. 首先对整个链表的结构体进行初始化;
2. 然后对链表结点的结构体进行初始化;
//初始化链表
LinkList* Init_LinkList(){
LinkList* list = (LinkList*)malloc(sizeof(LinkList));
list->size = 0;
//链表的头结点是不保存数据信息的,头结点也要分配空间
list->head = (LinkNode*)malloc(sizeof(LinkNode));
list->head->data = NULL;
list->head->next = NULL;
return list;
}
1.2 元素的指定位置插入;
1. 对函数的三个参数list,pos,data都要进行非空判断;
2. 插入新的元素的时候要注意以下几步:
(1)第一步,创建新的结点 ,也就是待插入的结点;
(2)第二步,找到待插入结点位置的前一个结点pCurrent;
(3)第三步,新结点入链表,进行插入操作;
(3)第四步,链表的元素个数size要加1;
//指定位置插入
void Insert_LinkList(LinkList* list, int pos, void* data){
//判断list是否有效
if (list == NULL){
return;
}
//判断data是否有效
if (data == NULL){
return;
}
//判断位置pos是否有效
if (pos<0 || pos>list->size){
//在链表的尾部插入
pos = list->size;
}
//第一步,创建新的结点,也就是待插入的结点newNode
LinkNode* newNode = (LinkNode*)malloc(sizeof(LinkNode));
//其中数据域为参数列表中的data
newNode->data = data;
newNode->next = NULL;
//第二步,找到待插入结点位置的前一个结点pCurrent
//从头结点开始遍历,一直找到i小于pos即可
LinkNode* pCurrent = list->head;
for (int i = 0; i < pos; i++){
//循环条件是一直往下遍历
pCurrent = pCurrent->next;
}
//第三步,新结点入链表,进行插入操作
newNode->next = pCurrent->next;
pCurrent->next = newNode;
//第四步,链表的元素个数size要加1
list->size++;
}
1.3 删除指定位置的元素;
1. 对函数的两个参数list和pos都要进行非空判断;
2. 删除元素时要注意以下几步:
(1)第一步,找到待插入结点位置的前一个结点pCurrent;
(2)第二步,先缓存待删除的结点pDel,也就是借助pCurrent结点将待删除结点pDel表示出来;
(3)第三步,进行删除元素操作;
(4)第四步,释放待删除结点pDel的内存;
(5)第五步,链表的元素个数size要减1;
//删除指定位置的值
void RemoveByPos_LinkList(LinkList* list, int pos){
//判断list是否有效
if (list == NULL){
return;
}
//判断待删除位置pos是否有效
if (pos < 0 || pos >= list->size){
return;
}
//第一步,找到待删除结点位置的前面一个结点pCurrent
LinkNode* pCurrent = list->head;
for (int i = 0; i < pos; i++){
pCurrent = pCurrent->next;
}
//第二步,先缓存待删除的结点pDel,也就是借助pCurrent结点将待删除结点pDel表示出来
LinkNode* pDel = pCurrent->next;
//第三步,进行删除元素操作
pCurrent->next = pDel->next;
//第四步,释放待删除结点pDel的内存
free(pDel);
//第五步,链表的元素个数size要减1
list->size--;
}
1.4 查找指定值的元素;
1. 对函数的两个参数list和data都要进行非空判断;
2. 查找元素时要注意以下几步:
(1)第一步,创建辅助指针结点pCurrent,并令其等于头指针后面的一个元素;
(2)第二步,直接进行遍历查找,若找到相等的值,则返回位置i即可;
//查找
int Find_LinkList(LinkList* list, void* data){
if (list == NULL){
return -1;
}
if (data == NULL){
return -1;
}
//第一步,创建辅助指针pCurrent,
//令其等于头指针后面的一个元素,因为头指针是不存放数据信息的
LinkNode* pCurrent = list->head->next;
//第二步,进行遍历查找
int i ;
for (i = 0; i < list->size; i++){
if (pCurrent->data == data){
break;
}
pCurrent = pCurrent->next;
}
return i;
}
1.5 返回第一个结点;
1. 对函数的参数list要进行非空判断;
2. 注意第一个结点不是头结点,而是头结点后面的第一个结点;
3. 返回第一个结点元素时直接返回就可以了;
//返回第一个结点
void* Front_LinkList(LinkList* list){
//头结点后面的一个结点才是第一个结点
return list->head->next->data;
}
1.6 打印链表结点;
1. 对函数的参数list要进行非空判断;
2. 这里用户传入的数据要转换成任何数据类型的也就是void*类型的;
3. 打印时用遍历打印;
//打印链表结点,用户传入的数据转换成void*类型的
void Print_LinkList(LinkList* list, PRINTLINKNODE print){
if (list == NULL){
return;
}
//定义辅助指针变量
LinkNode* pCurrent = list->head->next;
//进行遍历打印
for (int i = 0; i < list->size; i++){
print(pCurrent->data);
pCurrent = pCurrent->next;
}
}
1.7 释放链表内存;
1. 对函数的参数list要进行非空判断;
2. 释放链表内存时要注意以下几步:
(1)第一步,创建辅助指针结点pCurrent,并令其等于头指针;
(2)第二步,循环释放每一个结点的内存;
(3)第三步,释放链表的内存;
//释放链表内存
void FreeSpace_LinkList(LinkList* list){
if (list == NULL){
return;
}
//第一步,定义辅助指针变量
//注意这里是从头结点开始,因为头结点也占有内存
LinkNode* pCurrent = list->head;
//第二步,循环释放每一个结点的内存
for (int i = 0; i < list->size; i++){
//注意这里要先找到当前结点的下一个结点
//否则的话,要是当前结点内存释放了,则我们就找不到后面的结点了
LinkNode* pNext = pCurrent->next;
//释放当前结点的内存
free(pCurrent);
//令当前结点等于下一个结点
pCurrent = pNext;
}
//第三步,释放链表内存
list->size = 0;
free(list);
}
2. main.c测主函数测试;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LinkList.h"
//用户自定义数据类型
typedef struct Person{
char name[32];
int age;
int score;
}person;
//打印函数
void MyPrint(void* data){
//传入的是void*类型的数据,最后强转为person*类型的数据
person* p = (person*)data;
printf("name:%s age:%d score:%d\n",p->name,p->age,p->score);
}
int main(void){
//创建链表
LinkList* list = Init_LinkList();
//创建数据
person p1 = { "王昭君", 18, 100};
person p2 = { "公孙离", 19, 99 };
person p3 = { "李白", 20, 101 };
person p4 = { "貂蝉", 17, 97 };
person p5 = { "孙尚香", 16, 59 };
//数据插入链表
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);
//打印
printf("**********具体数据为**********\n");
Print_LinkList(list, MyPrint);
printf("\n");
//删除pos为3的元素
RemoveByPos_LinkList(list, 3);
//打印
printf("*******删除之后的数据为*******\n");
Print_LinkList(list, MyPrint);
printf("\n");
//返回第一个结点,数据类型是void*类型的
printf("*****返回第一个结点数据为*****\n");
person* p=(person*)Front_LinkList(list);
printf("name:%s age:%d score:%d\n", p->name, p->age, p->score);
printf("\n");
//查找元素
printf("*******元素p5的位置是*********\n");
int pos=Find_LinkList(list, &p2);
printf("元素p5的位置是:%d", pos);
printf("\n");
//释放链表内存
FreeSpace_LinkList(list);
system("pause");
return 0;
}
测试结果: