【数据结构】单向链表实现 超详细

news2024/11/17 21:25:02

目录

一. 单链表的实现

1.准备工作及其注意事项

1.1 先创建三个文件

1.2 注意事项:帮助高效记忆和理解

2.链表的基本功能接口

2.0 创建一个 链表

2.1 链表的打印

 3.链表的创建新节点接口

4.链表的节点插入功能接口

4.1 尾插接口

4.2 头插接口  

  4.3 指定位置 pos 之前 插入接口

 4.4 指定位置pos 之后 插入接口(推荐)

5.链表表的删除功能接口

5.1 尾删接口

5.2头删接口

5.3 删除 指定位置 pos 节点 接口

5.4 删除  指定位置 pos ==之后== 的一个 节点 接口

6.链表的  查找  接口

7.链表的  销毁  接口

二、总代码

SList.h

SList.c

test.c


前言:(受篇幅限制,为了划清知识模块,进行分章节讲解)

若想了解清楚 链表的概念和分类 

可以点击跳转 这一章节----> :【数据结构】链表的概念 及 分类 (使用比喻解释概念)


一. 单链表的实现

1.准备工作及其注意事项
1.1 先创建三个文件

 解释这三个文件的作用
 1、头文件SList.h  是来声明接口函数,定义链表,将几个公共用到的库函数集合起来
 2、源文件SList.c  是用来具体实现接口
 3、源文件test.c  用于接口的测试工作 ,即具体的使用场景

1.2 注意事项:帮助高效记忆和理解

1. 但凡是删除,必须 断言 链表不能为 空,避免传过来的是NULL指针 assert(*pphead);
2. 传递二级指针,要断言 不能为 NULL ,指针不能为空:assert(pphead);
3. 指定位置 pos 时,要确保pos存在:assert(pos);
4. (pphead)->next;  解引用前一定要加 括号,* 号 优先级 < 箭头操作符
5. 链表的所有插入接口:链表为空: 没有节点 就直接插入
6.要找 前一个节点 prev 或 后一个节点 next 时, 一定要确保 其本身存在!!!!
7.当指定位置 pos 刚好是 头节点时 就没有 prev 了

2.链表的基本功能接口
2.0 创建一个 链表
// 创建链表节点结构体
// 和顺序表创建原理相同,可以看我的 【顺序表】章节
typedef  int  SLDataType;
typedef struct SListNode
{
	SLDataType data;
	struct SListNode* next;
}SLTNode;
2.1 链表的打印
// 打印函数
//注意这里的 phead 仅表示单向链表传递过来的 第一个节点地址,不是 双向链表的带头节点 
void SLTPrint(SLTNode* phead)
{
	SLTNode* ptemp = phead;
	while (ptemp) // ptemp != NULL 说明为是有效的节点,则循环打印
	{
		printf("%d -> ", ptemp->data);
		ptemp = ptemp->next; // 更新 ptemp :保存下个节点的地址:遍历节点的关键
	}
	printf("NULL\n");
}
 3.链表的创建新节点接口
// 创建新节点函数:所有的插入接口,都需要 创建新节点
SLTNode* STLCreatNode(SLDataType x)
{
	// 先创建 一个 新节点
	SLTNode* newNode = (SLTNode*)malloc(sizeof(SLTNode));
	newNode->data = x;
	newNode->next = NULL;
	return newNode;
}
4.链表的节点插入功能接口
4.1 尾插接口

链表的尾插法
几种情况
1、链表非空:先找到尾节点,然后直接将尾节点 的 next 指向 新节点,(形成链接), 新节点 则 指向 NULL 变成 新的尾节点
2、链表为空:将头指针phead更新 成 新插入节点的地址,然后新节点 next 指向 NULL

// 注意:plist 头指针是 时刻更新为了指向头节点,当创建新的头节点后,要更新 plist ,而若要真正改变 plist 的值,需要传地址
// 传递过来的 头指针 &plist 是 一级指针 plist 的地址,要用 二级指针 pphead 来接收 ; 而 *pphead == plist 
// void SLTPushBack(SLTNode* phead, SLDataType x) // 错误写法:传值

