学习笔记---0基础+干货满满的单链表专题~~

news2024/11/18 12:35:58


目录​​​​​​​

1. 链表的概念及结构👑

1.1 什么是链表?👀

1.2 为什么需要链表?⁉️

1.3 链表的结构是怎么样的?❓

2. 链表的分类🦜

3. 实现单链表🫵

3.1 要实现的目标🎯

3.2 创建+打印🐤

3.2.1 SList.h

3.2.2 SList.c

3.2.3 test.c

3.2.4 代码运行测试​​​​​​​​​​​​​​

3.3 尾插🍕

3.3.0 尾插思路分析​​​​​​​

3.3.1 SList.h

3.3.2 SList.c

3.3.3 test.c

3.3.4 代码运行测试

3.4 头插🍤

3.4.0 头插思路分析

3.4.1 SList.h

3.4.2 SList.c

3.4.3 test.c

3.4.4 代码运行测试

3.5 尾删🍮

3.5.0 尾删思路分析

3.5.1 SList.h

3.5.2 SList.c

3.5.3 test.c

3.5.4 代码运行测

3.6 头删🥃

3.6.0 头删思路分析

3.6.1 SList.h

3.6.2 SList.c

3.6.3 test.c

3.6.4 代码运行测试

3.7 指定节点之前/之后插入节点+查找指定位置的数据🥎

3.7.0 指定节点之前/之后插入节点思路分析

3.7.1 SList.h

3.7.2 SList.c

3.7.3 test.c

3.7.4 代码运行测试

3.8 删除pos节点or pos节点之后的节点🏓

 3.8.0 删除pos节点or pos节点之后的节点思路分析

3.8.1 SList.h

3.8.2 SList.c

3.8.3 test.c

3.8.4 代码运行测试

3.9 销毁🌔

3.9.0 销毁思路分析

3.9.1 SList.h

3.9.2 SList.c

3.9.3 test.c

3.9.4 代码运行测试


1. 链表的概念及结构👑

1.1 什么是链表?👀

通过顺序表的学习,我们对线性表和顺序表有了一定的了解🫡

其实,链表也是线性表的一种,链表逻辑连续物理不连续地址不连续,这一点是和顺序表不同的

为了方便大家具像化理解,我们以火车车厢🚄举例:


我们发现:车厢(独立的---可以任意增加or减少but不影响其他车厢)是(逻辑上)连续的排列的,但是车厢编号(物理上)不一定连续排列

假设每节⻋厢的⻋⻔都是锁上的状态,需要不同的钥匙才能解锁,每次只能携带⼀把钥匙的情况下如何从⻋头⾛到⻋尾?

最简单的做法:每节⻋厢⾥都放⼀把下⼀节⻋厢的钥匙。

那么,链表(我们这里特指单链表)中的“车厢”是怎样的呢?


与顺序表不同的是,链表⾥的每节"⻋厢"都是独⽴申请的空间(可能连续,也可能不连续),我们称之为“结点/节点

节点的组成主要有两个部分:当前节点要保存的数据和保存下⼀个节点的地址(指针变量)

注意⚠️

我们这里特指的是单链表,所以如图所示,当到尾节点的时候,尾节点后面没有节点了,所以地址为空,即指向NULL


1.2 为什么需要链表?⁉️

我们在顺序表的应用那一篇博客提及到了顺序表的思考🤔

1.链表申请的空间都是独立的,需要几个我们就申请几个,不会造成浪费或者申请空间不够

2.拷贝数据的时候,也不需要释放旧空间

3.中间/头部的插入删除,只需要修改指针的指向,效率较高

............

1.3 链表的结构是怎么样的?❓

结合前⾯学到的结构体知识,我们可以给出每个节点对应的结构体代码:

假设当前保存的节点为整型:

struct SListNode
{
 int data; //节点数据
 struct SListNode* next; //指针变量⽤保存下⼀个节点的地址
};

2. 链表的分类🦜


