【数据结构】保姆级单链表教程(概念、分类与实现)

news2024/12/27 12:34:40

目录

🍊前言🍊:

🍈一、链表概述🍈:

1.链表的概念及结构:

2.链表存在的意义:

🍓二、链表的分类🍓:

🥝三、单链表的实现🥝:

1.工程文件:

2.接口实现(本文重点):

①.打印单链表:

②.申请新节点:

③.单链表尾插:

④.单链表头插:

⑤.单链表尾删:

⑥.单链表头删:

⑦.单链表查找:

⑧.单链表插入:

⑨.单链表删除:

⑩.单链表销毁:

🍉四、链表实现全部源码🍉:

1.SList.h:

2.SList.c:

3.test.c:

🍒总结🍒:


🛰️博客主页:✈️銮同学的干货分享基地

🛰️欢迎关注:👍点赞🙌收藏✍️留言

🛰️系列专栏:🎈 数据结构

                       🎈【进阶】C语言学习

                       🎈  C语言学习

🛰️代码仓库:🎉数据结构仓库

                       🎉VS2022_C语言仓库

        家人们更新不易,你们的👍点赞👍和⭐关注⭐真的对我真重要,各位路过的友友麻烦多多点赞关注,欢迎你们的私信提问,感谢你们的转发!

        关注我,关注我,关注我,你们将会看到更多的优质内容!!


🏡🏡 本文重点 🏡🏡:

🚅 链表概念与结构 🚃 链表分类 🚃 单链表实现🚏🚏

🍊前言🍊:

        在上节课中我们学习了线性表中的顺序表相关知识,掌握了顺序表的相关实现与操作。而在这节课中,我将带领各位小伙伴们继续学习线性表中的另一个重要部分,即链表的相关知识学习。

🍈一、链表概述🍈:

1.链表的概念及结构:

        链表(linked list)是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的

2.链表存在的意义:

        通过上节课的学习,我们对顺序表有了较深层次的认知,同时我们发现,顺序表在创建和使用时,存在着一些明显的问题

  • 空间不足时,顺序表需要进行增容,但由于顺序表本质为数组数据在物理上连续存放,因此在进行扩容时要付出较大的空间代价
  • 为避免频繁扩容,基本每次都扩容 2 倍,当扩容次数增多时,就很有可能会造成一定程度的空间浪费
  • 由于顺序表内数据连续存储,我们在向顺序表中位置插入或删除数据时,就需要挪动大量的数据,效率不高

        于是人们针对顺序表的这些缺陷,设计出了链表这个概念来克服这些不足

        而链表克服这些缺陷的方法是,将每一个节点划分为数据与指针两部分,数据部分用于存储数据而指针部分用于指向下一节点。这样做的好处是通过指针指向下一节点,于是数据的物理存储就可以不必连续,于是无论是在扩容,还是在插入与删除数据时,都能快速、方便的实现,并且不会造成很大的空间浪费

🍓二、链表的分类🍓:

1.单向或双向:

2.带头或不带头:

3.循环或非循环:

虽然有很多种不同的链表结构,但是最常用的链表结构主要是两种:无头单向非循环链表带头双向循环链表

  • 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。
  • 带头双向循环链表:结构最复杂,一般用在单独存储数据。虽然它结构复杂,但在实际使用中使用代码实现后,优秀的结构会带来很多优势,实现反而更加简单。并且在我们的实际中所使用的链表数据结构,一般都是带头双向循环链表

🥝三、单链表的实现🥝:

1.工程文件:

        与顺序表的实现方式类似,也使用模块化开发格式,使用 SList.h 、SList.c 、test.c 三个文件进行代码书写:

  • SeqList.h存放函数声明、包含其他头文件、定义宏
  • SeqList.c书写函数定义,书写函数实现
  • test.c书写程序整体执行逻辑

        这其中,我们的接口实现主要研究的是函数实现文件 SeqList.c 中的内容,对 test.c 文件中的内容分不关心

2.接口实现(本文重点):

        这里是本文重点中的重点,即 SeqList.c 文件中的接口具体实现:

①.打印单链表:

  • 执行操作前无需进行断言,原因是循环条件为空指针,则条件不满足并停止循环,不会出现死循环。
  • 根据指针循环操作,打印数据后使指针指向节点内存放下一节点地址的指针 NEXT