void SLTPushBack(SLTNode** pphead, SLDataType x)
{
	assert(pphead); // 传递过来的 一级指针的地址 二级指针 不能为 NULL
	// 先创建 一个 新节点
	SLTNode* newNode = STLCreatNode(x);

	// 1、链表为空
	if (*pphead == NULL)
	{
		*pphead = newNode;
		return;
	}

	// 2、链表非空
	SLTNode* ptail = *pphead; // 因为要找 尾节点:干脆命名为 tail
	//本质是:找到尾节点的地址,而不是 尾节点的 next
	while (ptail->next) 
	{
		ptail = ptail->next;
	}
	ptail->next = newNode;
}

4.2 头插接口  

void SLTPushFront(SLTNode** pphead, SLDataType x)
{
	assert(pphead); // 传递过来的 一级指针的地址 二级指针 不能为 NULL
	// 先创建 一个 新节点
	SLTNode* newNode = STLCreatNode(x);

	newNode->next = *pphead; // 先将原本的 头指针放在 新节点的next
	*pphead = newNode; // 更新 头指针
}

  4.3 指定位置 pos 之前 插入接口

// 在指定位置节点pos 之前插入数据 
// 思路:找三个节点 :prev     newNode      next 
//                  前      本身新节点     后         为了找到 地址 才能将三者链接起来
// 注意:要找 前一个节点 prev 时, 一定要确保 其本身存在!!! 
// 当 pos 刚好是 头节点时 就没有 prev 了,特殊情况, 否则会因为找不到prev而 程序奔溃
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLDataType x)
{
	assert(pphead); // 指针不能为空
	assert(pos); // pos 不能为空
	assert(*pphead); // 链表不能为空: pos 是链表中 的一个有效节点,pos 不为空,链表也不能为 空

	// 创建新节点
	SLTNode* newNode = STLCreatNode(x);
	if (*pphead == pos)
	{
		// 当 pos 刚好是 头节点时 就用 头插法:调用之前写的函数接口
		SLTPushFront(pphead, x);
		return;
	}
	SLTNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	// 三者关联起来:  prev -> newNode -> pos
	newNode->next = pos;
	prev->next = newNode;
}
 4.4 指定位置pos 之后 插入接口(推荐)

// 在指定位置节点pos 之后插入数据: 注意一下错误写法: 和正确写法刚好相反
// 特点:有了 pos 就不需要 头节点了!!
void SLTInsertAfter(SLTNode*pos, SLDataType x)
{
	assert(pos); // pos 不能为空
	// 创建新节点
	SLTNode* newNode = STLCreatNode(x);
	newNode->next = pos->next;
	pos->next = newNode;
}
5.链表表的删除功能接口
5.1 尾删接口

// 链表的尾删法
// 思路:删除尾节点 以及  前一个节点 pre 的next 要置为 NULL
// 要注意 只有一个节点时,没有前置节点 pre!!!!
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead); // 一级指针为plist 指向头节点,传递过来的 一级指针的地址二级指针不能为 NULL
	assert(*pphead); // 一级指针为plist 指向头节点, *pphead == plist 这个指针也不能为 NULL 不能为空链表

	// 链表非空
	// 链表只有一个节点时
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
		return;
	}
	// 链表有多个节点
	SLTNode* ptail = *pphead;
	SLTNode* prev = NULL; // 时刻更新保存 
	while(ptail->next)
	{ 
		prev = ptail;
		ptail = ptail->next;
	}
	prev->next = NULL;
	free(ptail);
	ptail = NULL;
}
5.2头删接口

// 链表的头删法
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead); // 指针不能为空
	assert(*pphead); // 链表不能为空
	// 让第二个节点成为新的头节点
	// 将 旧的节点释放掉: 注意 要先将 第二个节点的地址  (*pphead) -> next  临时储存起来!!
	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}
