数据结构--无头单向非循环链表接口的实现

1 无头单向非循环链表结构

无头单向非循环链表的示意图如下:
在这里插入图片描述
它的定义如下:

//无头单向非循环链表的定义
typedef int LDataType;
typedef struct ListNode {
LDataType data;
struct ListNode* next;
}ListNode;


typedef struct List {
ListNode* head;
}List;

2 无头单向非循环链表接口的实现

2.1 头文件及链表的定义

#include<stdio.h>
#include<stdlib.h>

typedef int LDataType;
typedef struct ListNode {
	LDataType data;         //存储的数据
	struct ListNode* next;   //指向下一个节点
}ListNode;

typedef struct List {
	ListNode* head;    //指向链表节点的指针
}List;

2.2 链表的初始化

//链表的初始化
void listInit(list* lst) {
	//链表的初始化就是使head的指向为空
	if (lst == NULL)
		return;       //判断参数是否有效
	lst->head = NULL;
}

2.3 创建一个新节点

//创建一个新节点
listNode* creatNode(LDataType val) {
	//创建一个链表节点,使节点的数据值为val,next指向空
	//返回创建节点的地址
	listNode* node = (listNode*)malloc(sizeof(listNode));
	//申请一个大小为listNode类型的空间,并返回该空间的地址
	node->data = val;
	node->next = NULL;
	return node;
}

2.4 尾插一个数据

//尾插一个数据
void ListPushBack(list* lst, LDataType val) {
	/*1、先判断链表是否为空链表,空链表直接进行尾插,非空则进行如下操作
	  2、得到链表的最后一个节点,地址保存在end中
	* 3、创建一个新的节点,地址保存在node中
	* 4、进行尾插
	*/
	if (lst == NULL)
		return;
	//1、先判断链表是否为空链表
	if (lst->head == NULL) {
		lst->head = creatNode(val);
		return;
	}
	//2、得到最后的节点end
	listNode * end;
	end = lst->head;
	while (end->next != NULL) {
		end = end->next;
	}                     

	//3、创建一个新的节点
	listNode* node = creatNode(val);

	//4、进行尾插
		end->next = node;
}

2.5 尾删一个数据

//尾删一个数据
void ListPopBack(list* lst) {
	/*
	* 1、首先判断链表是否为空链表,若为空,则直接返回,若不为空,进行如下操作
	* 2、找到最后一个节点,记录在end中,并记录上一个节点的位置,记录在perv中
	* 3、释放最后一个节点,使prev->next=NULL
	*/
	//1、若链表为空,则直接返回
	if (lst == NULL || lst->head == NULL)
		return;
	//2、找到最后一个节点并记录前一个节点
	listNode* prev, * end;
	prev = NULL;
	end = lst->head;
	while (end->next != NULL) {
		prev = end;
		end = end->next;
	}
	//prev可能为NULL,也可能不为NULL

	//3、释放最后一个节点
	free(end);
	if (prev == NULL) {
		lst->head = NULL;
	}else
		prev->next = NULL;
}

2.6 头插一个数据

//头插一个数据
void listPushFront(list* lst, LDataType val) {
	/*1、判断是否为空链表,空链表直接插入,非空则进行如下操作
	* 2、创建一个新的节点node
	* 3、node->next = lst->head , lst->head = node ;
	* 4、可以观察出,空链表和非空链表的插入过程相同,可以进行一个合并
	*/
	if (lst == NULL)
		return;
	listNode* node = creatNode(val);
	node->next = lst->head;
	lst->head = node;     
	//注意:上面两条语句的顺序不能发生变化,否则会使链表后面的语句丢失
	/*若不考虑两者的顺序,也可以写成
	* listNode* next = lst->head ;
	* lst->head = node ;
	* node->next = next ;
	*/
}

2.7 头删一个数据

void listPopFront(list* lst) {
	/*1、首先判断链表是否为空,空链表直接返回
	* 2、记录第二个节点的位置next和第一个节点的位置node
	* 3、释放node
	* 4、lst->head = next 
	*/
	//1、空链表直接返回
	if (lst == NULL || lst->head == NULL) {
		return;
	}
	//2、记录节点位置
	listNode* next, * node;
	node = lst->head;
	next = node->next;
	//3、删除节点
	free(node);
	lst->head = next;

}

2.8 在给定节点后插入一个数据

//在给定节点之后删除一个数据
void listEraseAfter(listNode* cur) {
	/*1、记录下一个节点的位置next和下下个节点的位置nextnext
	* 2、释放next;cur->next = nextnext
	*/
	listNode* next = cur->next;
	if (next == NULL)
		return;
	listNode* nextnext = next->next;
	free(next);
	cur->next = nextnext;
}

2.9 在给定节点之后删除一个数据

