一文教会你单向链表

news2024/9/23 9:34:13

目录

一、什么是链表?

1.链表的定义

2.链表的实现

2.1链表的定义

2.2创建一个链表

 二、链表的各个接口

1.创建节点

2.头插(将新创建的节点作为头插入到链表中)

3.打印链表

 4.尾插(将新创建的节点插入到链表的末端)

5.头删

 6.尾删

7.查找

8.删除指定节点位置之后

 9.删除指定位置节点

 10.在指定位置节点之后插入

 11.在指定位置节点之前插入

三、全部代码

1.接口头文件

2.接口实现

3.测试


一、什么是链表?

1.链表的定义

链表是是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。比较通俗易懂的说法就是,在计算机内存中开辟了一个个空间,然后通过地址的方式将它们链接在一起,并通过地址的方式进行访问。

2.链表的实现

只知道了链表的定义,估计大家还是云里雾里的,不知道什么才算是链表,接下来笔者就手动创建一个很挫的链表给大家,不通过函数的形式实现,主要是让大家先感受一下。

2.1链表的定义

在手动创建链表之前,我们要先对链表进行定义,对链表的定义,接口函数的引用和头文件的引用最好放在一个头文件中   这样在要使用创建的接口时便只需要引用一个头文件即可,而接口函数的实现你也可以放在一个.c文件中,最后在另一个.c文件中引用函数测试即可,如图: 

//链表博客版.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDateType;
//链表成员我们先用int,int简单好懂
//而之所以要给它取个SLDateType的别名
//不仅仅是因为方便和int进行区分
//更主要的是以后链表的成员不想用int类型的话
//直接在这里进行修改即可
typedef struct SlistNode
{
	SLDateType data;//成员
	struct SlistNode* next;
	//这里给它取名叫next其实是为了方便到时使用,其实你叫它abc也是可以的
	// 在链表中,一个节点通过地址链接到下一个节点,就像串串一样把它们穿起来,而这个地址则是它们唯一的联系,
	//我们这讲述的是单向链表,所以只能够是前面的找到后面的,从后面找到前面是不可能实现的。
}SlistNode;

2.2创建一个链表

链表,其实也没什么高大上的,就是通过地址找到下一个节点然后进行对应的访问,核心在于地址上   只要我们能够将首节点的地址链接到下一个节点,将下一个节点的地址链接到下下个节点的地址.....直到链接完成就停止即可,这里我们就先不链接那么多个节点,我们就简单的链接个节点数为3的链表

#include"链表博客版.h"
int main()
{
	SlistNode a, b, c;//创建三个节点
	a.next=&b;//a节点的链接部分存储b节点的地址
	b.next = &c;//b节点的链接部分存储c节点的地址
	c.next = NULL;//最后一个链接到空指针上,代表着链接结束
	a.data = 1;
	b.data = 2;
	c.data = 3;
	SlistNode* plist = &a;//将首节点保存
	while (plist)
	{
		printf("%d ", plist->data);//打印节点内的内容
		plist = plist->next;//不断地指向下一个节点,直到为空
	}
}

 二、链表的各个接口

1.创建节点

创建节点是一个很重要的函数,在插入函数中需要使用。在函数中创建节点,我们就不能够像之前一样直接创建了,众所周知,在函数上创建节点出了函数就会自动销毁,为了避免节点被自动销毁,这里采用malloc的方式创建节点,别忘了在头文件中引用函数

#include"链表博客版.h"
SlistNode* buy_slistnode(SLDateType x)
//使用节点指针作为返回类型,来拿到创建好的新节点
{
	SlistNode* newnode = (SlistNode*)malloc(sizeof(SlistNode));
	//使用malloc创建一个新节点
	if (newnode == NULL)
	{
		perror("buy_slistnode");
		exit(-1);//创建失败直接中止程序
	}
	newnode->data = x;//将节点内容修改成需要的值
	newnode->next = NULL;//将链接对象置为空,因为不知道要链接谁
	return newnode;
}

2.头插(将新创建的节点作为头插入到链表中)

为什么先将头插节点呢?无他,相比尾插它简单很多

