单链表的基本操作

前言

一、链表的含义

1.概念

单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素+指针,元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。

二、单链表的的存储结构及各种操作

1.单链表的存储结构

typedef int SLTDateType;//方便修改数据结构中元素的修改
typedef struct SListNode {
	SLTDateType data;//数据域
	struct  SListNode* next;//指针域
}SListNode;

2.单链表节点的创建

SListNode* BuySListNode(SLTDateType x) {
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));//向内存申请空间
	if (newnode == NULL) {//判断申请的空间是否成功
		perror("malloc fail");
		return;
	}
	newnode->data = x;//对数据域进行赋值
	newnode->next = NULL;
	return newnode;//返回这个节点
}

2.单链表大的尾部插入

void SListPushBack(SListNode** pplist, SLTDateType x) {

	SListNode * newnode = BuySListNode(x);//申请空间
	if (*pplist == NULL) {//如果链表为空直接将新的节点赋给头节点
		*pplist = newnode;
	}
	else {
		SListNode* cur = *pplist;//定义一个中间节点将头结点赋值给cur
		while (cur->next != NULL) {//利用while找到最后一个节点
			cur = cur->next;
		}
		cur->next = newnode; //将最后一个节点直接指向新的节点
	}
}

3.单链表的头部插入

void SListPushFront(SListNode** pplist, SLTDateType x) {
	SListNode* newnode = BuySListNode(x);//申请一新的节点
	SListNode* cur = *pplist;//定义新的节点将头结点赋值给它记录
	newnode->next = cur;//将新的节点的next指向cur
	*pplist = newnode;//然后将头结点更新为newnode
}

4.单链表的尾部删除

void SListPopBack(SListNode** pplist) {
	assert(*pplist!=NULL);//断言链表是否为空
	if ((*pplist)->next == NULL) {//只有一个节点,直接free,然后置为空
		free(*pplist);
		*pplist == NULL;
	}
	else {
		SListNode* tail = *pplist;//定义一个中间节点找到最后一个节点的前一个,将前一个free掉并置空
		while (tail->next->next != NULL)
		{
			tail = tail->next;
		}
		
		free(tail->next);
		tail->next = NULL;
	
	}
	

}

5.单链表的头部删除

void SListPopFront(SListNode** pplist) {
	assert(*pplist);//断言链表是否为空
	SListNode* cur = (*pplist)->next;//记录住头结点的下一个,防止找不到
	free(*pplist);//释放掉空间
	*pplist = cur;//将cur赋给头结点
}

6.单链表的查找

SListNode* SListFind(SListNode* plist, SLTDateType x) {
	assert(plist);//对链表断言
	SListNode* cur = plist;//定义中间节点cur,将头结点赋给cur
	while (cur != NULL) {//遍历查找
		if (cur->data == x) //找到返回这个节点
			return cur;
		cur = cur->next;
	}
		return NULL;//没找到返回NULL
}

7.单链表在任意位置的后面插入

void SListInsertAfter(SListNode* pos, SLTDateType x) {
	 assert(pos);
	 SListNode * newnode = BuySListNode(x);//申请节点
	 newnode->next=pos->next;//将新节点的next指向pos位置以前的节点
	 pos->next = newnode;//将pos节点的next指向新的节点
}

8.单链表在任意位置的后面删除

void SListEraseAfter(SListNode* pos) {
	assert(pos);
	SListNode* cur = pos->next->next;//记录住pos下一个的下一个的元素地址
	free(pos->next);//释放pos的next元素
	pos->next = cur;//将pos的next更新为cur
}

9.单链表在任意位置的前面插入

void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x) {
	assert(*pphead);
	assert(pos);
	SListNode* newnode = BuySListNode(x);
	if (*pphead == pos) {//pos是否是链表的头(*pphead==pos)。如果是,该函数只需调用SListPushFront(pphead,x),它会将值为x的新节点推送到链表的前面。
		SListPushFront(pphead, x);
	}
	else {
		
		SListNode* prev = NULL;
		SListNode* cur = *pphead;
		while (cur->next!= NULL) {//指定的位置不是链表的头,则代码将使用循环遍历链表,以查找指定位置之前的节点。它跟踪上一个节点(prev)和当前节点(cur)。一旦找到指定的位置pos,就会将新节点插入前一个节点和当前节点之间。prev->next被设置为指向新节点,newnode->next被设定为指向当前节点。


			if (cur == pos) {
				break;
			}
			prev = cur;
			cur = cur->next;
		}
		prev->next = newnode;
		newnode->next = cur;
	}
}

10.单链表在任意位置的前面删除

void SLTErase(SListNode** pphead, SListNode* pos) {
	assert(*pphead);
	assert(pos);
	if (pos == *pphead) {//是头结点直接调用头删函数
		SListPopFront(pphead);
	}
	else
	{
		SListNode* prev = NULL;//定义节点方便记录当前节点的上一个
		SListNode* cur = *pphead;//定义节点记录头结点
		while (cur->next!=NULL)//遍历查找节点
		{
			if (cur == pos) {//找到跳出循环
				break;
		}
			prev = cur; //记录上一节点
			cur = cur->next;
		}
		prev->next = cur->next;//指向下一节点的下一节点
		free(cur);//释放空间
	}
}

11.单链表的销毁

void SLTDestroy(SListNode** pphead) {
	assert(*pphead);
	SListNode* cur = *pphead;
	while (cur != NULL) {
		SListNode* node = cur->next;//创建一个临时指针节点,并为其分配cur->next的值,释放当前节点之前保留对下一个节点的引用。
		free(cur);//为当前节点(cur)分配的内存使用free函数释放。
		cur = node;
	}
	*pphead = NULL;//循环之后,头指针(*pphead)被设置为NULL,表示链表现在为空。

}

三、总结
       单链表单链表是一种动态数据结构,可以方便地进行插入和删除操作,而无需事先知道数据的数量或分配固定大小的内存。可以更灵活地利用内存,因为它可以动态分配内存空间,避免了数组需要预分配固定大小的内存的限制。在单链表中,插入和删除一个节点的操作效率很高,只需要修改相邻节点的指针即可,而不需要移动大量元素。单链表不需要在开始时知道存储元素的数量,可以根据需要动态增长。虽然有如此多的优点,但是也有许多缺点,如单链表不支持随机访问,只能通过从头节点开始逐个遍历来找到特定位置的节点。这导致了在访问第N个元素时需要O(N)的时间复杂度。单链表每个节点都需要额外的指针域来存储下一个节点的地址,这导致相比数组更多的存储空间开销。单链表在逆向遍历时效率较低,因为只有指向前一个节点的指针,需要从头开始遍历。由于节点在内存中可能不是顺序存储的,这可能导致缓存性能较差。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值