5.3 删除 指定位置 pos 节点 接口
// 删除pos 节点
// 删除 pos 节点后,还要 将 prev 和 next (pos的前后两个节点) 链接上!!: 比较麻烦
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead); // 指针不能为空
	assert(pos); // pos 不能为空
	assert(*pphead); // 链表不能为空: pos 是链表中 的一个有效节点,pos 不为空,链表也不能为 空

	//先 让 prev 链接上 next,后 free 释放掉 pos
	// 遇到 需要找 prev 的,一定要 检查是否存在 prev
	if (*pphead == pos)//检查是否存在 prev
	{
		free(pos);
		*pphead = NULL;
		return;
	}
	SLTNode* prev = *pphead;
	while (prev->next != pos) // 找 前面节点 prev
	{
		prev = prev->next;
	}
	prev->next = pos->next; // 先赋值后 再free释放
	free(pos);
	pos = NULL;
}
 5.4 删除  指定位置 pos ==之后== 的一个 节点 接口

// 删除pos 之后的节点
// 直接 删除 pos 之后的 节点 pos->next  
// 先让 pos 和 pos -> next -> next 链接起来,后 删除 节点 pos -> next 
// 注意:像这类找 上一个节点 prev 或 找下一个节点 next :都需要 检查 是否存在 该节点
void SLTEraseBeind(SLTNode* pos)
{
	assert(pos); // pos 不能为空
	assert(pos->next); // 这个节点必须存在,否则该函数无意义! 链表至少要有两个节点
	 // 三者的关联关系:pos    pos->next    pos->next->next
	 // 注意:下面 先 pos->next = pos->next->next, 后 free(pos->next) 是不对的  
     // pos->next 已经更新,不是你所认为的原来的那个 中间节点了,因此要先 临时保存起来!!!
	SLTNode* temp = pos->next;
	pos->next = pos->next->next;
	free(temp);
	temp = NULL;
}
 6.链表的  查找  接口
// 链表的查找
SLTNode* SLTFind(SLTNode** pphead, SLDataType x)
{
	// 遍历链表
	assert(pphead); // 指针不能为空
	SLTNode* ptemp = *pphead;
	while (ptemp)
	{
		if (ptemp->data == x) return ptemp; // 找到了就返回节点
		ptemp = ptemp->next;
	}
	// 没找到
	return NULL;
}
7.链表的  销毁  接口
// 销毁链表
// 一旦涉及到 动态内存申请,不要忘记销毁
void SListDestory(SLTNode** pphead)
{
	assert(pphead); // 指针不能为空
	assert(*pphead); // 链表不能为空,空的没必要销毁了
	// 顺序表是一段连续的空间,可以执行一次free全部销毁,而链表节点是独立的,需要遍历节点一个一个销毁
	 // 不能直接 一个一个 free 下去,需要 保存 next 节点,才能找到下个节点!!!!
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	// 当所有节点销毁后,需要 将头指针 销毁
	*pphead = NULL;
}

二、总代码

SList.h

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

// 零、创建链表节点
typedef int SLDataType;
typedef struct SListNode
{
	SLDataType data;
	struct SListNode* next;
}SLTNode;

// 一、打印函数: 这里用传址
void SLTPrint(SLTNode* ps);

// 二、尾插法
void SLTPushBack(SLTNode** pphead, SLDataType x);

// 三、头插法
void SLTPushFront(SLTNode** pphead, SLDataType x);

// 四、尾删法
void SLTPopBack(SLTNode** pphead);

// 五、头删法
void SLTPopFront(SLTNode** pphead);

// 六、链表的查找
SLTNode* SLTFind(SLTNode** pphead, SLDataType x);

// 七、指定位置 pos 之前插入
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLDataType x);

// 八、指定位置 pos 之后 插入
void SLTInsertAfter(SLTNode* pos, SLDataType x);