1.单向:一个方向---向后链接

2.双向:两个方向---前后都可以链接(我们下下期会讲)

3.带头:类似于哨兵位,不保存有效数据,只是标识一个头(哨兵位不能为空,也不能改变)

4.不带头:没有哨兵位,第一个节点保存有效数据和下一个节点的地址(为了方便,我们下面在实现单链表的时候会把第一个节点直接叫作“头节点”,但是和哨兵位所指代的头节点不一样)

5.循环:尾节点不指向NULL,而是指向头节点(带头)or第一个节点(不带头)的地址,使头尾相连--->循环♻️

6.不循环:尾节点指向NULL

链表的结构⾮常多样,以下情况组合起来就有8种(2 x 2 x 2)链表结构:


但是,这么多种链表,我们最常用的是单向不带头不循环链表(我们接下来简称单链表)和双向带头循环链表(我们下下期讲的时候简称双链表)

3. 实现单链表🫵

3.1 要实现的目标🎯

和顺序表一样,我们需要源文件和头文件来实现,也需要实现多个接口,方便使用(也可以为下期的单链表实现通讯录做准备)

我们需要多个接口帮助我们实现:创建、一系列具体操作、销毁

具体操作(一切以实现通讯录为目标)包括:头部/尾部插入数据、头部/尾部删除数据、打印出单链表、指定节点之后/之前插入节点、删除指定节点之后的节点、查找指定节点

3.2 创建+打印🐤

3.2.1 SList.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<string.h>

//定义单链表节点的结构体(创建)
typedef int SLDataType;
typedef struct SListNode
{
	SLDataType data;//要保存的数据
	struct SListNode* next;//存储下一个节点的地址
}SlNode;

//打印
void SLPrint(SLNode* phead);

3.2.2 SList.c

#include"SList.h"
//打印
void SLPrint(SlNode* phead)
{
	//循环打印
	SlNode* pcur = phead;//pcur从头节点开始遍历链表
	//不用phead遍历--->以后需要用到指向头节点的地址时,帮助我找到地址
	while (pcur)//pcur指向NULL的时候结束遍历
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;//pcur指向下一个节点继续遍历
	}
	printf("NULL\n");
}

3.2.3 test.c

#include"SList.h"
void SLTest()
{
	//创建节点--->申请空间
	//存储有效数据
	SlNode* node1 = (SlNode*)malloc(sizeof(SlNode));
	node1->data = 1;
	SlNode* node2 = (SlNode*)malloc(sizeof(SlNode));
	node2->data = 2;
	SlNode* node3 = (SlNode*)malloc(sizeof(SlNode));
	node3->data = 3;
	SlNode* node4 = (SlNode*)malloc(sizeof(SlNode));
	node4->data = 4;
	SlNode* node5 = (SlNode*)malloc(sizeof(SlNode));
	node5->data = 5;
	//存储下一个节点的地址
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = node5;
	node5->next = NULL;//单向不带头不循环链表

	//打印
	SlNode* plist = node1;
	SLPrint(plist);
}
int main()
{
	SLTest();
	return 0;
}

3.2.4 代码运行测试​​​​​​​​​​​​​​


3.3 尾插🍕

3.3.0 尾插思路分析​​​​​​​


3.3.1 SList.h

//尾插
void SLPushBack(SlNode** pphead, SLDataType x);//一级指针要二级指针接受才可以改变形参

3.3.2 SList.c

//插入数据都需要创建空间--->我们单独写出来,避免重复多次
SlNode* SLBuyNNode(SLDataType x)
{
	SlNode* node = (SlNode*)malloc(sizeof(SlNode));
	if (node == NULL)
	{
		perror("malloc");
		return 1;
	}
	node->data = x;
	node->next = NULL;
	return node;
}
//尾插
void SLPushBack(SlNode** pphead, SLDataType x)//一级指针要二级指针接受才可以改变
{
    //传过来的指针不能为空
	assert(pphead);
	SlNode* node = SLBuyNNode(x);
	//链表为空,直接插入
	if (*pphead == NULL)
	{
		*pphead = node;
		return 1;
	}
	//到这说明不为空,遍历
	SlNode* pcur = *pphead;
	while (pcur->next)
	{
		pcur = pcur->next;
	}
	pcur->next = node;
}

