线性表(6)——单链表功能实现

目录

1. LinkList.c各种功能函数的实现;

1.1 初始化链表;

1.2 元素的指定位置插入;

1.3 删除指定位置的元素;

 1.4 查找指定值的元素;

1.5 返回第一个结点;

1.6 打印链表结点;

1.7 释放链表内存;

2. main.c测主函数测试;


上一节我们说了单链表的函数框架搭建;现在来说一下函数功能的代码实现;

每个功能函数都有一个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;
}

测试结果:

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值