void slist_pushfront(SlistNode** phead, SLDateType x)
//采用二级指针的原因是,当没有节点的时候,我们要对首节点的地址进行修改
{
	//先创建一个新的节点
	SlistNode* newnode = buy_slistnode(x);
	//我们要头插是吧,也就是说新创建的节点是新的头
	//那么我们是不是应该把我们自己原来的头更新一下
	//然后再将之前的节点,也就是之前的头链接到新的头后面

/*	*phead = newnode;
	newnode->next = *phead;*/

	//但这是错误的,原因很简单,你的头更新了,那么你就找不到之前的节点了
    //换一下顺序即可
	newnode->next = *phead;
	*phead = newnode;
}

3.打印链表

插入完节点之后,也不知道自己到底有没有插入,因此我们来设计一个打印链表的函数

void print_slist(SlistNode* phead)
{
	while (phead)//phead不为空意味着还有节点没被访问完
	{
		printf("%d->", phead->data);
		phead=phead->next;//指向下一个节点
	}
	printf("NULL\n");//访问完了打印空,提示已经访问完了
}

测试效果:

#include"链表博客版.h"
void test1()
{
	SlistNode* plist = NULL;//创建一个链表头
	slist_pushfront(&plist, 1);//依次将1,2,3头插进链表中
	slist_pushfront(&plist, 2);//那么链表最后应该是3为头,1为尾
	slist_pushfront(&plist, 3);
	print_slist(plist);
}
int main()
{
	test1();
}

 4.尾插(将新创建的节点插入到链表的末端)

尾插要在链表的末端进行插入,那么找到链表的末端是一件必须要做的事

void slist_pushback(SlistNode** phead, SLDateType x)
{
	SlistNode* tmp = *phead;
	//创建一个首节点的拷贝,避免影响到首节点的指向
	SlistNode* newnode = buy_slistnode(x);//创建一个新节点
	while(tmp->next)
	//当成员的next为空的时候意味着已经找到目标了
	// 跳出循环
	//接下来就是把这个成员的指向改变
	{
		tmp = tmp->next;
	}
	tmp->next = newnode;
}

很多小伙伴,写到这里的时候就以为已经完成了,但你想一想,如果此时链表中没有节点呢,也就是*phead此时为NULL的时候,你还能够指向next吗,你能对空指针进行解引用吗?显然不能,因此我们把这种情况单独处理。

void slist_pushback(SlistNode** phead, SLDateType x)
{
	SlistNode* tmp = *phead;
	//创建一个首节点的拷贝,避免影响到首节点的指向
	SlistNode* newnode = buy_slistnode(x);//创建一个新节点
	if (*phead==NULL)//当*phead==NULL时,意味着链表为空
	{
		*phead = newnode;//直接链接
		return;
	}
	while(tmp->next)
	//当成员的next为空的时候意味着已经找到目标了
	// 跳出循环
	//接下来就是把这个成员的指向改变
	{
		tmp = tmp->next;
	}
	tmp->next = newnode;
}

测试代码:

void test2()
{
	SlistNode* plist = NULL;
	slist_pushback(&plist, 10086);//依次尾插10086,666,555,111
	slist_pushback(&plist, 666);
	slist_pushback(&plist, 555);
	slist_pushback(&plist, 111);
	print_slist(plist);
}
int main()
{
  test2();
}

错误情况

程序直接就崩溃了,连print_slist即使是空也应该打印出来的NULL都没打印出来

正确情况

5.头删

void slist_popfront(SlistNode** phead)
{
	if (*phead==NULL)//空了就别删了
	{
		printf("链表为空,操作失败\n");
		return;
	}
	SlistNode* tmp = (*phead)->next;
	//储存头的下一个节点,避免找不到
	free(*phead);//直接释放头节点
	*phead =tmp;//头节点重新指向下一个节点
}

 效果测试:

void test3()
{
	SlistNode* plist = NULL;
	slist_popfront(&plist);//直接删除,测试报错
	slist_pushback(&plist, 10086);//依次尾插10086,666,555,111
	slist_pushback(&plist, 666);
	slist_pushback(&plist, 555);
	slist_pushback(&plist, 111);
	print_slist(plist);
	slist_popfront(&plist);//删除10086
	print_slist(plist);
	slist_popfront(&plist);//删除666
	print_slist(plist);
	slist_popfront(&plist);//删除555
	print_slist(plist);
	slist_popfront(&plist);//删除111
	print_slist(plist);
}

int main()
{
	test3();
}

 6.尾删