3.3.3 test.c

#include"SList.h"
void SLTest()
{
	//创建节点--->申请空间
	//存储有效数据
	SlNode* node1 = (SlNode*)malloc(sizeof(SlNode));
	node1->data = 1;
	SlNode* node2 = (SlNode*)malloc(sizeof(SlNode));
	node2->data = 2;
	SlNode* node3 = (SlNode*)malloc(sizeof(SlNode));
	node3->data = 3;
	SlNode* node4 = (SlNode*)malloc(sizeof(SlNode));
	node4->data = 4;
	SlNode* node5 = (SlNode*)malloc(sizeof(SlNode));
	node5->data = 5;
	//存储下一个节点的地址
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = node5;
	node5->next = NULL;//单向不带头不循环链表

	//打印
	SlNode* plist = node1;
	SLPrint(plist);
}
void SLTest01()
{
	SlNode* plist = NULL;
	//尾插
	SLPushBack(&plist, 1);
	SLPushBack(&plist, 2);
	SLPushBack(&plist, 3);
	SLPushBack(&plist, 4);
	SLPrint(plist);
}
int main()
{
	SLTest();
	SLTest01();
	return 0;
}

3.3.4 代码运行测试


3.4 头插🍤

3.4.0 头插思路分析


3.4.1 SList.h

//头插
void SLPushFront(SlNode** pphead, SLDataType x);//一级指针要二级指针接受才可以改变形参

3.4.2 SList.c

//头插
void SLPushFront(SlNode** pphead, SLDataType x)//一级指针要二级指针接受才可以改变形参
{
	//传过来的指针不能为空
	assert(pphead);
	SlNode* node = SLBuyNNode(x);
	//新节点和原来的头节点链接
	node->next = *pphead;
	//新节点成为新的头节点
	*pphead = node;
}

3.4.3 test.c

#include"SList.h"
void SLTest()
{
	//创建节点--->申请空间
	//存储有效数据
	SlNode* node1 = (SlNode*)malloc(sizeof(SlNode));
	node1->data = 1;
	SlNode* node2 = (SlNode*)malloc(sizeof(SlNode));
	node2->data = 2;
	SlNode* node3 = (SlNode*)malloc(sizeof(SlNode));
	node3->data = 3;
	SlNode* node4 = (SlNode*)malloc(sizeof(SlNode));
	node4->data = 4;
	SlNode* node5 = (SlNode*)malloc(sizeof(SlNode));
	node5->data = 5;
	//存储下一个节点的地址
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = node5;
	node5->next = NULL;//单向不带头不循环链表

	//打印
	SlNode* plist = node1;
	SLPrint(plist);
}
void SLTest01()
{
	SlNode* plist = NULL;
	//尾插
	SLPushBack(&plist, 1);
	SLPushBack(&plist, 2);
	SLPushBack(&plist, 3);
	SLPushBack(&plist, 4);
	SLPrint(plist);
	//头插
	SLPushFront(&plist, 5);
	SLPrint(plist);
}
int main()
{
	SLTest();
	SLTest01();
	return 0;
}

3.4.4 代码运行测试


3.5 尾删🍮

3.5.0 尾删思路分析


​​​​​​​


3.5.1 SList.h

//尾删
void SLPopBack(SlNode** pphead);

3.5.2 SList.c

///尾删
void SLPopBack(SlNode** pphead)
{
	assert(pphead&&*pphead);
	//只有1个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	//多个节点
		else
	{
		SlNode* prev = NULL;
		SlNode* ptail = *pphead;
		while (prev->next != NULL)
		{
			prev = ptail;
			ptail = ptail->next;
		}
		prev->next = ptail->next;
		free(ptail);
		ptail = NULL;
	}
}