//在给定节点之后删除一个数据
void listEraseAfter(listNode* cur) {
	/*1、记录下一个节点的位置next和下下个节点的位置nextnext
	* 2、释放next;cur->next = nextnext
	*/
	listNode* next = cur->next;
	listNode* nextnext = next->next;
	free(next);
	cur->next = nextnext;
}

2.10 查找某个节点

listNode* listFind(list* lst, LDataType val) {
	/*1、若为空链表,则直接返回
	* 2、遍历整个链表,查找data==val的节点
	*/
	if (lst == NULL || lst->head == NULL)
		return;
	listNode* cur = lst->head;
	while (cur) {
		if (cur->data == val) {
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

2.11 求链表的长度

//求链表的长度
int listSize(list* lst) {
	/*1、若为空链表,则直接返回0
	* 2、遍历整个链表,计算链表的长度
	*/
	if (lst == NULL || lst->head == NULL)
		return;
	listNode* cur = lst->head;
	int len = 0;
	while (cur) {
		len++;
		cur = cur->next;
	}
	return len;
}

2.12 打印链表

void printList(list* lst) {
	//遍历整个链表依次进行打印
	if (lst == NULL)
		return;
	listNode* cur = lst->head;
	while (cur) {
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

2.13 查找第n个位置的节点

//查找某个节点
listNode* listFindByIdx(list* lst, int n) {
	/*1、若为空链表,则直接返回
	* 2、遍历整个链表,查找第n个节点
	*/
	if (lst == NULL || lst->head == NULL)
		return;
	listNode* cur = lst->head;
	int len = 0;
	while (len < n && cur != NULL) {
		cur = cur->next;
		len++;
	}
	if (len >= n)
		return cur;
	if (cur == NULL)
		return NULL;
}

2.14 销毁一个链表

//销毁一个链表
void listDestroy(list* lst) {
	/*1、若为空链表则直接返回
	* 2、进行头删操作,直至链表清空
	*/
	if (lst == NULL || lst->head == NULL)
		return;
	listNode* cur = lst->head;
	while (cur) {
		lst->head = cur->next;
		free(cur);
		cur = lst->head;
	}
}

注意:
1、进行操作前,一般先考虑链表为空的情况,在考虑链表非空的情况;
2、若程序无法识别list类型,则写全类型名:struct list;

3 验证链表的接口

int main() {
	list lst;
	listInit(&lst);//初始化链表
	listPushBack(&lst, 1);//尾插1
	//链表为1
	printList(&lst); //打印链表
	listPushBack(&lst, 2);//尾插2
	//链表为1->2
	printList(&lst); //打印链表
	listPushFront(&lst, 0);//头插0
	//链表为0->1->2
	printList(&lst); //打印链表
	
	listNode* cur = listFind(&lst ,0);//查找值为0的节点
	listInsertAfter(cur, 11);//在值为0的节点的后方插入11
	//链表为0->11->1->2
	printList(&lst); //打印链表
	cur = listFindByIdx(&lst, listSize(&lst) - 1);
	listInsertAfter(cur, 13);//尾插13
	//链表为0->11->1->2->13
	printList(&lst); //打印链表

	listPopBack(&lst);//尾删
	//链表为0->11->1->2
	printList(&lst); //打印链表
	listPopFront(&lst);//头删
	//链表为11->1->2
	printList(&lst); //打印链表
	cur = listFindByIdx(&lst, 0);
	listEraseAfter(cur);//删除位置0之后的节点
	//链表为11->2
	printList(&lst); //打印链表
	cur = listFindByIdx(&lst, listSize(&lst) - 2);
	listEraseAfter( cur);//尾删
	//链表为11
	printList(&lst); //打印链表
	listDestroy(&lst);//销毁链表
	printList(&lst); //打印链表
	system("pause");
	return 0;
}

运行结果如下图:
在这里插入图片描述

  • 一个小技巧
    可以将所有的全局变量及函数声明均定义在一个头文件中,这样,就不用考虑.c文件中函数的先后顺序了。
    这里头文件内容如下:
typedef int LDataType;
typedef struct listNode {
	LDataType data;         //存储的数据
	struct ListNode* next;   //指向下一个节点
}listNode;

typedef struct list {
	listNode* head;    //指向链表节点的指针
}list;

void listInit(list* lst);
listNode* creatNode(LDataType val);
void listPushBack(list* lst, LDataType val);
void listPopBack(list* lst);
void listPushFront(list* lst, LDataType val);
void listPopFront(list* lst);
void listInsertAfter(listNode* cur, LDataType val);
void listEraseAfter(listNode* cur);
void printList(list* lst);
listNode* listFind(list* lst, LDataType val);
listNode* listFindByIdx(list* lst, int n);
int listSize(list* lst);
void listDestroy(list* lst);

.c文件中所要声明的头文件如下:

#include<stdio.h>
#include<stdlib.h>
#include"list.h"
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值