// 九、删除 指定 pos 节点
void SLTErase(SLTNode** pphead, SLTNode* pos);

// 十、删除指定 pos 之后 的节点
void SLTEraseAfter(SLTNode* pos);

// 十一、销毁链表
void SLTDestory(SLTNode** pphead);

SList.c

#include"SList.h"

// 一、打印函数: 这里用传址
void SLTPrint(SLTNode* phead)
{
	SLTNode* ptemp = phead;
	while (ptemp) //  ptemp != NULL 表示为有效节点 
	{
		printf("%d -> ", ptemp->data);
		ptemp = ptemp->next;
	}
	printf("NULL\n");
}

// 创建节点函数
SLTNode* SLTCreatNode(SLDataType x)
{
	SLTNode* newNode = (SLTNode*)malloc(sizeof(SLTNode));
	newNode->data = x;
	newNode->next = NULL;
	return newNode;
}
// 二、尾插法
void SLTPushBack(SLTNode** pphead, SLDataType x)
{
	assert(pphead);
	// 创建新节点
	SLTNode* newNode = SLTCreatNode(x);
	// 链表为空: 没有节点 就直接插入
	if (*pphead == NULL)
	{
		*pphead = newNode;
		return;
	}
	// 链表非空:找尾节点
	SLTNode* ptail = *pphead;
	while (ptail->next)
	{
		ptail = ptail->next;
	}
	ptail->next = newNode;
}

// 三、头插法
void SLTPushFront(SLTNode** pphead, SLDataType x)
{
	assert(pphead);
	// 创建新节点
	SLTNode* newNode = SLTCreatNode(x);
	// 先 链接 第一个节点,  没有第一个节点就是 NULL,也可以直接给 newNode->next,后更新 *pphead
	newNode->next = *pphead;
	*pphead = newNode;
}

// 四、尾删法
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	// 先找尾节点 和 前置节点 prev,后删除+链接
	// 当只有一个 节点时
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
		return;
	}
	// 当有 两个 节点 及以上
	SLTNode* ptail = *pphead;
	SLTNode* prev = NULL;
	while (ptail->next)
	{
		prev = ptail;
		ptail = ptail->next;
	}
	prev->next = NULL;
	free(ptail);
	ptail = NULL;
}

// 五、头删法
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	// 让 *pphead 指向第二个节点,free 掉第一个
	SLTNode* next = (*pphead)->next; // 一定要加 括号,* 号 优先级 < 箭头操作符 
	free(*pphead);
	*pphead = next;
}

// 六、链表的查找
SLTNode* SLTFind(SLTNode** pphead, SLDataType x)
{
	assert(pphead);
	// 遍历
	SLTNode* ptemp = *pphead;
	while (ptemp)
	{
		if (ptemp->data == x) return ptemp;
		ptemp = ptemp->next;
	}
	return NULL;
}

// 七、指定位置 pos 之前插入
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLDataType x)
{
	assert(pphead);
	assert(pos);
	assert(*pphead);
	// 涉及到三个节点: prev    newNode   pos
	// 创建新节点
	SLTNode* newNode = SLTCreatNode(x);
	if (*pphead == pos)// 无 prev 的情况
	{
		SLTPushFront(pphead, x);
		return;
	}
	SLTNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	newNode->next = pos;
	prev->next = newNode;
}

// 八、指定位置 pos 之后 插入(推荐!)
void SLTInsertAfter(SLTNode* pos, SLDataType x)
{
	assert(pos);
	// 创建新节点
	SLTNode* newNode = SLTCreatNode(x);
	newNode->next = pos->next;
	pos->next = newNode;
}

// 九、删除 指定 pos 节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);
	assert(*pphead);
	// 关系三个节点:prev    pos    next
	// 先找 prev
	SLTNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	prev->next = pos->next;
	free(pos);
	pos = NULL;
}