3.5.3 test.c

#include"SList.h"
void SLTest()
{
	//创建节点--->申请空间
	//存储有效数据
	SlNode* node1 = (SlNode*)malloc(sizeof(SlNode));
	node1->data = 1;
	SlNode* node2 = (SlNode*)malloc(sizeof(SlNode));
	node2->data = 2;
	SlNode* node3 = (SlNode*)malloc(sizeof(SlNode));
	node3->data = 3;
	SlNode* node4 = (SlNode*)malloc(sizeof(SlNode));
	node4->data = 4;
	SlNode* node5 = (SlNode*)malloc(sizeof(SlNode));
	node5->data = 5;
	//存储下一个节点的地址
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = node5;
	node5->next = NULL;//单向不带头不循环链表

	//打印
	SlNode* plist = node1;
	SLPrint(plist);
}
void SLTest01()
{
	SlNode* plist = NULL;
	//尾插
	SLPushBack(&plist, 1);
	SLPushBack(&plist, 2);
	SLPushBack(&plist, 3);
	SLPushBack(&plist, 4);
	SLPrint(plist);
	//头插
	SLPushFront(&plist, 5);
	SLPrint(plist);
	//尾删
	SLPopBack(&plist);
	SLPrint(plist);
}
int main()
{
	SLTest();
	SLTest01();
	return 0;
}

3.5.4 代码运行测


3.6 头删🥃

3.6.0 头删思路分析


3.6.1 SList.h

//头删
void SLPopFront(SlNode** pphead);

3.6.2 SList.c

//头删
void SLPopFront(SlNode** pphead)
{
	assert(pphead&&*pphead);
	SlNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
	del = NULL;
}

3.6.3 test.c

#include"SList.h"
void SLTest()
{
	//创建节点--->申请空间
	//存储有效数据
	SlNode* node1 = (SlNode*)malloc(sizeof(SlNode));
	node1->data = 1;
	SlNode* node2 = (SlNode*)malloc(sizeof(SlNode));
	node2->data = 2;
	SlNode* node3 = (SlNode*)malloc(sizeof(SlNode));
	node3->data = 3;
	SlNode* node4 = (SlNode*)malloc(sizeof(SlNode));
	node4->data = 4;
	SlNode* node5 = (SlNode*)malloc(sizeof(SlNode));
	node5->data = 5;
	//存储下一个节点的地址
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = node5;
	node5->next = NULL;//单向不带头不循环链表

	//打印
	SlNode* plist = node1;
	SLPrint(plist);
}
void SLTest01()
{
	SlNode* plist = NULL;
	//尾插
	SLPushBack(&plist, 1);
	SLPushBack(&plist, 2);
	SLPushBack(&plist, 3);
	SLPushBack(&plist, 4);
	SLPrint(plist);
	//头插
	SLPushFront(&plist, 5);
	SLPrint(plist);
	//尾删
	SLPopBack(&plist);
	SLPrint(plist);
	//头删
	SLPopFront(&plist);
	SLPrint(plist);
}
int main()
{
	SLTest();
	SLTest01();
	return 0;
}

3.6.4 代码运行测试


3.7 指定节点之前/之后插入节点+查找指定位置的数据🥎

3.7.0 指定节点之前/之后插入节点思路分析



3.7.1 SList.h

//查找数据
SlNode* SLFind(SlNode** pphead, SLDataType x);

//指定位置之前插入
void SLInsert(SlNode** pphead,SlNode* pos, SLDataType x);

//指定位置之后插入
void SLInsertAfter(SlNode* pos, SLDataType x);

3.7.2 SList.c

//查找数据
SlNode* SLFind(SlNode** pphead, SLDataType x)
{
	assert(pphead);
	SlNode* pcur = *pphead;
	while (pcur)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}

