单向链表模板(C语言)

单向链表是一种常见的数据结构,它由一系列节点组成,每个节点包含两部分:存储数据的元素和指向下一个节点的指针。每个节点只有指向下一个节点的指针,没有指向前一个节点的指针,因此称为单向链表。

在单向链表中,第一个节点称为头节点,最后一个节点称为尾节点。头节点用来表示链表的起始位置,尾节点则指向一个特殊的空节点(NULL或None),表示链表的结束。

单向链表的优点是插入和删除操作的时间复杂度为O(1),只需修改相邻节点的指针即可完成。而查找操作的时间复杂度较高,为O(n),需要从头节点开始遍历链表直到找到目标节点。

在单向链表中,可以实现很多常见的操作,例如:插入节点、删除节点、查找节点、反转链表等。由于内存中的节点是非连续存储的,因此单向链表的长度理论上是没有限制的。

 如下所示是C语言版的单向链表模板

#include <stdio.h>
#include <stdlib.h>
#define eleType int
//链表那结点的结构体
typedef struct ListNode{
	//数据
	eleType data;
	//后继节点
	struct ListNode* next;
}ListNode;
//链表的结构体
typedef struct LinkedList{
	//链表的头节点
	struct ListNode* head;
	//链表的元素个数
	size_t size;
}LinkedList;
//链表的创建(初始化)
void LinkedListCreate(LinkedList *list){
	//头节点置为NULL
	list->head=NULL;
	//元素个数为0 --->空链表
	list->size=0;
}
//链表的销毁
void LinkedListDestroy(LinkedList *list){
	while(list->head)
	{
		//头节点依次用它的后继节点赋值再释放
		//最终头节点为NULL说明链表被销毁
		ListNode * temp=list->head;
		list->head=list->head->next;
		free(temp);
	}
	list->size=0;
}
//链表的增加
void LinkedListInsert(LinkedList *list,int i,eleType value){
	//判断插入位置是否合法
	//因为最后一个元素的后继节点为NULL
	//所以也可以取到,故if中不取等
	if(i<0||i>list->size)
	{
		printf("Invalid index\n");
		return;
	}
	//创建新节点
	ListNode *newNode =(ListNode*)malloc(sizeof(ListNode));
	//value的值赋值为新节点
	newNode->data=value;
	//判断插入位置(i)
	if(i==0){
		//插入头部
		newNode->next=list->head;
		list->head=newNode;
	}//如果不是插入头部
	else{
		//从头节点开始
		ListNode* current=list->head;
		for(int j=0;j<i-1;j++){
			//这个是链表,不是数组
			//所以如果想在第i个位置插入元素
			//应从头开始查找,一直到第i-1个位置
			//current一个一个往后推
			//推 i-1 次,此时current代表的便是第i-1个节点
			current=current->next;
		}
		//新节点的后继节点指向第i个节点(current是第i-1个,它的next是第i个)
		//那么后继节点便成为了第i个节点
		newNode->next=current->next;
		//current代表的仍然是第i-1个节点
		//让第i-1个节点指向newNode
		current->next=newNode;
	}
	//链表大小加1
	list->size++;
}

//链表节点的删除
void LinkedListRemove(LinkedList* list,int i){
	//判断删除位置是否合法
	if(i<0||i>=list->size){
		printf("Invalid index\n");
		return ;
	}
	//如果删除的是头节点
	if(i==0){
		//定义一个新的节点指向头节点的后继节点
		//存着后继节点的内容
		ListNode *next=list->head->next;
		//释放头节点
		free(list->head);
		//头节点指向原先头节点的后继节点
		//新的头节点成为了原来头节点的后继节点
		//原先的头节点已被释放
		list->head=next;
	}else{
		//把链表的头节点储存到current中
		ListNode* current=list->head;
		for(int j=0;j<i-1;j++)
		{
			//找到第i个节点的前驱节点
			//即第i-1个节点
			current=current->next;
		}
		//存放下需要删除节点的后续节点
		ListNode *next=current->next->next;
		//释放需要删除的节点
		free(current->next);
		//把需要删除的节点的后续节点补过来
		current->next=next;
	}
	list->size--;
}
//查找节点
ListNode* LinkedListFind(LinkedList *list,eleType value){
	ListNode *current=list->head;
	//用循环找所需查找节点
	while(current){
		//如果就是需要找的节点
		if(current->data==value){
			return current;
		}
		//current 往后递增
		current=current->next;
	}
	//没有的话
	return NULL;
}
//链表的索引
ListNode * LinkedListGet(LinkedList* list,int i){
	//判断位置是否合法
	if(i<0||i>=list->size){
		printf("Invalid index\n");
		return NULL;
	}
	ListNode* current=list->head;
	for(int j=0;j<i;j++)
	{
		current=current->next;
	}
	return current;
}
//链表元素的修改
void LinkedListUpdate(LinkedList *list,int i,eleType value){
	//利用链表元素的索引找到目标节点
	ListNode* node=LinkedListGet(list,i);
	if(node){
		//修改链表元素
		node->data=value;
	}
}
//链表元素的打印
void LinkedListPrint(LinkedList* list){
	//从链表头开始
	//每次遍历一个节点
	ListNode *current=list->head;
	while(current){
		//遍历到就打印出来
		printf("%d->",current->data);
		//下一个节点
		current=current->next;
	}
	//链表的最后 打印NULL 代表最终结果
	printf("NULL\n");
}
int main()
{
	LinkedList list;
	//初始化
	LinkedListCreate(&list);
	//插入数据
	LinkedListInsert(&list,0,10);
	LinkedListInsert(&list,1,20);
	LinkedListInsert(&list,2,30);
	LinkedListInsert(&list,3,40);
	printf("Original List:\n");
	//打印链表
	LinkedListPrint(&list);
	//移除元素
	LinkedListRemove(&list,2);
	LinkedListPrint(&list);
	//修改元素
	LinkedListUpdate(&list,2,300);
	LinkedListPrint(&list);
	//查找元素
	ListNode * found=LinkedListFind(&list,40);
	if(!found){
		printf("Element not found!\n");
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值