在学习中对于链表的实现。链表的增删查改等操作(C语言版)

本文探讨了作为程序员学习链表的重要性,并详细介绍了如何在C语言中实现不带头不带环单向链表的增、删、查、改操作。通过练习这些基础操作,可以深化对链表数据结构的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 大家都不陌生,一个程序员,语言是基础,数据结构是核心之一,因此,

在学习过程中必须反复练习,那么今天我们来看看对与数据结构中,链表的实现。

首先,我们要明确,在线性表中有两类,一是顺序表,分为动态顺序表和静态顺序表,

我们前面有介绍静态,二是链表,链表又分为八种,即:

1.不带头不带环单向链表。(学习)

2.带头不带环单向链表。

3.不带头带环单向链表。

4.带头带环单向链表。

5.不带头不带环双向链表。

6.带头不带环双向链表。

7.不带头带环双向链表。

8.带头带环双向链表。(常用)

这八种基本相似,但在学习阶段都需要练习,今天我把我练习的,不带头不带环单项链表。

一下为代码的声明。

#pragma once

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


#define DIV_LINE printf("\n\n===========%s==========\n\n",__FUNCTION__);

typedef char TypeChar;

typedef struct LinkNode
{
	TypeChar data;
	struct LinkNode *next;
}LinkNode;

//对单链表进行初始化
void InitLinkNode(LinkNode **head);

//打印
void LinkNodePrint(LinkNode *head);

//创建节点
LinkNode *CreatNode(TypeChar value);

//对单链表进行尾插;
LinkNode* PushBackLinkNode(LinkNode** head, TypeChar Value);

//对单链表进行尾删
void PopBackLinkNode(LinkNode** head);

//对单链表进行头插
void PushFrontLinkNode(LinkNode** head, TypeChar Value);

//对单链表进行头删
void PopFrontLinkNode(LinkNode** head);

//对单链表进行值位置的查找,返回对应值的地址
LinkNode* FindLinkNode(LinkNode* head, TypeChar value);

//在链表的指定位置之前插入元素,普通放方法,时间复杂度O(n)
void InsertFrontLinkNode(LinkNode** head, LinkNode* pos, TypeChar value);

//在链表的指定位置之前插入元素。(移花接木大法)时间复杂度为o(1).
void InsertFrontLinkNode1(LinkNode** head, LinkNode* pos, TypeChar value);

//在单链表指定位置之后插入元素。
void InsertAfterLinkNode(LinkNode* head, LinkNode* pos, TypeChar value);

//删除单链表中任意指定位置的节点。时间复杂度为o(n)
void EraseLinkNode(LinkNode** head, LinkNode* pos);

//删除单链表中指定位置的节点,(除过尾节点)时间复杂度为o(1).
void EraseLinkNode1(LinkNode* head, LinkNode* pos);

//删除指定值的节点,(在无头单链表中第一个出现的值的节点)
void RemoveLinkNode(LinkNode** head, TypeChar value);

//删除指定值的所有元素。
void RemoveLinkNodeAll(LinkNode** head, TypeChar value);

//判断链表是否为空
int EmotyLinkNode(LinkNode* head);

//求链表长度
size_t SizeLinkNode(LinkNode* head);

//将链表逆序打印
void BackPrintLinkNode(LinkNode* head);
代码的实现:

#include"LinkNode.h"

//打印
void LinkNodePrint(LinkNode *head)
{
	LinkNode* cur = NULL;
	printf("head:");
	if(head == NULL)
	{
		//空链表。
		return;
	}
	cur = head;
	
	while(cur != NULL)
	{
		printf("[%c:%p]-> ",cur->data,&cur->data);
		cur = cur->next;
	}
	printf("NULL\n\n");
}

//对单链表进行初始化
void InitLinkNode(LinkNode **head)
{
	if (head == NULL)
	{
		// 非法输入。
		return;
	}
	*head = NULL;
}