// 十、删除指定 pos 之后 的节点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next); // 注意  pos->next 这个必须存在
	// 关系三个节点: pos      pos->next     pos->next->next
	// 另一种可能:     pos      pos->next     NULL
	if (pos->next->next == NULL)
	{
		free(pos->next);
		pos->next = NULL;
		return;
	}
	// 直接销毁  pos->next  会找不到 pos->next->next,先保存
	SLTNode* ptemp = pos->next->next;
	free(pos->next);
	pos->next = NULL;
	pos->next = ptemp;
}

// 十一、销毁链表
void SLTDestory(SLTNode** pphead)
{
	assert(pphead);
	// 遍历销毁
	if (*pphead == NULL)return;
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	// 别忘了将 头指针销毁!!!
	*pphead = NULL;
}

test.c

#include"SList.h"

void SLTest1()
{
	// 零、创建 链表
	SLTNode* plist = NULL;

	// 二、尾插法
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4); // 1 -> 2 -> 3 -> 4 -> NULL
	printf("测试尾插:");
	SLTPrint(plist);

	// 三、头插法
	SLTPushFront(&plist, 5);
	SLTPushFront(&plist, 6); // 6 -> 5 -> 1 -> 2 -> 3 -> 4 -> NULL
	printf("测试头插:");
	SLTPrint(plist);

	// 四、尾删法
	SLTPopBack(&plist);
	SLTPopBack(&plist); // 6 -> 5 -> 1 -> 2 -> NULL
	printf("测试尾删:");
	SLTPrint(plist);

	// 五、头删法
	SLTPopFront(&plist);
	SLTPopFront(&plist); // 1 -> 2 -> NULL
	printf("测试头删:");
	SLTPrint(plist);

	// 六、链表的查找
	SLTNode* FindRet = SLTFind(&plist, 2);
	printf("测试查找:");
	if (FindRet) printf("找到了\n");
	else printf("没找到\n");

	// 七、指定位置 pos 之前插入
	SLTNode* FindRet1 = SLTFind(&plist, 2);
	SLTNode* FindRet2 = SLTFind(&plist, 1);
	SLTInsert(&plist, FindRet1, 200);
	SLTInsert(&plist, FindRet2, 100);// 100 -> 1 -> 200 -> 2 -> NULL
	printf("测试指定位置之前插入:");
	SLTPrint(plist);

	// 八、指定位置 pos 之后 插入(推荐!)
	SLTNode* FindRet3 = SLTFind(&plist, 2);
	SLTInsertAfter(FindRet3, 200); // 100 -> 1 -> 200 -> 2 -> 200 -> NULL
	printf("测试指定位置之后插入:");
	SLTPrint(plist);

	// 九、删除 指定 pos 节点
	SLTNode* FindRet4 = SLTFind(&plist, 1);
	SLTErase(&plist, FindRet4);// 100 -> 200 -> 2 -> 200 -> NULL
	printf("测试删除指定节点:");  
	SLTPrint(plist);

	// 十、删除指定 pos 之后 的节点
	SLTNode* FindRet5 = SLTFind(&plist, 200); // 注意如果 通过 Find 函数 找 节点,节点中有重复数据,返回 第一个遇到的
	SLTEraseAfter(FindRet5);// 100 -> 200 -> 200 -> NULL
	printf("测试删除指定节点:"); 
	SLTPrint(plist);

	//
}
int main()
{
	SLTest1();
	return 0;
}

完。

若上述文章有什么错误,欢迎各位大佬及时指出,我们共同进步!

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

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

相关文章

Jupyter Notebook中的%matplotlib inline详解

Jupyter Notebook中的%matplotlib inline详解 &#x1f335;文章目录&#x1f335; &#x1f333;引言&#x1f333;&#x1f333;什么是魔术命令&#x1f333;&#x1f333;%matplotlib inline详解&#x1f333;(&#x1f448;直入主题请点击)&#x1f333;小结&#x1f333;&…

华为FreeClip耳机可以调节音量大小吗?附教程!