//指定位置之前插入
void SLInsert(SlNode** pphead, SlNode* pos, SLDataType x)
{
	assert(pphead && *pphead&&pos);
	//创建空间
	SlNode* node = SLBuyNode(x);
	//pos为第一个节点(只有1个节点)
	if (pos == (*pphead))
	{
		node->next = *pphead;
		*pphead = node;
		return 1;
	}
	//pos不为第一个节点
	//找pos节点的前一个节点
	SlNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	node->next = pos;
	prev->next = node;
}
//指定位置之后插入
void SLInsertAfter(SlNode* pos, SLDataType x)
{
	assert(pos);
	//创建空间
	SlNode* node = SLBuyNNode(x);
	node->next = pos->next;
	pos->next = node;
}

3.7.3 test.c

#include"SList.h"
void SLTest()
{
	//创建节点--->申请空间
	//存储有效数据
	SlNode* node1 = (SlNode*)malloc(sizeof(SlNode));
	node1->data = 1;
	SlNode* node2 = (SlNode*)malloc(sizeof(SlNode));
	node2->data = 2;
	SlNode* node3 = (SlNode*)malloc(sizeof(SlNode));
	node3->data = 3;
	SlNode* node4 = (SlNode*)malloc(sizeof(SlNode));
	node4->data = 4;
	SlNode* node5 = (SlNode*)malloc(sizeof(SlNode));
	node5->data = 5;
	//存储下一个节点的地址
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = node5;
	node5->next = NULL;//单向不带头不循环链表

	//打印
	SlNode* plist = node1;
	SLPrint(plist);
}
void SLTest01()
{
	SlNode* plist = NULL;
	//尾插
	SLPushBack(&plist, 1);
	SLPushBack(&plist, 2);
	SLPushBack(&plist, 3);
	SLPushBack(&plist, 4);
	SLPrint(plist);
	//头插
	SLPushFront(&plist, 5);
	SLPrint(plist);
	//尾删
	SLPopBack(&plist);
	SLPrint(plist);
	//头删
	SLPopFront(&plist);
	SLPrint(plist);
	//pos之前插入
	SlNode* find = SLFind(&plist, 2);
	SLInsert(&plist, find, 6);
	SLPrint(plist);
	//pos之后插入
	SlNode* find = SLFind(&plist, 3);
	SLInsertAfter(find, 7);
	SLPrint(plist);
}
int main()
{
	SLTest();
	SLTest01();
	return 0;
}

3.7.4 代码运行测试



3.8 删除pos节点or pos节点之后的节点🏓

 3.8.0 删除pos节点or pos节点之后的节点思路分析



3.8.1 SList.h

//删除pos节点
void SLErase(SlNode** pphead, SlNode* pos);

//删除pos节点之后的节点
void SLEraseAfter(SlNode* pos);

3.8.2 SList.c

//删除pos节点
void SLErase(SlNode** pphead, SlNode* pos)
{
	assert(pphead && *pphead && pos);
	//pos是第一个节点
	if (pos==(*pphead))
	{
		*pphead= (*pphead)->next;
		free(pos);
		return 1;
	}
	//pos不是第一个节点
	SlNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	prev->next = pos->next;
	free(pos);
	pos = NULL;//出于规范
}
//删除pos节点之后的节点
void SLEraseAfter(SlNode* pos)
{
	//尾节点不行,空指针也不行
	assert(pos&&pos->next);
	SlNode* del = pos->next;
	pos->next = del->next;
	free(del);
}

3.8.3 test.c