//创建节点
LinkNode *CreatNode(TypeChar value)
{
	LinkNode* new_node = (LinkNode *)malloc(sizeof(LinkNode));
	if(new_node == NULL)
	{
		//申请内存失败。
		return NULL;
	}
	new_node->next = NULL;
	new_node->data = value;
	return new_node;
}

//对单链表进行尾插;
LinkNode* PushBackLinkNode(LinkNode **head, TypeChar value)
{
	LinkNode *new_node = NULL;
	LinkNode *cur = NULL; 
	if(head == NULL)
	{
		//非法输入
		return NULL;
	}
	new_node = CreatNode(value);
	if(*head == NULL)
	{
		*head = new_node;
		return *head;
	}
	cur = *head;
	while(cur->next != NULL)
	{
		cur = cur->next;
	}
	cur->next = new_node;
	return new_node;
}

//对单链表进行尾删
void PopBackLinkNode(LinkNode **head)
{
	LinkNode* to_delete = NULL;
	LinkNode* cur = *head;
	if (head == NULL)
	{
		//非法输入。
		return ;
	}
	if (*head == NULL)
	{
		//为空链表。
		return;
	}
	if ((*head)->next == NULL)
	{
		free(*head);
		*head = NULL;
		return;
	}
	while (cur->next->next != NULL)
	{
		cur = cur->next;
	}
	to_delete = cur->next;
	free(to_delete);
	cur->next = NULL;
	return;
}

//对单链表进行头插
void PushFrontLinkNode(LinkNode** head, TypeChar value)
{
	LinkNode* cur = NULL;
	if (head == NULL)
	{
		//非法输入。
		return;
	}
	cur = CreatNode(value);
	cur->next = *head;
	*head = cur;
}

//对单链表进行头删
void PopFrontLinkNode(LinkNode** head)
{
	LinkNode* cur = NULL;
	if (head ==NULL)
	{
		//非法输入。
		return;
	}
	if (*head == NULL)
	{
		//为空列表。
		return;
	}
	cur = (*head)->next;
	free(*head);
	*head = cur;
}