void SListPrint(SLNode* SLHead)
{
	SLNode* cur = SLHead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

②.申请新节点:

  • 在各项操作前,需动态申请新节点,再对新申请的节点进行操作
SLNode* BuyListNode(SLDataType x)
{
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
    if (newnode == NULL)
	{
		perror("newnode:>");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

③.单链表尾插:

  • 如果此时头节点为空指针,说明此时单链表内没有节点,此时只需要将申请来的新节点作为头节点即可。
  • 头节点不为空,则应当首相找到尾节点,使尾结点指针指向申请来的新节点后,再使新节点指针指向空即可。
void SLPushBack(SLNode** pphead, SLDataType x)
{
	SLNode* newnode = BuyListNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		//找到尾结点
		SLNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}
  • 测试尾插接口功能实现:

④.单链表头插:

  • 头插实现非常简单,首先申请新节点,先使新节点的指针指向原来的头节点,再使链表头指向新节点即可
  • 这里不需要考虑空节点的原因是,就算链表内没有内容,即首节点为空新节点指针指向空也没有问题申请新节点时原本就指向空)。
void SLPushFront(SLNode** pphead, SLDataType x)
{
	SLNode* newnode = BuyListNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}
  • 测试头插接口功能实现:

⑤.单链表尾删:

  • 执行操作前需要进行非空判断,防止传入空指针。
  • 若链表内只有一个节点,则直接释放并置空即可
  • 若有一个以上节点,则当执行下面三个步骤
  1. 首先寻找尾节点,找到后将其释放并置空
  2. 但在释放前,必须将倒数第二个节点的指针指向空否则将在指向最后一个被释放的节点时,变成野指针
  3. 单向链表无法回溯,于是我们应当定义另一个指针,在每次移动尾节点指针前保存当前节点的位置
void SLPopBack(SLNode** pphead)
{
	//判断链表是否为空:
	if (*pphead == NULL)
	{
		return;
	}
	//若只有一个节点,直接释放并置空即可:
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	//若有多个节点则执行多步尾删:
	else
	{
		SLNode* tail = *pphead;
		SLNode* prev = NULL;
		//找到尾节点:
		while (tail->next != NULL)
		{
			prev = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;
		prev->next = NULL;
	}
}
  • 测试尾删接口功能实现:

⑥.单链表头删:

  • 执行操作前判断指针非空,防止对空指针进行操作。
  • 使链表头指向第二个节点,接着将第一个节点释放并置空即可
void SLPopFront(SLNode** pphead)
{
	if (*pphead == NULL)
	{
		return;
	}
	else
	{
		SLNode* next = (*pphead)->next;
		free(*pphead);
		*pphead = next;
	}
}
  • 测试头删接口功能实现:

⑦.单链表查找:

  • 采用遍历思想依次对每一个节点的数据进行判断,符合条件即进行打印,不符合条件则继续向后遍历,直至指向 NULL,并且因此无需进行非空判断
void SLFind(SLNode* phead, SLDataType x)
{
	SLNode* cur = phead;
	int count = 1;
	while (cur)
	{
		if (cur->data == x)
		{
			printf("第%d个节点:%p -> %d\n", count++, cur, x);
		}
			cur = cur->next;
	}
}
  • 测试查找接口功能实现:

⑧.单链表插入:

        单链表在插入新节点时有两种插入方式,一种是在目标节点前方插入,另一种是在目标节点后方插入,因此需要分别进行实现

Ⅰ、单链表前插:

  • 前插有两种情况,一种是在首节点处插入,此时即相当于头插操作
  • 另一种是在非首节点前插入,此时首先申请新节点,接着遍历单链表,找到插入位置后,使新节点指向目标节点后插入其前方
void SLInsertFront(SLNode** pphead, SLNode* pos, SLDataType x)
{
	//首先申请新节点
	SLNode* newnod = BuyListNode(x);
	if (*pphead == pos)
	{
		newnod->next = *pphead;
		*pphead = newnod;
	}
	else
	{
		//找到目标节点 pos 的前一个节点:
		SLNode* PostPrev = *pphead;
		while (PostPrev->next != pos)
		{
			PostPrev = PostPrev->next;
		}
		//找到后插入新节点:
		PostPrev->next = newnod;
		newnod->next = pos;
	}
}
  • 测试前插接口功能实现:

Ⅱ、单链表后插:

  • 在前插操作时,我们需要遍历整个链表来查找插入位置,因此效率较为低下,于是我们通常使用后插的方式插入新节点。
  • 后插直接申请节点,插入目标位置后即可。
void SLInsertAfter(SLNode* pos, SLDataType x)
{
	SLNode* newnode = BuyListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}
  • 测试后插接口功能实现:

⑨.单链表删除:

  • 单链表的删除很简单,分为两种情况进行处理,一种情况是整个链表中只有一个节点,则删除节点相当于释放整个数组并置空
  • 另一种情况是含有一个以上节点,此时只需要让目标节点的前一个节点指针指向后一个节点,再释放目标节点并置空即可。
void SLErase(SLNode** pphead, SLNode* pos)
{
	if (*pphead == pos)
	{
		*pphead = pos->next;
		free(pos);
		pos = NULL;
	}
	else
	{
		SLNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}
  • 测试删除接口功能实现:

⑩.单链表销毁:

  • 遍历整个单链表,将每一个节点都进行释放并置空即可
void SListDestory(SLNode** pphead)
{
	if (*pphead == NULL)
	{
		return;
	}
	SLNode* cur = *pphead;
	while (cur)
	{
		SLNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}

🍉四、链表实现全部源码🍉:

1.SList.h:

#pragma once

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

typedef int SLDataType;

//单链表节点结构:
typedef struct SListNode
{
	SLDataType data;
	struct SListNode* next;
}SLNode;

void SLPrint(SLNode* SLHead);    //打印单链表
SLNode* BuyListNode(SLDataType x);    //申请新节点
void SLPushBack(SLNode** pphead, SLDataType x);    //单链表尾插
void SLPushFront(SLNode** pphead, SLDataType x);    //单链表头插
void SLPopBack(SLNode** pphead);    //单链表尾删
void SLPopFront(SLNode** pphead);    //单链表头删
void SLFind(SLNode* phead, SLDataType x);    //单链表查找
void SLInsertFront(SLNode** pphead, SLNode* pos, SLDataType x);    //单链表前插
void SLInsertAfter(SLNode* pos, SLDataType x);    //单链表后插
void SLErase(SLNode** pphead, SLNode* pos);    //单链表删除
void SLDestory(SLNode** pphead);    //单链表销毁

2.SList.c:

#define _CRT_SECURE_NO_WARNINGS 1

#include"SList.h"

//打印单链表:
void SLPrint(SLNode* SLHead)
{
	SLNode* cur = SLHead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

//申请节点:
SLNode* BuyListNode(SLDataType x)
{
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	if (newnode == NULL)
	{
		perror("newnode:>");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

//单链表尾插:
void SLPushBack(SLNode** pphead, SLDataType x)
{
	SLNode* newnode = BuyListNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		//找到尾结点
		SLNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

//单链表头插:
void SLPushFront(SLNode** pphead, SLDataType x)
{
	SLNode* newnode = BuyListNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

//单链表尾删:
void SLPopBack(SLNode** pphead)
{
	//判断链表是否为空:
	if (*pphead == NULL)
	{
		return;
	}
	//若只有一个节点,直接释放并置空即可:
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	//若有多个节点则执行多步尾删:
	else
	{
		SLNode* tail = *pphead;
		SLNode* prev = NULL;
		//找到尾节点:
		while (tail->next != NULL)
		{
			prev = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;
		prev->next = NULL;
	}
}

//单链表头删
void SLPopFront(SLNode** pphead)
{
	if (*pphead == NULL)
	{
		return;
	}
	else
	{
		SLNode* next = (*pphead)->next;
		free(*pphead);
		*pphead = next;
	}
}

//单链表查找
void SLFind(SLNode* phead, SLDataType x)
{
	SLNode* cur = phead;
	int count = 1;
	while (cur)
	{
		if (cur->data == x)
		{
			printf("第%d个节点:%p -> %d\n", count++, cur, x);
		}
			cur = cur->next;
	}
}

//单链表前插:
void SLInsertFront(SLNode** pphead, SLNode* pos, SLDataType x)
{
	//首先申请新节点
	SLNode* newnod = BuyListNode(x);
	if (*pphead == pos)
	{
		newnod->next = *pphead;
		*pphead = newnod;
	}
	else
	{
		//找到目标节点 pos 的前一个节点:
		SLNode* PostPrev = *pphead;
		while (PostPrev->next != pos)
		{
			PostPrev = PostPrev->next;
		}
		//找到后插入新节点:
		PostPrev->next = newnod;
		newnod->next = pos;
	}
}

//单链表后插:
void SLInsertAfter(SLNode* pos, SLDataType x)
{
	SLNode* newnode = BuyListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

//单链表删除:
void SLErase(SLNode** pphead, SLNode* pos)
{
	if (*pphead == pos)
	{
		*pphead = pos->next;
		free(pos);
		pos = NULL;
	}
	else
	{
		SLNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

//单链表销毁:
void SLDestory(SLNode** pphead)
{
	if (*pphead == NULL)
	{
		return;
	}
	SLNode* cur = *pphead;
	while (cur)
	{
		SLNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}

3.test.c:

#define _CRT_SECURE_NO_WARNINGS 1

#include"SList.h"

void TestSList1()
{
    SLNode* plist = NULL;
    //单链表尾插:
    SLPushBack(&plist, 1);
    SLPushBack(&plist, 2);
    SLPushBack(&plist, 3);
    SLPushBack(&plist, 4);
    SLPrint(plist);
    //单链表后插:
    SLInsertAfter(plist->next, 5);
    SLPrint(plist);
}

int main()
{
    TestSList1();
    return 0;
}

//单链表头插:
//SLNode* plist = NULL;
单链表尾插:
//SLPushBack(&plist, 1);
//SLPushBack(&plist, 2);
//SLPushBack(&plist, 3);
//SLPushBack(&plist, 4);
//SLPrint(plist);
单链表头插:
//SLPushFront(&plist, 2);
//SLPushFront(&plist, 3);
//SLPushFront(&plist, 4);
//SLPrint(plist);

//单链表尾删:
//SLNode* plist = NULL;
单链表尾插:
//SLPushBack(&plist, 1);
//SLPushBack(&plist, 2);
//SLPushBack(&plist, 3);
//SLPushBack(&plist, 4);
//SLPrint(plist);
单链表尾删:
//SLPopBack(&plist);
//SLPopBack(&plist);
//SLPopBack(&plist);
//SLPrint(plist);

//单链表头删:
//SLNode* plist = NULL;
单链表尾插:
//SLPushBack(&plist, 1);
//SLPushBack(&plist, 2);
//SLPushBack(&plist, 3);
//SLPushBack(&plist, 4);
//SLPrint(plist);
单链表头删:
//SLPopFront(&plist);
//SLPrint(plist);
//SLPopFront(&plist);
//SLPrint(plist);
//SLPopFront(&plist);
//SLPrint(plist);
//SLPopFront(&plist);
//SLPrint(plist);

//单链表查找:
//SLNode* plist = NULL;
单链表尾插:
//SLPushBack(&plist, 1);
//SLPushBack(&plist, 2);
//SLPushBack(&plist, 3);
//SLPushBack(&plist, 2);
//SLPushBack(&plist, 2);
//SLPushBack(&plist, 4);
//SLPushBack(&plist, 2);
//
//SLPrint(plist);
单链表查找:
//SLFind(plist, 2);
//SLPrint(plist);

//单链表前插:
//SLNode* plist = NULL;
单链表尾插:
//SLPushBack(&plist, 1);
//SLPushBack(&plist, 2);
//SLPushBack(&plist, 3);
//SLPushBack(&plist, 4);
//SLPrint(plist);
单链表前插:
//SLInsertFront(&plist, (plist->next)->next, 3);;
//SLPrint(plist);

//单链表后插:

//单链表删除:
//SLNode* plist = NULL;
单链表尾插:
//SLPushBack(&plist, 1);
//SLPushBack(&plist, 2);
//SLPushBack(&plist, 3);
//SLPushBack(&plist, 4);
//SLPrint(plist);
单链表删除:
//SLErase(&plist, (plist->next)->next);
//SLPrint(plist);

//单链表销毁:
//SLNode* plist = NULL;
单链表尾插:
//SLPushBack(&plist, 1);
//SLPushBack(&plist, 2);
//SLPushBack(&plist, 3);
//SLPushBack(&plist, 4);
//SLPrint(plist);
单链表销毁:
//SLDestory(plist);
//SLPrint(plist);

🍒总结🍒:

        今天我们认识并学习了单向无头链表的相关概念、结构与接口实现,并且针对每个常用的功能接口都进行了实现分解,并对各个接口的各项注意点都进行了强调说明,希望能对各位小伙伴们的链表学习提供一些谨小的帮助。

        🔥🔥努力的时间还不够,哪有时间去绝望🔥🔥

        更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~  你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

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

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

相关文章

​盘点几款国内外安全稳定的域名解析平台​

众所周知&#xff0c;有了域名后想建站使用&#xff0c;必须要先解析域名。域名使用注册商一般会提供域名解析服务&#xff0c;这虽然为用户提供了方便&#xff0c;但功能大多有限&#xff0c;使用第三方域名解析平台就成了非常必要的选择。今天&#xff0c;小编就为大家盘点几…

计算机视觉OpenCv学习系列:第四部分、键盘+鼠标响应操作

第四部分、键盘鼠标响应操作第一节、键盘响应操作1.键盘响应事件2.键盘响应3.代码练习与测试第二节、鼠标操作与响应1.鼠标事件与回调2.鼠标操作3.代码练习与测试学习参考第一节、键盘响应操作 键盘响应中有一个函数叫做waitKey&#xff0c;所有的获取键盘键值都是通过waitKey…

【经典笔试题】动态内存管理

test1&#xff1a;void GetMemory(char* p) {p (char*)malloc(100); } void Test(void) {char* str NULL;GetMemory(str);strcpy(str, "hello world");printf(str); }int main() {Test();return 0; }请问执行上面代码&#xff0c;会出现什么结果&#xff1f;解析&a…

7. R语言【独立性检验】:卡方独立性检验、Fisher精确检验 、Cochran-Mantel-Haenszel检验

文章目录1. 卡方检验2. 费希尔精确检验&#xff08;Fisher Exact Test&#xff09;3. Cochran-Mantel-Haenszel检验独立性检验&#xff1a;用来判断变量之间相关性的方法&#xff0c;如果两个变量彼此独立&#xff0c;那么两者统计上就是不相关的 1. 卡方检验 可以使用chisq.…

Java面向对象之多态、内部类、常用API

目录面向对象之三大特性之三&#xff1a;多态多态的概述、多态的形式多态的好处多态下引用数据类型的类型转换多态的综合案例内部类内部类概述内部类之一&#xff1a;静态内部类内部类之二&#xff1a;成员内部类内部类之三&#xff1a;局部内部类内部类之四&#xff1a;匿名内…

JavaSE与网络面试题

大佬的&#xff1a; https://github.com/Snailclimb/JavaGuide https://osjobs.net/topk/all/ 自增自减 要点&#xff1a; 赋值 &#xff0c;最后计算 右边的从左到右加载值&#xff0c;一次压入操作数栈 实际先算哪个看运算符的优先级 自增、自减操作都是直接修改变量…

SpringCloud面试题

为什么需要学习Spring Cloud 不论是商业应用还是用户应用&#xff0c;在业务初期都很简单&#xff0c;我们通常会把它实现为单体结构的应用。但是&#xff0c;随着业务逐渐发展&#xff0c;产品思想会变得越来越复杂&#xff0c;单体结构的应用也会越来越复杂。这就会给应用带…

带你走入虚函数和多态的世界(c++)

1、什么是虚函数 C类中用virtual修饰的函数叫做虚函数&#xff0c;构造函数没有虚构造函数&#xff0c;存在虚析构函数&#xff0c;C所有虚函数都是一个指针去存储的&#xff0c;所以具有虚函数的类&#xff0c;内存会增加一个指针大小的内存 #include<iostream> #includ…

第一章:计算机网络概述

一、计算机网络基本概念 1、什么是计算机网路&#xff1f; 计算机网络是通信技术与计算机技术紧密结合的产物。计算机网络就是一种特殊的通信网络&#xff0c;其特别之处就是&#xff0c;其信源和信宿通常就是我们所说的计算机&#xff0c;发出的信息通常就是数字化的一些信息…

数据分析-深度学习 Pytorch Day5

李宏毅《机器学习》第6讲——梯度下降Review: 梯度下降法在回归问题的第三步中&#xff0c;需要解决下面的最优化问题&#xff1a;我们要找一组参数θ &#xff0c;让损失函数越小越好&#xff0c;这个问题可以用梯度下降法解决。假设θ有里面有两个参数θ1,θ2&#xff0c;随机…

FPGA 20个例程篇:19.OV7725摄像头实时采集送HDMI显示(一)

第七章 实战项目提升&#xff0c;完善简历 19.OV7725摄像头实时采集送HDMI显示&#xff08;一&#xff09; 在例程“OV7725摄像头实时采集送HDMI显示”中&#xff0c;我们将走近FPGA图像处理的世界&#xff0c;图像处理、数字信号、高速接口也一直被业界公认为FPGA应用的三大主…

k8s ingress概念和实践

什么是Ingress Ingress 是对集群中服务的外部访问进行管理的 API 对象&#xff0c;典型的访问方式是 HTTP/HTTPS 该特性从1.19版本开始作为stable状态进行发布 Ingress 公开从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。 如下…

Python算法:三种简单排序的方法

目录 前言 1、插入排序 实例 2、选择排序 实例 3、冒泡排序 实例 前言 声明&#xff1a;本文所有动图来源为菜鸟教程 &#x1f340;作者简介&#xff1a;被吉师散养、喜欢前端、学过后端、练过CTF、玩过DOS、不喜欢java的不知名学生。 &#x1f341;个人主页&#xff1a;红…

监督学习、半监督学习、无监督学习、自监督学习、强化学习和对比学习

目录 一、监督学习 二、半监督学习 三、无监督学习 3.1.聚类算法 3.2.降维算法 3.3.异常检测 3.4.自动编码器 3.5.生成模型 3.6.关联规则学习 3.7.自组织映射(SOM) 四、自监督学习 4.1. 基于上下文&#xff08;Context based&#xff09; 4.2. 基于时序&#xff08…

85.【Vue-细刷-01】

Vue(一)、利用Vscode开发Vue1.在桌面创建文件夹code2.使用Vscode进行打开这个文件夹3.在Vscode的右键创建文件夹4.右键创建.html文件(二)、第一个Vue程序1.下载并引入Vue.js2.引入vue.js3.创建视图层4.创建Model层5.获取Vue实列中的数据6.效果展示⭐为什么要使用new 关键字来创…

文件操作(二):学习笔记10

目录 一.概念梳理 1.文件的分类 2.程序运行时&#xff0c;内存和外存数据交流的过程 二.文件缓冲区 三.常用的文件读写函数笔记 1.常用格式化文件读写函数 (1)格式化文件写入函数 用fprintf进行文件写入操作&#xff1a; (2)格式化文件读取函数 用fscanf进行文件读取 2…

Java枚举类与注解

目录 一、枚举类的使用 枚举类的实现 枚举类的属性 自定义枚举类 步骤 举例 使用enum定义枚举类 使用说明 举例 Enum类的主要方法 实现接口的枚举类 二、注解的使用 概述 常见的Annotation示例 自定义Annotation&#xff08;参照SupressWarnings 定义&#xff09…

一不小心,登上支付宝开发者社区热文榜单Top3

大家好&#xff0c;我是小悟 那天中午要午休的时候&#xff0c;看到微信通讯录新朋友有个红色1&#xff0c;像俺这种有强迫症的&#xff0c;那不得去把它点掉。打开一看&#xff0c;加好友的备注是“我是熊二&#xff0c;支付宝开发者社区运营”。 收到支付宝社区的运营添加微…

【ROS】dynamic_reconfigure配置详细说明

文章目录 文章目录 前言 一、编写.cfg文件 二、为节点配置dynamic_reconfigure 总结 前言 dynamic_reconfigure配置是ROS中为了方便用户对程序中的参数进行实时调整而推出的工具&#xff0c;配置好自己的dynamic_reconfigure文件后&#xff0c;可以很方便的使用ROS提供的r…

2022-12-18 网工进阶(三十八)MPLS LDP---LDP基础、工作原理(会话、标签的发布和管理、特性)、配置举例

LDP概述 LDP是MPLS的一种控制协议&#xff0c;相当于传统网络中的信令协议&#xff0c;负责FEC的分类、标签的分配以及LSP的建立和维护等操作。LDP规定了标签分发过程中的各种消息以及相关处理过程。 LDP的工作过程主要分为两部分&#xff1a;LSR之间建立LDP会话&#xff1b;…