#include"SList.h"
void SLTest()
{
	//创建节点--->申请空间
	//存储有效数据
	SlNode* node1 = (SlNode*)malloc(sizeof(SlNode));
	node1->data = 1;
	SlNode* node2 = (SlNode*)malloc(sizeof(SlNode));
	node2->data = 2;
	SlNode* node3 = (SlNode*)malloc(sizeof(SlNode));
	node3->data = 3;
	SlNode* node4 = (SlNode*)malloc(sizeof(SlNode));
	node4->data = 4;
	SlNode* node5 = (SlNode*)malloc(sizeof(SlNode));
	node5->data = 5;
	//存储下一个节点的地址
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = node5;
	node5->next = NULL;//单向不带头不循环链表

	//打印
	SlNode* plist = node1;
	SLPrint(plist);
}
void SLTest01()
{
	SlNode* plist = NULL;
	//尾插
	SLPushBack(&plist, 1);
	SLPushBack(&plist, 2);
	SLPushBack(&plist, 3);
	SLPushBack(&plist, 4);
	SLPrint(plist);
	//头插
	SLPushFront(&plist, 5);
	SLPrint(plist);
	//尾删
	SLPopBack(&plist);
	SLPrint(plist);
	//头删
	SLPopFront(&plist);
	SLPrint(plist);
	//pos之前插入
	SlNode* find = SLFind(&plist, 2);
	//SLInsert(&plist, find, 6);
	//SLPrint(plist);
	pos之后插入
	//SlNode* find = SLFind(&plist, 3);
	//SLInsertAfter( find, 7);
	//SLPrint(plist);
	
	//删除pos节点
	/*SLErase(&plist, find);
	SLPrint(plist);*/

	//删除pos之后
	SLEraseAfter(find);
	SLPrint(plist);
}
int main()
{
	SLTest();
	SLTest01();
	return 0;
}

3.8.4 代码运行测试



3.9 销毁🌔

3.9.0 销毁思路分析


3.9.1 SList.h

//销毁
void SLDesTroy(SlNode** pphead);

3.9.2 SList.c