void slist_popback(SlistNode** phead)
{
	if (*phead == NULL)
	{
		printf("链表为空,操作失败\n");
		return;
	}
	if ((*phead)->next == NULL)
		//如果只有一个节点,我们就不可能找到上一个节点,因此单独处理
	{
		free(*phead);//直接释放
		*phead = NULL;
		return;
	}
	SlistNode* tmp = *phead;
	SlistNode* prev = NULL;//用来存储目标的上一个节点
	while (tmp->next)
	{
		prev = tmp;
		tmp=tmp->next;
	}
	prev->next = NULL;//改变上一个节点的指向
	free(tmp);
}

测试代码:

void test4()
{
	SlistNode* plist = NULL;
	slist_popback(&plist);//直接删除,测试报错
	slist_pushback(&plist, 10086);//依次尾插10086,666,555,111
	slist_pushback(&plist, 666);
	slist_pushback(&plist, 555);
	slist_pushback(&plist, 111);
	print_slist(plist);
	slist_popback(&plist);//删除111
	print_slist(plist);
	slist_popback(&plist);//删除555
	print_slist(plist);
	slist_popback(&plist);//删除666
	print_slist(plist);
	slist_popback(&plist);//删除10086
	print_slist(plist);
	slist_popback(&plist);//删除空链表
	print_slist(plist);
}

int main()
{
	test4();
}

7.查找

在对指定位置操作之前,我们得先找到目标位置才行,找到目标位置是比较简单的,简单地遍历一遍链表,找的到就返回对应的地址,找不到就返回空指针

SlistNode* slist_find(SlistNode* phead,SLDateType x)
{
	while (phead)
	{
		if (phead->data == x)
		{
			return phead;
		}
		phead=phead->next;
	}
	return NULL;
}

8.删除指定节点位置之后

之所以先讲指定位置之后删除,是因为这个相比指定位置删除简单很多

void slist_erase_after(SlistNode* pos)
{
	if (pos == NULL ||pos->next==NULL )
		//如果为空则删除失败,如果下一个节点为空也不能删除
	{
		printf("该位置无效,操作失败\n");
		return;
	}
	SlistNode* tmp = pos->next;
	pos->next = pos->next->next;
	free(tmp);
}

测试代码

void test5()
{
	SlistNode* plist = NULL;//创建一个链表头
	slist_pushback(&plist, 1);//通过尾插依次将1,2,3头插进链表中
	slist_pushback(&plist, 2);
	slist_pushback(&plist, 3);
	print_slist(plist); 
	SlistNode* pos=slist_find(plist,1);//查找1所在的位置
	slist_erase_after(pos);//将1之后删除
	print_slist(plist);
	pos = slist_find(plist, 3);//查找3所在的位置
	slist_erase_after(pos);//将3之后删除,但是3之后没有节点,删除必定失败
	print_slist(plist);
}
int main()
{
	test5();
}

 9.删除指定位置节点

void slist_erase(SlistNode* pos,SlistNode**phead)
{
	if (pos == NULL)//为空就别删了
	{
		printf("该位置无效,操作失败\n");
		return;
	}
	if(*phead==pos)//当只有一个节点时,操作不到两个节点,单独处理
	{
		SlistNode*tmp=(*phead)->next;
		free(*phead);
		*phead = tmp;
		return;
	}
	SlistNode* cur = *phead;
	while (cur->next)
	{
		if (cur->next == pos)
		{
			break;
		}
		cur=cur->next;
	}
	//此时phead的next就是目标节点
	SlistNode* tmp = cur->next;
	cur->next = cur->next->next;//将目标节点的上一个节点链接到目标节点的下一个地址
	free(tmp);
}

测试代码:

void test6()
{
	SlistNode* plist = NULL;//创建一个链表头
	slist_pushback(&plist, 1);//通过尾插依次将1,2,3头插进链表中
	slist_pushback(&plist, 2);
	slist_pushback(&plist, 3);
	print_slist(plist);
	SlistNode* pos = slist_find(plist, 1);//查找1所在的位置
	slist_erase(pos, &plist);//将1删除
	print_slist(plist);	
	 pos = slist_find(plist, 2);//查找2所在的位置
	slist_erase(pos, &plist);//将2删除
	print_slist(plist);
	 pos = slist_find(plist, 3);//查找3所在的位置
	slist_erase(pos, &plist);//将3删除
	print_slist(plist);
}
int main()
{
	test6();
}

 10.在指定位置节点之后插入