//对单链表进行值位置的查找,返回对应值的地址
LinkNode* FindLinkNode(LinkNode* head, TypeChar value)
{
	LinkNode* cur = NULL;
	if (head == NULL)
	{
		//空链表。
		return NULL;
	}
	cur = head;
	while (cur != NULL)
	{
		if (cur->data == value)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//在链表的指定位置之前插入元素,普通放方法,时间复杂度O(n)
void InsertFrontLinkNode(LinkNode** head, LinkNode* pos, TypeChar value)
{
	LinkNode* new_node = NULL;
	LinkNode* cur = NULL;
	if (head == NULL || pos == NULL)
	{
		//非法输入。
		return;
	}
	if (*head == NULL)
	{
		//单链表为空。
		return;
	}
	cur = *head;
	if (cur == pos)   //对头节点进行判断,是否是pos.
	{
		PushFrontLinkNode(head, value);
		return;
	}
	while (cur->next != NULL)
	{
		if (cur->next == pos)
		{
			new_node = CreatNode(value);
			cur->next = new_node;
			new_node->next = pos;
			return;
		}
		cur = cur->next;
	}
	return;
}

//在链表的指定位置之前插入元素。(移花接木大法)时间复杂度为o(1).
void InsertFrontLinkNode1(LinkNode** head, LinkNode* pos, TypeChar value) //pos值必须要是合法节点
{
	LinkNode* new_node = NULL;
	if (head == NULL || pos == NULL)
	{
		//非法输入。
		return;
	}
	if (*head == NULL)
	{
		//链表为空。
		return;
	}
	new_node = CreatNode(pos->data);
	new_node->next = pos->next;
	pos->next = new_node;
	pos->data = value;
}

//在单链表指定位置之后插入元素。
void InsertAfterLinkNode(LinkNode* head, LinkNode* pos, TypeChar value)
{
	// 因为是在单链表之后插入元素,所以不会改变头指针,所以用* 而不用**
	LinkNode* new_node = NULL;
	if (head == NULL || pos == NULL)
	{
		//链表为空链表。
		return;
	}
	new_node = CreatNode(value);
	new_node->next = pos->next;
	pos->next = new_node;
	return;
}

//删除单链表中任意指定位置的节点。时间复杂度为o(n)
void EraseLinkNode(LinkNode** head, LinkNode* pos)
{
	LinkNode* cur = NULL;
	if (head == NULL || pos == NULL)
	{
		// 非法输入。
		return;
	}
	if (*head == NULL)
	{
		//链表为空。
		return;
	}
	if (*head == pos)
	{
		*head = (*head)->next;
		free(pos);
		return;
	}
	cur = *head;
	while (cur->next != NULL)
	{
		if (cur->next == pos)
		{
			cur->next = pos->next;
			pos->next = NULL;
			break;
		}
		cur = cur->next;
	}
	free(pos);
}

//删除单链表中指定位置的节点,(除过尾节点)时间复杂度为o(1).
void EraseLinkNode1(LinkNode* head, LinkNode* pos)
{
	LinkNode* temp = NULL;
	if (head == NULL || pos == NULL)
	{
		//链表为空,pos非法。
		return;
	}
	temp = pos->next;
	pos->data = temp->data;
	pos->next = temp->next;
	free(temp);
	return;
}

//删除指定值的节点,(在无头单链表中第一个出现的值的节点)
void RemoveLinkNode(LinkNode** head, TypeChar value)
{
	LinkNode* cur = NULL;
	LinkNode* temp = NULL;
	if (head == NULL)
	{
		//非法输入。
		return ;
	}
	if (*head == NULL)
	{
		//空链表。
		return ;
	}
	cur = *head;
	if (cur->data == value)  //头节点。
	{
		*head = (*head)->next;
		free(cur);
		return ;
	}
	while (cur->next != NULL)
	{
		if (cur->next->data == value)
		{
			temp = cur->next;        //赋值一定要注意保存原来指针指向的地址,以便于释放内存。
			cur->next = cur->next->next;//不明白画图。
			free(temp);
			break;
		}
		cur = cur->next;
	}
	
}

//删除指定值的所有元素。
void RemoveLinkNodeAll(LinkNode** head, TypeChar value)
{
	LinkNode* pos = NULL;
	int ret = 1;
	while (ret)
	{
		pos = FindLinkNode(*head, value);
		if (pos == NULL)
		{
			ret = 0;
		}
		EraseLinkNode(head, pos);
	}
	//LinkNode* cur = NULL;
	//LinkNode* temp = NULL;
	//LinkNode* keep = NULL;
	//LinkNode* sb = NULL;
	//if (head == NULL)
	//{
	//	// 非法输入。
	//	return;
	//}
	//if (*head == NULL)
	//{
	//	// 空链表。
	//	return;
	//}
	//temp = *head;
	//if ((*head)->data == value)
	//{
	//	*head = (*head)->next;
	//	free(temp);
	//}
	//keep = *head;
	//cur = (*head)->next;
	//while (cur->next != NULL)
	//{
	//	if (cur->data == value)
	//	{
	//		keep->next = cur->next;
	//		sb = cur;
	//	}
	//	else
	//	{
	//		keep = keep->next;
	//	}
	//	cur = cur->next;
	//	free(sb);
	//}
}

//判断链表是否为空
int EmotyLinkNode(LinkNode* head)
{
	if (head == NULL)
	{
		return 1;
	}
	return 0;
}

//求链表长度
size_t SizeLinkNode(LinkNode* head)
{
	size_t count = 0;
	LinkNode* cur = NULL;
	cur = head;
	while (cur != NULL)
	{
		++count;
		cur = cur->next;
	}
	return count;
}

//将链表逆序打印
void BackPrintLinkNode(LinkNode* head)
{
	if (head == NULL)
	{
		//为空链表。
		return;
	}
	BackPrintLinkNode(head->next);
	printf("[%c: %p]",head->data,head);
}
以下是代码的测试。。

#include"LinkNode.h"


void TestInit()
{
	LinkNode *head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
}

void TestPushBackLinkNode()
{
	LinkNode *head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	PushBackLinkNode(&head,'a');
	PushBackLinkNode(&head,'b');
	PushBackLinkNode(&head,'c');
	PushBackLinkNode(&head,'d');
	LinkNodePrint(head);
}

void TestPopBackLinkNode() 
{
	LinkNode *head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	PopBackLinkNode(&head);
	PushBackLinkNode(&head,'a');
	PushBackLinkNode(&head,'b');
	PushBackLinkNode(&head,'c');
	PushBackLinkNode(&head,'d');
	PopBackLinkNode(&head);
	PopBackLinkNode(&head);
	LinkNodePrint(head);
	PopBackLinkNode(&head);
	LinkNodePrint(head);
	PopBackLinkNode(&head);
	LinkNodePrint(head);
}

void TestPushFrontLinkNode() 
{
	LinkNode *head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	PushFrontLinkNode(&head, 'y');
	LinkNodePrint(head);
	PushBackLinkNode(&head, 'a');
	PushBackLinkNode(&head, 'b');
	PushBackLinkNode(&head, 'c');
	PushFrontLinkNode(&head, 'x');
	LinkNodePrint(head);
}

void TestPopFrontLinkNode() 
{
	LinkNode *head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	PopFrontLinkNode(&head);
	LinkNodePrint(head);
	PushBackLinkNode(&head, 'a');
	PushBackLinkNode(&head, 'b');
	PushBackLinkNode(&head, 'c');
	PopFrontLinkNode(&head);
	PopFrontLinkNode(&head);
	LinkNodePrint(head);
	PopFrontLinkNode(&head);
	LinkNodePrint(head);
}

void TestFindLinkNode()
{
	LinkNode* pos = NULL;
	LinkNode* temp = NULL;
	LinkNode* head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	PushBackLinkNode(&head,'a');
	pos = PushBackLinkNode(&head,'b');
	PushBackLinkNode(&head,'c');
	PushBackLinkNode(&head,'d');
	temp = FindLinkNode(head,'b');
	printf("expect %p,actual %p\n",pos,temp);
}

//o(n)
void TestInsertFrontLinkNode()
{
	LinkNode* pos = NULL;
	LinkNode* temp = NULL;
	LinkNode* head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	temp = PushBackLinkNode(&head,'a');
	pos = PushBackLinkNode(&head,'b');
	PushBackLinkNode(&head,'c');
	PushBackLinkNode(&head,'d');
	LinkNodePrint(head);
	InsertFrontLinkNode(&head,pos,'x');
	LinkNodePrint(head);
	InsertFrontLinkNode(&head,temp,'y');
	LinkNodePrint(head);
	InsertFrontLinkNode(&head,NULL,'8');
	LinkNodePrint(head);
}

void TestInsertFrontLinkNode1()
{
	LinkNode* pos = NULL;
	LinkNode* temp = NULL;
	LinkNode* head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	temp = PushBackLinkNode(&head,'a');
	pos = PushBackLinkNode(&head,'b');
	PushBackLinkNode(&head,'c');
	PushBackLinkNode(&head,'d');
	LinkNodePrint(head);
	InsertFrontLinkNode1(&head,pos,'x');
	LinkNodePrint(head);
	InsertFrontLinkNode1(&head,temp,'y');
	LinkNodePrint(head);
	InsertFrontLinkNode1(&head,NULL,'8');
	LinkNodePrint(head);
}

void TestInsertAfterLinkNode()
{
	LinkNode* pos = NULL;
	LinkNode* temp = NULL;
	LinkNode* head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	temp = PushBackLinkNode(&head,'a');
	pos = PushBackLinkNode(&head,'b');
	PushBackLinkNode(&head,'c');
	PushBackLinkNode(&head,'d');
	LinkNodePrint(head);
	InsertAfterLinkNode(head,pos,'x');
	LinkNodePrint(head);
	InsertAfterLinkNode(head,temp,'y');
	LinkNodePrint(head);
	InsertAfterLinkNode(head,NULL,'8');
	LinkNodePrint(head);
}

void TestEraseLinkNode()
{
	LinkNode* pos = NULL;
	LinkNode* temp = NULL;
	LinkNode* head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	temp = PushBackLinkNode(&head,'a');
	pos = PushBackLinkNode(&head,'b');
	PushBackLinkNode(&head,'c');
	PushBackLinkNode(&head,'d');
	LinkNodePrint(head);
	EraseLinkNode(&head,pos);
	LinkNodePrint(head);
	EraseLinkNode(&head,temp);
	LinkNodePrint(head);
}

void TestEraseLinkNode1()  //采用换值不换位置的方法,所以pos的地址如果不正确,程序奔溃。
{
	LinkNode* pos = NULL;
	LinkNode* temp = NULL;
	LinkNode* head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	temp = PushBackLinkNode(&head,'a');
	pos = PushBackLinkNode(&head,'b');//在删除temp时候,pos已经被删除。
	PushBackLinkNode(&head,'c');
	PushBackLinkNode(&head,'d');
	EraseLinkNode1(head,temp);
	LinkNodePrint(head);
	EraseLinkNode1(head,temp);
	LinkNodePrint(head);
}

void TestRemoveLinkNode()
{
	int ret = 0;
	LinkNode *head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	PushBackLinkNode(&head, 'a');
	PushBackLinkNode(&head, 'b');
	PushBackLinkNode(&head, 'c');
	PushBackLinkNode(&head, 'd');
	LinkNodePrint(head);
	RemoveLinkNode(&head,'b');
	RemoveLinkNode(&head,'d');
	LinkNodePrint(head);
	RemoveLinkNode(&head,'a');
	LinkNodePrint(head);
}

void TestRemoveLinkNodeAll()
{

	LinkNode *head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	PushBackLinkNode(&head, 'd');
	PushBackLinkNode(&head, 'a');
	PushBackLinkNode(&head, 'd');
	PushBackLinkNode(&head, 'c');
	PushBackLinkNode(&head, 'd');
	PushBackLinkNode(&head, 'c');
	PushBackLinkNode(&head, 'd');
	PushBackLinkNode(&head, 'd');
	LinkNodePrint(head);
	RemoveLinkNodeAll(&head, 'd');
	LinkNodePrint(head);
}

void TestEmotyAndSzie()
{
	int ret = 0;
	size_t temp = 0;
	LinkNode *head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	ret = EmotyLinkNode(head);
	printf("except 1 actual %d\n",ret); //是空返回1,不是空返回0.
	PushBackLinkNode(&head, 'd');
	PushBackLinkNode(&head, 'a');
	PushBackLinkNode(&head, 'd');
	PushBackLinkNode(&head, 'c');
	PushBackLinkNode(&head, 'd');
	PushBackLinkNode(&head, 'c');
	PushBackLinkNode(&head, 'd');
	PushBackLinkNode(&head, 'd');
	temp = SizeLinkNode(head);
	printf("except 8 actual %d\n",temp);
}
void TestBackPrintLinkNode()
{
	LinkNode *head = NULL;
	DIV_LINE;
	InitLinkNode(&head);
	PushBackLinkNode(&head, 'a');
	PushBackLinkNode(&head, 'b');
	PushBackLinkNode(&head, 'c');
	PushBackLinkNode(&head, 'd');
	BackPrintLinkNode(head);
}

int main()
{
	TestInit();
	TestPushBackLinkNode();
	TestPopBackLinkNode();
	TestPushFrontLinkNode();
	TestPopFrontLinkNode();
	TestFindLinkNode();
	TestInsertFrontLinkNode();
	TestInsertFrontLinkNode1();
	TestInsertAfterLinkNode();
	TestEraseLinkNode();
	TestEraseLinkNode1();
	TestRemoveLinkNode();
	TestRemoveLinkNodeAll();
	TestEmotyAndSzie();
	TestBackPrintLinkNode();
	return 0;
}


链表的增删查改。。如有不足,希望多多指导。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值