//销毁
void SLDesTroy(SlNode** pphead)
{
	assert(pphead);
	SlNode* pcur = *pphead;
	while (pcur)
		//注意:如果是pcur->next,那么循环将结束于尾节点没有free的时候
	{
		SlNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

3.9.3 test.c

#include"SList.h"
void SLTest()
{
	//创建节点--->申请空间
	//存储有效数据
	SlNode* node1 = (SlNode*)malloc(sizeof(SlNode));
	node1->data = 1;
	SlNode* node2 = (SlNode*)malloc(sizeof(SlNode));
	node2->data = 2;
	SlNode* node3 = (SlNode*)malloc(sizeof(SlNode));
	node3->data = 3;
	SlNode* node4 = (SlNode*)malloc(sizeof(SlNode));
	node4->data = 4;
	SlNode* node5 = (SlNode*)malloc(sizeof(SlNode));
	node5->data = 5;
	//存储下一个节点的地址
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = node5;
	node5->next = NULL;//单向不带头不循环链表

	//打印
	SlNode* plist = node1;
	SLPrint(plist);
}
void SLTest01()
{
	SlNode* plist = NULL;
	//尾插
	SLPushBack(&plist, 1);
	SLPushBack(&plist, 2);
	SLPushBack(&plist, 3);
	SLPushBack(&plist, 4);
	SLPrint(plist);
	//头插
	SLPushFront(&plist, 5);
	SLPrint(plist);
	//尾删
	SLPopBack(&plist);
	SLPrint(plist);
	//头删
	SLPopFront(&plist);
	SLPrint(plist);
	//pos之前插入
	SlNode* find = SLFind(&plist, 2);
	//SLInsert(&plist, find, 6);
	//SLPrint(plist);
	pos之后插入
	//SlNode* find = SLFind(&plist, 3);
	//SLInsertAfter( find, 7);
	//SLPrint(plist);
	
	//删除pos节点
	/*SLErase(&plist, find);
	SLPrint(plist);*/

	//删除pos之后
	SLEraseAfter(find);
	SLPrint(plist);
	//销毁
	SLDesTroy(&plist);
	SLPrint(plist);
}
int main()
{
	SLTest();
	SLTest01();
	return 0;
}

3.9.4 代码运行测试


本次的分享到这里就结束了!!!

PS:小江目前只是个新手小白。欢迎大家在评论区讨论哦!有问题也可以讨论的!

如果对你有帮助的话,记得点赞👍+收藏⭐️+关注➕

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

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

相关文章

Ubuntu更新镜像源切换

概述 用ubuntu用apt命令&#xff0c;自动安装或更新包的时候&#xff0c;默认的镜像源服务器非常卡&#xff0c;很不方便。切换到国内的镜像源&#xff0c;下载更新非常快。为防止以后忘记&#xff0c;本文以国内服务器阿里巴巴的为例简单描述。 版本 Ubuntu23.10 找到更新…

使用 类加载器 或者 类对象 读取文件(参考的路径都是编译以后的文件夹,out 或者 target 文件夹 )

以下内容 本人都是 用 Maven 工程总结的 &#xff0c;所以会和普通项目的项目目录不太一样。相对路径&#xff1a;项目 的 根目录 开始查找。&#xff08; 但是在我们真正开发的时候&#xff0c;我们读到的更多的文件并不是直接放在我们项目里面这个文件夹里面&#xff0c;而是…

OpenAI 现已开始考虑自研 AI 芯片战略

根据 TechCrunch 的报道&#xff0c;随着 AI 芯片短缺的问题日益严重&#xff0c;OpenAI 现已开始考虑自研 AI 芯片。 据悉&#xff0c;从去年开始 OpenAI 内部就已经开始讨论 AI 芯片战略&#xff0c;以解决其 AI 芯片短缺的问题。这些方案包括自研 AI 芯片、与英伟达等芯片制…

用节点亲和性把 Pod 分配到节点

用节点亲和性把 Pod 分配到节点 当前集群信息&#xff1a; rootk8s-master:~# kubectl get node -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME k8s…

宝塔部署code-server

大家好&#xff0c;我叫徐锦桐&#xff0c;个人博客地址为www.xujintong.com。平时记录一下学习计算机过程中获取的知识&#xff0c;还有日常折腾的经验&#xff0c;欢迎大家来访。 code-server其实就是vscode网页版&#xff0c;可以实现随时随地编程。那么本教程是将源码的二进…

理解电路:从电报机到门电路,我们如何做到“千里传信”?

目录 背景 从信使到电报&#xff0c;我们怎么做到“千里传书”&#xff1f; 理解继电器&#xff0c;给跑不动的信号续一秒 小结 背景 所有最终执行的程序其实都是使用“0”和“1”这样的二进制代码来表示的。我们知道&#xff0c;对应的整数和字符串&#xff0c;其实也是用…

2023 年和 2024 年 10 个最佳加密货币趋势

1.熊市低迷 加密货币市场已进入持续数月的长期看跌阶段。尽管 2023 年初出现了一些看涨走势&#xff0c;但大多数领先的加密货币随后都出现了看跌低迷&#xff0c;导致其市值大幅下跌。 此外&#xff0c;持续的熊市可归因于一系列因素&#xff0c;包括宏观经济不确定性、利率…

复杂系统设计基本注意事项

目录 一、软件复杂性度量方法 &#xff08;一&#xff09;McCabe度量方法 &#xff08;二&#xff09;John Ousterhout度量方法 &#xff08;三&#xff09;一般建议 二、复杂性带来的危害 &#xff08;一&#xff09;修改扩散&#xff08;Modification Diffusion&#x…

力扣每日一题54:螺旋矩阵

题目描述&#xff1a; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5]示例 2&#xff1a; 输入&#…

电路电子技术4 等效电阻的计算实际电源等效变换

1.等效电阻的计算 思路&#xff1a;清楚电路结构即可。可以看到&#xff08;R1//R2&#xff09;&#xff08;R3//R4&#xff09;。 这样即可得到答案C。 2.电流源等效电压源 实际电压源等效为实际电流源时&#xff0c;电流源的电激流应等于电压源的源电源除以电压源的内阻。 实…

django基于Python的房价预测系统+爬虫+大屏可视化分析

欢迎大家点赞、收藏、关注、评论 文章目录 前言一、项目介绍二、开发环境三、功能需求分析1 数据采集功能设计2数据管理功能设计3爬虫功能需求分析4 数据可视化功能需求分析数据库表的设计 四、核心代码五、效果图六、文章目录 前言 房价是一个国家经济水平的重要体现&#xff…

JS加密/解密之闭包的运用

深入探讨JavaScript闭包的演变与应用 摘要&#xff1a; 本文将深入探讨JavaScript闭包的概念、特性以及其在实际开发中的应用。我们将从闭包的起源开始&#xff0c;探讨它在JavaScript编程中的重要性&#xff0c;并通过实例展示闭包在不同场景下的灵活应用。 引言 JavaScrip…

2005.6-2018.6月中国企业OFDI微观数据

2005.6-2018.6月中国企业OFDI微观数据 1、时间&#xff1a;2005.6-2018.6 2、范围&#xff1a;公司 3、指标&#xff1a;Year、Month、Chinese Entity、 Quantity in Millions 、Share size、Transaction Party、Sector、Subsector、Country、Region、BRI 4、数据解释&…

矩阵的转置c++

大家好&#xff0c;我叫徐锦桐&#xff0c;个人博客地址为www.xujintong.com。平时记录一下学习计算机过程中获取的知识&#xff0c;还有日常折腾的经验&#xff0c;欢迎大家来访。 介绍 由下面的图片可以看出&#xff0c;从左上角到右上角的那条斜线是分界线&#xff08;这条…

微信小程序之微信授权登入及授权的流程讲解

目录 一、流程讲解 1. 图解 2. 讲解 二、官方登入 wxLogin wx.getUserProfile 代码 三、数据交互授权登入 1. 前端 2. 后端代码 一、流程讲解 1. 图解 2. 讲解 这张图片是关于微信小程序授权登录的流程图。流程图展示了使用微信官方提供的登录能力来获取用户身份标识…

再也不被时间束缚:C++ stdchrono时间库全面解析

C stdchrono时间库全面解析 一、引言二、C std::chrono时间库概述2.1、std::chrono命名空间的作用和用途2.2、基本组成部分&#xff1a;duration、time_point和clock 三、duration的使用详解3.1、duration表示时间段的概念和使用方法3.2、duration的各种单位和精度选项3.3、使用…

使用c++实现简易线程池

线程池其实就是一堆处理任务的线程和 一个任务队列 &#xff0c;处理线程不断地从这个任务队列中拿出任务进行处理。 不过需要注意的是 对于这个任务队列需要保证线程安全 一个简易的线程池需要 1&#xff0c;一个向任务队列中添加任务的接口 2&#xff0c;一个从任务队列中取…

Zabbix告警与飞书集成

一、配置媒介 1、下载飞书的Zabbix媒介类型如下&#xff1a; zbx_export_mediatype_feishu.xml 2、Zabbix中导入媒介类型 Zabbix Web中选择管理 > 报警媒介&#xff0c;然后导入该媒介类型。导入规则选择“更新现有的”和“创建新的”。 3、配置飞书媒介类型用户 Zabbi…

【游记】CSP2023-S2

本来不像另起一篇的&#xff0c;但是hb要求了还是写一下 游记 考前 考场电脑好迷你&#xff0c;我来的早是第一个入场的&#xff0c;抹了点清凉油无聊一直在用手量设备的尺寸 开考前十分钟左右就下发文件了&#xff0c;题面密码还没有公布&#xff0c;但是大样例已经可以看…

uCOSIII实时操作系统 十 事件标志组

目录 事件标志组&#xff1a; 事件标志组API函数&#xff1a; 创建事件标志组&#xff1a; 等待事件标志组&#xff1a; 向事件标志组发送标志&#xff1a; 事件标志组实验&#xff1a; 事件标志组&#xff1a; 有时候一个任务可能需要和多个事件同步这个时候就需要使用事…