void slist_insert_after(SlistNode* pos, SLDateType x)
{
	if (pos == NULL)
	{
		printf("目标不存在,操作失败\n");
		return;
	}
	SlistNode* newnode = buy_slistnode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

测试代码:

void test7()
{
	SlistNode* plist = NULL;//创建一个链表头
	slist_pushback(&plist, 1);//通过尾插依次将1,2,3头插进链表中
	slist_pushback(&plist, 2);
	slist_pushback(&plist, 3);
	SlistNode* pos = slist_find(plist, 1);//查找1所在的位置
	slist_insert_after(pos, 10086);//在1之后进行插入
	print_slist(plist);
	pos = slist_find(plist, 3);//查找3所在的位置
	slist_insert_after(pos, 520);//在3之后进行插入
	print_slist(plist);
	pos = slist_find(plist, 10086);//查找10086所在的位置
	slist_insert_after(pos,9 );//在10086之后进行插入
	print_slist(plist);
}
int main()
{
	test7();
}

 11.在指定位置节点之前插入

void slist_insert_before(SlistNode* pos, SLDateType x,SlistNode**phead)
{
	if (pos == NULL)
	{
		printf("目标不存在,操作失败\n");
		return;
	}	
	SlistNode* newnode = buy_slistnode(x);
	if (*phead==pos)//在第一个节点前插入,没有上一个节点,单独处理
	{
		newnode->next = pos;
		*phead = newnode;
		return;
	}
	SlistNode* cur = *phead;
	while (cur)//为空意味着找不到
	{
		if (cur->next == pos)//找到上一个节点了
		{
			break;
		}
		cur = cur->next;
	}
	if (cur == NULL)
	{
		printf("目标不存在,操作失败\n");
		return;
	}
	cur->next = newnode;
	newnode->next = pos;
}

测试代码

void test8()
{
	SlistNode* plist = NULL;//创建一个链表头
	slist_pushback(&plist, 1);//通过尾插依次将1,2,3头插进链表中
	print_slist(plist);
	SlistNode* pos = slist_find(plist, 1);//查找1所在的位置
	slist_insert_before(pos, 10086,&plist);//在1之前插入666
	print_slist(plist);
	slist_pushback(&plist, 2);
	slist_pushback(&plist, 3);
	pos = slist_find(plist, 10086);//查找10086所在的位置
	slist_insert_before(pos, 666, &plist);//在10086之前插入666
	print_slist(plist);
	pos = slist_find(plist, 3);//查找3所在的位置
	slist_insert_before(pos, 999, &plist);//在3之前插入999
	print_slist(plist);

}
int main()
{
	test8();
}

三、全部代码

1.接口头文件

//链表博客版.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDateType;
//链表成员我们先用int,int简单好懂
//而之所以要给它取个SLDateType的别名
//不仅仅是因为方便和int进行区分
//更主要的是以后链表的成员不想用int类型的话
//直接在这里进行修改即可
typedef struct SlistNode
{
	SLDateType data;//成员
	struct SlistNode* next;
	//这里给它取名叫next其实是为了方便到时使用,其实你叫它abc也是可以的
	// 在链表中,一个节点通过地址链接到下一个节点,就像串串一样把它们穿起来,而这个地址则是它们唯一的联系,
	//我们这讲述的是单向链表,所以只能够是前面的找到后面的,从后面找到前面是不可能实现的。
}SlistNode;
SlistNode* buy_slistnode(SLDateType x);
//头插
void slist_pushfront(SlistNode**phead,SLDateType x);
//打印链表
void print_slist(SlistNode* phead);
//尾插
void slist_pushback(SlistNode** phead, SLDateType x);
//头删
void slist_popfront(SlistNode** phead);
//尾删
void slist_popback(SlistNode**phead);
//查找
SlistNode* slist_find(SlistNode*phead,SLDateType x);
//删除指定位置之后
void slist_erase_after(SlistNode*pos);
//删除指定位置
void slist_erase(SlistNode* pos,SlistNode**phead);
//在指定位置之后插入
void slist_insert_after(SlistNode* pos, SLDateType x);
//在指定位置之前插入
void slist_insert_before(SlistNode* pos, SLDateType x, SlistNode** phead);

2.接口实现

#include"链表博客版.h"
SlistNode* buy_slistnode(SLDateType x)
//使用节点指针作为返回类型,来拿到创建好的新节点
{
	SlistNode* newnode = (SlistNode*)malloc(sizeof(SlistNode));
	//使用malloc创建一个新节点
	if (newnode == NULL)
	{
		perror("buy_slistnode");
		exit(-1);//创建失败直接中止程序
	}
	newnode->data = x;//将节点内容修改成需要的值
	newnode->next = NULL;//将链接对象置为空,因为不知道要链接谁
	return newnode;
}
void slist_pushfront(SlistNode** phead, SLDateType x)
//采用二级指针的原因是,当没有节点的时候,我们要对首节点的地址进行修改
{
	//先创建一个新的节点
	SlistNode* newnode = buy_slistnode(x);
	//我们要头插是吧,也就是说新创建的节点是新的头
	//那么我们是不是应该把我们自己原来的头更新一下
	//然后再将之前的节点,也就是之前的头链接到新的头后面

/*	*phead = newnode;
	newnode->next = *phead;*/

	//但这是错误的,原因很简单,你的头更新了,那么你就找不到之前的节点了
    //换一下顺序即可
	newnode->next = *phead;
	*phead = newnode;
}
void print_slist(SlistNode* phead)
{
	while (phead)//phead不为空意味着还有节点没被访问完
	{
		printf("%d->", phead->data);
		phead=phead->next;//指向下一个节点
	}
	printf("NULL\n");//访问完了打印空,提示已经访问完了
}
void slist_pushback(SlistNode** phead, SLDateType x)
{
	SlistNode* tmp = *phead;
	//创建一个首节点的拷贝,避免影响到首节点的指向
	SlistNode* newnode = buy_slistnode(x);//创建一个新节点
	if (*phead==NULL)//当*phead==NULL时,意味着链表为空
	{
		*phead = newnode;//直接链接
		return;
	}
	while(tmp->next)
	//当成员的next为空的时候意味着已经找到目标了
	// 跳出循环
	//接下来就是把这个成员的指向改变
	{
		tmp = tmp->next;
	}
	tmp->next = newnode;
}
void slist_popfront(SlistNode** phead)
{
	if (*phead==NULL)//空了就别删了
	{
		printf("链表为空,操作失败\n");
		return;
	}
	SlistNode* tmp = (*phead)->next;
	//储存头的下一个节点,避免找不到
	free(*phead);//直接释放头节点
	*phead =tmp;//头节点重新指向下一个节点
}
void slist_popback(SlistNode** phead)
{
	if (*phead == NULL)
	{
		printf("链表为空,操作失败\n");
		return;
	}
	if ((*phead)->next == NULL)
		//如果只有一个节点,我们就不可能找到上一个节点,因此单独处理
	{
		free(*phead);//直接释放
		*phead = NULL;
		return;
	}
	SlistNode* tmp = *phead;
	SlistNode* prev = NULL;//用来存储目标的上一个节点
	while (tmp->next)
	{
		prev = tmp;
		tmp=tmp->next;
	}
	prev->next = NULL;//改变上一个节点的指向
	free(tmp);
}
SlistNode* slist_find(SlistNode* phead,SLDateType x)
{
	while (phead)
	{
		if (phead->data == x)
		{
			return phead;
		}
		phead=phead->next;
	}
	return NULL;
}
void slist_erase_after(SlistNode* pos)
{
	if (pos == NULL ||pos->next==NULL )
		//如果为空则删除失败,如果下一个节点为空也不能删除
	{
		printf("该位置无效,操作失败\n");
		return;
	}
	SlistNode* tmp = pos->next;
	pos->next = pos->next->next;
	free(tmp);
}
void slist_erase(SlistNode* pos,SlistNode**phead)
{
	if (pos == NULL)//为空就别删了
	{
		printf("该位置无效,操作失败\n");
		return;
	}
	if(*phead==pos)//当只有一个节点时,操作不到两个节点,单独处理
	{
		SlistNode*tmp=(*phead)->next;
		free(*phead);
		*phead = tmp;
		return;
	}
	SlistNode* cur = *phead;
	while (cur->next)
	{
		if (cur->next == pos)
		{
			break;
		}
		cur=cur->next;
	}
	//此时phead的next就是目标节点
	SlistNode* tmp = cur->next;
	cur->next = cur->next->next;//将目标节点的上一个节点链接到目标节点的下一个地址
	free(tmp);
}
void slist_insert_after(SlistNode* pos, SLDateType x)
{
	if (pos == NULL)
	{
		printf("目标不存在,操作失败\n");
		return;
	}
	SlistNode* newnode = buy_slistnode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}
void slist_insert_before(SlistNode* pos, SLDateType x,SlistNode**phead)
{
	if (pos == NULL)
	{
		printf("目标不存在,操作失败\n");
		return;
	}	
	SlistNode* newnode = buy_slistnode(x);
	if (*phead==pos)//在第一个节点前插入,没有上一个节点,单独处理
	{
		newnode->next = pos;
		*phead = newnode;
		return;
	}
	SlistNode* cur = *phead;
	while (cur)//为空意味着找不到
	{
		if (cur->next == pos)//找到上一个节点了
		{
			break;
		}
		cur = cur->next;
	}
	if (cur == NULL)
	{
		printf("目标不存在,操作失败\n");
		return;
	}
	cur->next = newnode;
	newnode->next = pos;
}

3.测试

#include"链表博客版.h"
void test1()
{
	SlistNode* plist = NULL;//创建一个链表头
	slist_pushfront(&plist, 1);//依次将1,2,3头插进链表中
	slist_pushfront(&plist, 2);//那么链表最后应该是3为头,1为尾
	slist_pushfront(&plist, 3);
	print_slist(plist);
}
void test2()
{
	SlistNode* plist = NULL;
	slist_pushback(&plist, 10086);//依次尾插10086,666,555,111
	slist_pushback(&plist, 666);
	slist_pushback(&plist, 555);
	slist_pushback(&plist, 111);
	print_slist(plist);
}
void test3()
{
	SlistNode* plist = NULL;
	slist_popfront(&plist);//直接删除,测试报错
	slist_pushback(&plist, 10086);//依次尾插10086,666,555,111
	slist_pushback(&plist, 666);
	slist_pushback(&plist, 555);
	slist_pushback(&plist, 111);
	print_slist(plist);
	slist_popfront(&plist);//删除10086
	print_slist(plist);
	slist_popfront(&plist);//删除666
	print_slist(plist);
	slist_popfront(&plist);//删除555
	print_slist(plist);
	slist_popfront(&plist);//删除111
	print_slist(plist);
}
void test4()
{
	SlistNode* plist = NULL;
	slist_popback(&plist);//直接删除,测试报错
	slist_pushback(&plist, 10086);//依次尾插10086,666,555,111
	slist_pushback(&plist, 666);
	slist_pushback(&plist, 555);
	slist_pushback(&plist, 111);
	print_slist(plist);
	slist_popback(&plist);//删除111
	print_slist(plist);
	slist_popback(&plist);//删除555
	print_slist(plist);
	slist_popback(&plist);//删除666
	print_slist(plist);
	slist_popback(&plist);//删除10086
	print_slist(plist);
	slist_popback(&plist);//删除空链表
	print_slist(plist);
}
void test5()
{
	SlistNode* plist = NULL;//创建一个链表头
	slist_pushback(&plist, 1);//通过尾插依次将1,2,3头插进链表中
	slist_pushback(&plist, 2);
	slist_pushback(&plist, 3);
	print_slist(plist); 
	SlistNode* pos=slist_find(plist,1);//查找1所在的位置
	slist_erase_after(pos);//将1之后删除
	print_slist(plist);
	pos = slist_find(plist, 3);//查找3所在的位置
	slist_erase_after(pos);//将3之后删除,但是3之后没有节点,删除必定失败
	print_slist(plist);
}
void test6()
{
	SlistNode* plist = NULL;//创建一个链表头
	slist_pushback(&plist, 1);//通过尾插依次将1,2,3头插进链表中
	slist_pushback(&plist, 2);
	slist_pushback(&plist, 3);
	print_slist(plist);
	SlistNode* pos = slist_find(plist, 1);//查找1所在的位置
	slist_erase(pos, &plist);//将1删除
	print_slist(plist);	
	 pos = slist_find(plist, 2);//查找2所在的位置
	slist_erase(pos, &plist);//将2删除
	print_slist(plist);
	 pos = slist_find(plist, 3);//查找3所在的位置
	slist_erase(pos, &plist);//将3删除
	print_slist(plist);
}
void test7()
{
	SlistNode* plist = NULL;//创建一个链表头
	slist_pushback(&plist, 1);//通过尾插依次将1,2,3头插进链表中
	slist_pushback(&plist, 2);
	slist_pushback(&plist, 3);
	SlistNode* pos = slist_find(plist, 1);//查找1所在的位置
	slist_insert_after(pos, 10086);//在1之后进行插入
	print_slist(plist);
	pos = slist_find(plist, 3);//查找3所在的位置
	slist_insert_after(pos, 520);//在3之后进行插入
	print_slist(plist);
	pos = slist_find(plist, 10086);//查找10086所在的位置
	slist_insert_after(pos,9 );//在10086之后进行插入
	print_slist(plist);
}
void test8()
{
	SlistNode* plist = NULL;//创建一个链表头
	slist_pushback(&plist, 1);//通过尾插依次将1,2,3头插进链表中
	print_slist(plist);
	SlistNode* pos = slist_find(plist, 1);//查找1所在的位置
	slist_insert_before(pos, 10086,&plist);//在1之前插入666
	print_slist(plist);
	slist_pushback(&plist, 2);
	slist_pushback(&plist, 3);
	pos = slist_find(plist, 10086);//查找10086所在的位置
	slist_insert_before(pos, 666, &plist);//在10086之前插入666
	print_slist(plist);
	pos = slist_find(plist, 3);//查找3所在的位置
	slist_insert_before(pos, 999, &plist);//在3之前插入999
	print_slist(plist);

}
int main()
{
	test8();
}

 今天的分享到这里就结束了,更新各位友友的来访,祝各位友友前程似锦O(∩_∩)O

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/811209.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言基础入门详解三

前些天发现了一个蛮有意思的人工智能学习网站,8个字形容一下"通俗易懂&#xff0c;风趣幽默"&#xff0c;感觉非常有意思,忍不住分享一下给大家。 &#x1f449;点击跳转到教程 一、C语言之函数指针 #include<stdio.h> #include<stdlib.h> /**函数指针 …

基于BIM+AI的建筑能源优化模型【神经网络】

推荐&#xff1a;用 NSDT设计器 快速搭建可编程3D场景。 AEC&#xff08;建筑、工程、施工&#xff09;行业的BIM 技术&#xff0c;允许在实际施工开始之前虚拟地建造建筑物&#xff1b; 这带来了许多有形和无形的好处&#xff1a;减少成本超支、更有效的协调、增强决策权等等。…

实例026 随机更换主界面背景

实例说明 如果开发的软件用户使用频率非常高&#xff0c;可以为程序设计随机更换背景的程序。这样不但可以使用户心情愉快&#xff0c;也增加了软件的人性化设计。下面的界面就是一个随机更换主界面的例子&#xff0c;效果如图1.26所示。 技术要点 随机更换主界面背景使用了…

MySql002——关系型数据库基础知识

前言&#xff1a;因为本专栏学习的是MySQL&#xff0c;而MySQL是关系型数据库&#xff0c;所以这篇文章就来介绍一些关系型数据库基础知识&#xff0c;至于其他知识小伙伴们可以自行学习&#xff0c;同时不足之处也欢迎批评指正&#xff0c;谢谢~ 一、MySQL关系型数据库(RDBMS)…

Flowable-服务-Http任务

目录 定义图形标记XML内容界面操作 定义 Http 任务不是 BPMN 2.0 规范定义的官方任务&#xff0c;在 Flowable 中&#xff0c;Http 任务是作为一种特殊的服务 任务来实现的&#xff0c;主要调用Http服务使用。 图形标记 由于 Http 任务不是 BPMN 2.0 规范的“官方”任务&…

05-向量的意义_n维欧式空间

线性代数 向量与其运算 向量是线性代数里面最基本的概念&#xff0c;它其实就是一维数组&#xff0c;由 N 个数构成的&#xff0c; X(X1, X2…Xn) 向量的维度可以是任意正整数&#xff0c;可以表示在 n 维空间中的位置或方向。向量本身是一维的&#xff0c; 但向量所处的空间…

JavaWeb+jsp+Tomcat的网上订餐项目

点击以下链接获取源码&#xff1a; https://download.csdn.net/download/qq_64505944/88130029?spm1001.2014.3001.5503 技术&#xff1a;ssm jsp JDK1.8 MySQL5.7 Tomcat7.0.5 功能&#xff1a;普通用户与管理员两个登录&#xff0c;管理员可以进行商品的增删改&#xff0c;…

JAVA SE -- 第十二天

&#xff08;全部来自“韩顺平教育”&#xff09; 常用类 一、包装类 1、包装类的分类 ①针对八种基本数据类型相应的引用类型--包装类 ②有了类的特点&#xff0c;就可以调用类中的方法 ③ 基本数据类型包装类booleanBooleancharCharacterbyteByteshortShortintInteger…

基于STM32设计的人体健康检测仪

一、项目介绍 当前文章介绍基于STM32设计的人体健康检测仪。设备采用STM32系列MCU作为主控芯片&#xff0c;配备血氧浓度传感器&#xff08;使用MAX30102血氧浓度检测传感器&#xff09;、OLED屏幕和电池供电等外设模块。设备可以广泛应用于医疗、健康等领域。可以帮助医生和病…

Spring源码(三)Spring Bean生命周期

Bean的生命周期就是指&#xff1a;在Spring中&#xff0c;一个Bean是如何生成的&#xff0c;如何销毁的 Bean生命周期流程图 1、生成BeanDefinition Spring启动的时候会进行扫描&#xff0c;会先调用org.springframework.context.annotation.ClassPathScanningCandidateCompo…

【C++入门到精通】C++入门 —— 类和对象(了解类和对象)

目录 一、类和对象的历史由来 二、面向过程和面向对象的初步认识 三、类 1.引子 2.类的定义 3.类的访问限定符及封装 ⭕访问限定符 &#x1f6a9;访问限定符解释说明 &#x1f6a9;struct 与 class 的区别 1. 默认访问级别&#xff1a; 2. 继承权限&#xff08;默认的…

安全基础 --- html标签 + 编码

html标签 &#xff08;1&#xff09;detail标签 <details>标签用来折叠内容&#xff0c;浏览器会折叠显示该标签的内容。 <1> 含义&#xff1a; <details> 这是一段解释文本。 </details> 用户点击这段文本&#xff0c;折叠的文本就会展开&#x…

山西电力市场日前价格预测【2023-07-31】

日前价格预测 预测明日&#xff08;2023-07-31&#xff09;山西电力市场全天平均日前电价为294.49元/MWh。其中&#xff0c;最高日前电价为318.11元/MWh&#xff0c;预计出现在19: 30。最低日前电价为278.89元/MWh&#xff0c;预计出现在00: 15。 价差方向预测 1&#xff1a;实…

Git远程仓库的创建、克隆、推送和拉取

文章目录 1.前言2.远程仓库的创建3.远程仓库的克隆3.1 使用HTTPS进行克隆3.2 使用SSH进行克隆 4.远程仓库的推送5. 远程仓库的拉取 1.前言 在之前的文章中,讲解了Git的一些基本概念和常用的命令. 是时候干一件大事了-实现多人协助开发! 环境:Centos7云服务器 代码托管平台: G…

基于LSTM神经网络的BIM对象识别【BIM+AI】

BIM 模型中的一个基本数据是对象的名称&#xff0c;尤其是房间。 没有专有名称&#xff0c;人们就不可能理解模型/设计的内容。 在本文中&#xff0c;我们尝试使用 Tensorflow 构建一个基于该数据识别房间的LSTM神经网络模型。 推荐&#xff1a;用 NSDT设计器 快速搭建可编程3D…

第一章HelloWorld

确认环境 java -version javac编写代码 public class HelloWorld{public static void main(String[] args){System.out.println("HelloWorld");} }编译运行 javac HelloWord.java编译java文件成class字节码文件 java HelloWorld运行.class字节码文件 备注 容易…

手把手教你使用stable diffusion生成自己的艺术二维码

艺术二维码制作指南 导读midjourneystable diffusion 环境准备安装stable diffusion webuisd-webui-qrcode-toolkit安装 草料二维码模型准备QR PatternQR Code MonsterIoC Lab Control Net 艺术二维码制作1. 二维码信息提取2. 使用QR Tookit生成二维码3. 下载二维码图片4. prom…

电脑维护指南:让你的战友始终高效稳定

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

管理类联考——写作——论说文——实战篇——立意篇——真题审题立意汇总分类

难度&#xff1a;*号越多越难&#xff0c;越需要看。 角度3——4种材料类型、4个立意对象、5种写作态度 寓言类材料**** 2022年 鸟类会飞是因为它们在进化中不断优化了其身体结构。飞行是一项较为特殊的运动&#xff0c;鸟类的躯干进化出了适合飞行的流线型。飞行也是一项需…

【数理知识】刚体基本运动

文章目录 1 刚体定义2 自由刚体3 两种基本运动1 平动2 转动 4 举例 11 计算质心位置&#xff0c;求差得到平移向量2 计算协方差矩阵3 奇异值分解4 计算旋转矩阵 Ref 1 刚体定义 刚体就是质点间距离保持不变的质点系。 刚体的空间位置由任意与刚体固连的不共线三点决定。 2 自…