不会只有我一个人吧&#xff1f;都用华为FreeClip耳机一段时间了&#xff0c;才发现它竟然不支持在耳机上直接调节音量&#xff0c;也是没谁了&#xff01;但是后来自己摸索了一下&#xff0c;发现了华为FreeClip耳机原来是几个简单有效的调节音量大小的方法滴~不得不说&#x…

0202-1-处理机调度与死锁

第三章:处理机调度与死锁 处理机调度算法的目标 处理机调度算法的共同目标 资源利用率:CPU的利用率CPU有效工作时间/(CPU有效工作时间CPU空闲等待时间)公平性平衡性策略强制执行 批处理系统的目标 平均周转时间短系统吞吐量高处理机利用率高 分时系统的目标 响应时间快均…

LeetCode:141和142,环形链表之追及相遇和快慢指针的运用

这两个题是相关联的&#xff0c;主要做法为哈希和快慢指针&#xff0c;当然像博主我&#xff0c;不看解析只会O&#xff08;n^2&#xff09;的暴力遍历&#xff0c;太惨了&#xff0c;不过&#xff0c;快慢指针还是很好理解的&#xff0c;是一个追及的问题&#xff0c; 目录 …

半桥式三相无刷直流电动机不同导通角的性能的变化

半桥式三相无刷直流电动机不同导通角的性能的变化 syms Omega clear clcOmega0pi/180*120 for Omega_x[pi/180*120,pi/180*130,pi/180*140,pi/180*150,pi/180*160,pi/180*170,pi/180*180]Omega_x*180/piOmega_x_0 (4*sin(Omega_x/2)/(Omega_xsin(Omega_x)))/(4*sin(Omega0/2)/…

Javaweb之SpringBootWeb案例之yml配置文件的详细解析

4.2 yml配置文件 前面我们一直使用springboot项目创建完毕后自带的application.properties进行属性的配置&#xff0c;那其实呢&#xff0c;在springboot项目当中是支持多种配置方式的&#xff0c;除了支持properties配置文件以外&#xff0c;还支持另外一种类型的配置文件&am…

了解UDP发送过快导致的问题和对应解决方案

在当今这个以数据为核心的时代&#xff0c;企业对于数据传输的速度和稳定性有着日益增长的需求。UDP凭借其低延迟和高效率的特性&#xff0c;在实时通信和大规模数据传输领域扮演着关键角色。然而&#xff0c;UDP的无连接特性和缺乏可靠性也给数据传输带来了挑战&#xff0c;尤…

Docker极速入门掌握基本概念和用法

1、Docker概念 1.1什么是docker Docker是一个快速交付应用、运行应用的技术&#xff0c;具备以下优势 可将程序及其依赖、运行环境一起打包为一个镜像&#xff0c;可以迁移到任意Linux操作系统运行时利用沙箱机制形成隔离容器&#xff0c;各个应用互不干扰启动、移除都可以通…

【Springcloud篇】学习笔记一(一至三章):微服务介绍、构建环境

零基础微服务架构理论入门介绍 一个基于分布式的服务架构应该含有的架构内容如下&#xff1a; 1.1SpringCloud是什么 1.2基于微服务的系统 1.3服务与之对用的技术 1.4课程目录 第一章_SpringBoot和SpringCloud版本选择 详细可见SpringCloud2020.mmap文件 1.概述 2.SpringBoo…

Fashion MNIST数据集介绍及基于Pytorch下载数据集

Fashion MNIST数据集介绍及基于Pytorch下载数据集 &#x1f335;文章目录&#x1f335; &#x1f333;引言&#x1f333;&#x1f333;Fashion MNIST数据集简介&#x1f333;Fashion MNIST数据集的类别说明Fashion MNIST数据集图片示例 &#x1f333;基于PyTorch下载Fashion MN…

ElasticSearch-SpringBoot整合ElasticSearch

六、SpringBoot整合ElasticSearch 1、浏览官方文档 1、查找跟ES客户端相关的文档 使用Java REST Client 选择Java Hight Level REST Client 2、创建项目的准备 1.找到原生的依赖 2.找到对象 3.分析这个类里面的方法 3、正式创建项目 1.创建工程 2.导入依赖 注意依赖版本…

如何使用本地私有NuGet服务器

写在前面 上一篇介绍了如何在本地搭建一个NuGet服务器&#xff0c; 本文将介绍如何使用本地私有NuGet服务器。 操作步骤 1.新建一个.Net类库项目 2.打包类库 操作后会生成一个.nupkg文件&#xff0c;当然也可以用dotnet pack命令来执行打包。 3.推送至本地NuGet服务器 打开命…

RISC-V指令格式

RISC-V指令格式 1 RISC-V指令集命名规范2 RISC-V指令集组成2.1 基础整数指令集2.2 扩展指令集 3 RISC-V指令格式3.1 指令表述3.2 指令格式 本文属于《 RISC-V指令集基础系列教程》之一&#xff0c;欢迎查看其它文章。 1 RISC-V指令集命名规范 前面提到过RV32I&#xff0c;这是…

C#,哥伦布数(Golomb Number)的算法与源代码

1 哥伦布数&#xff08;Golomb Number&#xff09; 哥伦布数&#xff08;Golomb Number&#xff09;是一个自然数的非减量序列&#xff0c;使得n在序列中正好出现G&#xff08;n&#xff09;次。前几个15的G&#xff08;n&#xff09;值为&#xff1a;1 2 2 3 3 4 4 4 5 5 5 6…

【深度学习】基于PyTorch架构神经网络学习总结(基础概念基本网络搭建)

神经网络整体架构 类似于人体的神经元 神经网络工作原来为层次结构&#xff0c;一层一层的变换数据。如上述示例有4层&#xff0c;1层输入层、2层隐藏层、1层输出层神经元&#xff1a;数据的量或矩阵的大小&#xff0c;如上述示例中输入层中有三个神经元代表输入数据有3个特征…

网络异常案例四_IP异常

问题现象 终端设备离线&#xff0c;现场根据设备ip&#xff0c;ping不通。查看路由器。 同一个路由器显示的终端设备&#xff08;走同一个wifi模块接入&#xff09;&#xff0c;包含不同网段的ip。 现场是基于三层的无线漫游&#xff0c;多个路由器wifi配置了相同的ssid信息&a…

SpringBoot+Vue实现各种文件预览(附源码)

&#x1f468;‍&#x1f4bb;作者简介&#xff1a;在笑大学牲 &#x1f39f;️个人主页&#xff1a;无所谓^_^ ps&#xff1a;点赞是免费的&#xff0c;却可以让写博客的作者开心好几天&#x1f60e; 项目运行效果 前言 在做项目时&#xff0c;文件的上传和预览必不可少。继上…

国标GB/T 28181详解:GB/T28181状态信息报送流程

目 录 一、状态信息报送 二、状态信息报送的基本要求 三、命令流程 1、流程图 2、流程描述 四、协议接口 五、产品说明 六、状态信息报送的作用 七、参考 在国标GBT28181中&#xff0c;定义了状态信息报送的流程&#xff0c;当源设备(包括网关、SIP 设备、SIP 客…

面试经典150题 -- 区间(总结)

总的链接 : 面试经典 150 题 - 学习计划 - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台最经典 150 题&#xff0c;掌握面试所有知识点https://leetcode.cn/studyplan/top-interview-150/ 228 汇总区间 直接用双指针模拟即可 ; class Solution { public…

华为数通方向HCIP-DataCom H12-821题库(单选题:401-420)

第401题 R1的配置如图所示,此时在R1查看FIB表时,关于目的网段192.168.1.0/24的下跳是以下哪一项? A、10.0.23.3 B、10.0.12.2 C、10.0.23.2 D、10.0.12.1 【答案】A 【答案解析】 该题目考查的是路由的递归查询和 RIB 以及 FIB 的关系。在 RIB 中,静态路由写的是什么,下…