【数据结构】第三站:单链表
目录
一、顺序表的缺陷
二、链表
1.链表的概念以及结构
2.链表的分类
3.单链表的逻辑结构与物理结构
三、单链表的实现
1.单链表的定义
2.单链表的接口定义
3.单链表的接口实现
四、单链表的实现完整代码
一、顺序表的缺陷
在上一篇文章中,我们了解了顺序表的结构以及他的接口的实现。但同时我们也发现了他的一些缺陷
问题:
1. 中间/头部的插入删除,时间复杂度为O(N)
2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
思考:如何解决以上问题呢?下面给出了链表的结构来看看
二、链表
1.链表的概念以及结构
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
2.链表的分类
链表一共有八种类型,他们可由是单向还是双向,是循环还是非循环,是带头结点还是不带头结点进行排列组合出八种结构
虽然有很多种结构,但是只有两种最为常用
无头单向非循环链表和带头双向循环链表
这里我们先只需要了解无头单向非循环链表,其他链表后续了解
3.单链表的逻辑结构与物理结构
如下图所示,是链表的实际的物理结构与逻辑结构。物理结构就是实实在在数据在内存中的变化,逻辑结构就是为了方便理解,形象化出来的
三、单链表的实现
1.单链表的定义
typedef int SLTDateType;typedef struct SListNode {SLTDateType data;struct SListNode* next; }SListNode;
如上代码所示,单链表有数据域和指针域两部分组成,指针是用于指向下一个结点的指针
2.单链表的接口定义
//单链表的打印 void SListPrint(SListNode* plist); //单链表的尾插 void SListPushBack(SListNode** pplist, SLTDateType x); //单链表的头插 void SListPushFront(SListNode** pplist, SLTDateType x); //单链表的尾删 void SListPopBack(SListNode** pplist); //单链表的头删 void SListPopFront(SListNode** pplist); //单链表的查找 SListNode* SListFind(SListNode* plist,SLTDateType x); //单链表在pos位置之后插入 void SListInsertAfter(SListNode* pos, SLTDateType x); //单链表在pos位置之前插入 void SListInsertPrev(SListNode** pplist, SListNode* pos, SLTDateType x); //单链表在pos之后删除 void SListEraseAfter(SListNode* pos); //单链表在pos之前删除 void SListErasePrev(SListNode** pplist, SListNode* pos); //单链表在pos位置删除 void SListErase(SListNode** pplist, SListNode* pos); //单链表的销毁 void SListDestroy(SListNode** pplist);
如上代码所示,是我们的单链表需要实现的接口,对于链表和顺序表一样都是为了实现数据的管理,区别就是前者是离散的,后者是连续的。我们的目的还是增删查改
3.单链表的接口实现
1.单链表的打印
//单链表的打印 void SListPrint(SListNode* plist) {SListNode* cur = plist;while (cur != NULL){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n"); }
我们先来完成单链表的打印,对于单链表的打印,还是比较简单的,只需要先将头结点的指针给保存下来,然后依次去遍历单链表即可
2.单链表的尾插以及获取结点函数
//获取一个结点 SListNode* BuySListNode(SLTDateType x) {SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));if (tmp == NULL){perror("malloc fail");return;}tmp->next = NULL;tmp->data = x;return tmp; }//单链表的尾插 void SListPushBack(SListNode** pplist, SLTDateType x) {assert(pplist);SListNode* newnode = BuySListNode(x);if (*pplist == NULL){*pplist = newnode;return;}SListNode* tail = (*pplist);while (tail->next != NULL){tail = tail->next;}tail->next = newnode; }
对于单链表的尾插,我们要特别注意了。pplist是单链表头结点的地址,所以一定不为空
首先是获取结点,我们为了方便,先直接将其封装为一个函数。
有了结点了,那么我们还要思考如何尾插,那么我们先完成一般情况,假设已经有了一个很长的单链表了,我们还想要继续尾插一个值,那么只需要先找到原来的尾结点,然后将尾结点和新结点进行链接即可
当然还是存在一些特殊情况的,比如说原来的单链表压根就没有尾结点,也就是说链表是空的,那么上面的一般方法肯定行不通,这里其实就需要特殊处理一下,直接将新节点和链表头链接起来即可
3.单链表的头插
//单链表的头插 void SListPushFront(SListNode** pplist, SLTDateType x) {assert(pplist);SListNode* newnode = BuySListNode(x);SListNode* first = *pplist;*pplist = newnode;newnode->next = first; }
对于单链表的头插,就比较简单了,我们直接创建一个新结点,然后记录下原来的第一个结点的地址,然后让链表头与新节点链接起来,然后新节点与原来的第一个结点链接起来,这里我们会发下,其实是不需要处理空链表的情况的,这里体现了单链表适合头插
4.单链表的尾删
//单链表的尾删 void SListPopBack(SListNode** pplist) {assert(pplist);assert(*pplist);if ((*pplist)->next == NULL){free(*pplist);*pplist = NULL;}else{SListNode* tail = *pplist;while (tail->next->next != NULL){tail = tail->next;}free(tail->next);tail->next = NULL;} }
对于单链表的尾删,我们要想清楚了,首先是一般情况,当链表很长的时候,我们想要删除最后一个结点,那么得先找到前一个结点,然后释放最后一个结点,最后让前一个结点指向空。
我们还需要注意链表为空的状态,这个肯定是不可以删除的,所以我们直接断言掉。
然后是链表为一个结点的情况,如果链表只有一个结点,那么我们会发现,压根找不到前一个结点,所以我们也特殊处理,我们直接释放掉第一个结点,然后置空即可。
5.单链表的头删
//单链表的头删 void SListPopFront(SListNode** pplist) {assert(pplist);assert(*pplist);SListNode* second = (*pplist)->next;free(*pplist);*pplist = second; }
对于单链表的头删,我们同样断言掉链表为空的状态
然后我们需要做的就是记录第二个结点,然后释放原来的第一个结点,最后连接链表头和第二个结点。这样我们就实现了我们的目的。值得注意的是,我们发现链表的头删也是比较有优势的。
6.单链表的查找
//单链表的查找 SListNode* SListFind(SListNode* plist,SLTDateType x) {SListNode* cur = plist;while (cur != NULL){if (cur->data == x){return cur;}cur = cur->next;}return NULL; }
对于单链表的查找,这个也很简单,他和单链表的打印思路是一样的,不同的是只需要返回结点的地址即可。
7.单链表在pos位置之后的插入
//单链表在pos位置之后插入 void SListInsertAfter(SListNode* pos, SLTDateType x) {assert(pos);SListNode* newnode = BuySListNode(x);SListNode* next = pos->next;pos->next = newnode;newnode->next = next; }
单链表在pos位置之后的插入也是比较简单的,我们只需要先申请一个结点,然后记录pos位置的下一个结点,然后连接就可以了。值得注意的是,pos的位置不可能为空。因为他不是一个有效的结点地址
8.单链表在pos位置之前的插入
//单链表在pos位置之前插入 void SListInsertPrev(SListNode** pplist, SListNode* pos, SLTDateType x) {assert(pplist);assert(pos);assert(*pplist);SListNode* newnode = BuySListNode(x);if (*pplist == pos){*pplist = newnode;newnode->next = pos;}else{SListNode* prev = *pplist;while (prev->next != pos){prev = prev->next;}prev->next = newnode;newnode->next = pos;} }
对于在pos位置之前的插入,确实是比较繁琐了。我们要思考,首先pos和pplist不可能为空,然后这个链表也是不可能为空链表的,至少也要有一个值。否则如果存在pos这个结点呢?
然后我们在来考虑一般情况,我们假设链表很长,在中间位置pos之前插入一个结点,那么毫无疑问的是,我们需要先申请一个结点,然后在通过遍历的方式要找到pos之前的那个结点。
有了这两个结点,那么我们就可以进行连接了。
然后是特殊情况,假如这个链表只有一个结点呢,这个结点正好就是pos,我们发现pos就没有前一个结点,其实这个就等效于头插。我们采用头插的方式即可
9.单链表在pos之后删除
//单链表在pos之后删除 void SListEraseAfter(SListNode* pos) {assert(pos);assert(pos->next);SListNode* next = pos->next;pos->next = next->next;free(next);next = NULL; }
单链表在pos之后删除的话,首先pos和pos的下一个结点不会为空,否则题目就矛盾了。所以我们得断言,然后我们直接记录pos 的下一个结点,然后连接pos和pos之后的结点。最后释放掉pos的下一个结点即可。
10.单链表在pos之前删除
//单链表在pos之前删除 void SListErasePrev(SListNode** pplist, SListNode* pos) {assert(pos);assert(pplist);assert(pos != *pplist);assert(*pplist);if ((*pplist)->next == pos){SListNode* del = *pplist;*pplist = pos;free(del);del = NULL;}else{SListNode* prev = *pplist;while (prev->next->next != pos){prev = prev->next;}SListNode* del = prev->next;prev->next = pos;free(del);del = NULL;} }
对于单链表在pos之前删除确实就比较复杂了,首先pos,pplist,*pplist肯定不可能为空,然后pos也绝不可以是头节点,所以pos!=*pplist
我们现在来思考,假设一般情况,链表很长,在中间位置是pos,删除pos的前一个结点,那么我们就需要找到pos 的前一个的前一个结点。然后记录pos的前一个结点。释放pos 的前一个结点,然后进行连接即可
对于特殊情况,也就是,pos在第二个结点上,这样我们无法找到pos的前一个的前一个结点,但是这个就是头删,我们直接采用类似的思路即可
11.单链表在pos位置的删除
//单链表在pos位置删除 void SListErase(SListNode** pplist, SListNode* pos) {assert(pplist);assert(pos);assert(*pplist);if (*pplist == pos){free(pos);*pplist = pos = NULL;}else{SListNode* prev = *pplist;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;} }
这个与上一个接口是基本一致的思路。不同的是,pos可以在头结点了,如果是头节点就是头删。
如果不是,就是先找到前一个结点,然后进行删除连接即可
12.单链表的销毁
//单链表的销毁 void SListDestroy(SListNode** pplist) {SListNode* cur = *pplist;while (cur != NULL){SListNode* next = cur->next;free(cur);cur = next;} }
对于单链表的销毁,这个也很简单,就直接遍历销毁即可,与打印和查找的思路是一致的
四、单链表的实现完整代码
SList.h文件
#pragma once#include<stdio.h> #include<stdlib.h> #include<malloc.h> #include<assert.h>typedef int SLTDateType;typedef struct SListNode {SLTDateType data;struct SListNode* next; }SListNode;//单链表的打印 void SListPrint(SListNode* plist); //单链表的尾插 void SListPushBack(SListNode** pplist, SLTDateType x); //单链表的头插 void SListPushFront(SListNode** pplist, SLTDateType x); //单链表的尾删 void SListPopBack(SListNode** pplist); //单链表的头删 void SListPopFront(SListNode** pplist); //单链表的查找 SListNode* SListFind(SListNode* plist,SLTDateType x); //单链表在pos位置之后插入 void SListInsertAfter(SListNode* pos, SLTDateType x); //单链表在pos位置之前插入 void SListInsertPrev(SListNode** pplist, SListNode* pos, SLTDateType x); //单链表在pos之后删除 void SListEraseAfter(SListNode* pos); //单链表在pos之前删除 void SListErasePrev(SListNode** pplist, SListNode* pos); //单链表在pos位置删除 void SListErase(SListNode** pplist, SListNode* pos); //单链表的销毁 void SListDestroy(SListNode** pplist);
SList.c文件
#define _CRT_SECURE_NO_WARNINGS 1 #include"SList.h"//单链表的打印 void SListPrint(SListNode* plist) {SListNode* cur = plist;while (cur != NULL){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n"); }//获取一个结点 SListNode* BuySListNode(SLTDateType x) {SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));if (tmp == NULL){perror("malloc fail");return;}tmp->next = NULL;tmp->data = x;return tmp; }//单链表的尾插 void SListPushBack(SListNode** pplist, SLTDateType x) {assert(pplist);SListNode* newnode = BuySListNode(x);if (*pplist == NULL){*pplist = newnode;return;}SListNode* tail = (*pplist);while (tail->next != NULL){tail = tail->next;}tail->next = newnode; }//单链表的头插 void SListPushFront(SListNode** pplist, SLTDateType x) {assert(pplist);SListNode* newnode = BuySListNode(x);SListNode* first = *pplist;*pplist = newnode;newnode->next = first; }//单链表的尾删 void SListPopBack(SListNode** pplist) {assert(pplist);assert(*pplist);if ((*pplist)->next == NULL){free(*pplist);*pplist = NULL;}else{SListNode* tail = *pplist;while (tail->next->next != NULL){tail = tail->next;}free(tail->next);tail->next = NULL;} }//单链表的头删 void SListPopFront(SListNode** pplist) {assert(pplist);assert(*pplist);SListNode* second = (*pplist)->next;free(*pplist);*pplist = second; }//单链表的查找 SListNode* SListFind(SListNode* plist,SLTDateType x) {SListNode* cur = plist;while (cur != NULL){if (cur->data == x){return cur;}cur = cur->next;}return NULL; } //单链表在pos位置之后插入 void SListInsertAfter(SListNode* pos, SLTDateType x) {assert(pos);SListNode* newnode = BuySListNode(x);SListNode* next = pos->next;pos->next = newnode;newnode->next = next; } //单链表在pos位置之前插入 void SListInsertPrev(SListNode** pplist, SListNode* pos, SLTDateType x) {assert(pplist);assert(pos);assert(*pplist);SListNode* newnode = BuySListNode(x);if (*pplist == pos){*pplist = newnode;newnode->next = pos;}else{SListNode* prev = *pplist;while (prev->next != pos){prev = prev->next;}prev->next = newnode;newnode->next = pos;} } //单链表在pos之后删除 void SListEraseAfter(SListNode* pos) {assert(pos);assert(pos->next);SListNode* next = pos->next;pos->next = next->next;free(next);next = NULL; } //单链表在pos之前删除 void SListErasePrev(SListNode** pplist, SListNode* pos) {assert(pos);assert(pplist);assert(pos != *pplist);assert(*pplist);if ((*pplist)->next == pos){SListNode* del = *pplist;*pplist = pos;free(del);del = NULL;}else{SListNode* prev = *pplist;while (prev->next->next != pos){prev = prev->next;}SListNode* del = prev->next;prev->next = pos;free(del);del = NULL;} } //单链表在pos位置删除 void SListErase(SListNode** pplist, SListNode* pos) {assert(pplist);assert(pos);assert(*pplist);if (*pplist == pos){free(pos);*pplist = pos = NULL;}else{SListNode* prev = *pplist;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;} } //单链表的销毁 void SListDestroy(SListNode** pplist) {SListNode* cur = *pplist;while (cur != NULL){SListNode* next = cur->next;free(cur);cur = next;} }
Test.c文件
#define _CRT_SECURE_NO_WARNINGS 1#include"Slist.h"void TestSList1() {SListNode* phead = NULL;SListPushBack(&phead, 1);SListPushBack(&phead, 2);SListPushBack(&phead, 3);SListPushBack(&phead, 4);SListPushBack(&phead, 5);SListPrint(phead);SListPushFront(&phead, 6);SListPushFront(&phead, 7);SListPushFront(&phead, 8);SListPushFront(&phead, 9);SListPushFront(&phead, 10);SListPrint(phead);SListPopBack(&phead);SListPopBack(&phead);SListPopBack(&phead);SListPopBack(&phead);SListPrint(phead);SListPopBack(&phead);SListPrint(phead);} void TestSList2() {SListNode* phead = NULL;SListPushBack(&phead, 1);SListPushBack(&phead, 2);SListPushBack(&phead, 3);SListPushBack(&phead, 4);SListPushBack(&phead, 5);SListPrint(phead);SListPopFront(&phead);SListPopFront(&phead);SListPopFront(&phead);SListPopFront(&phead);SListPrint(phead);SListPopFront(&phead);SListPrint(phead); } void TestSList3() {SListNode* phead = NULL;SListPushBack(&phead, 1);SListPushBack(&phead, 2);SListPushBack(&phead, 3);SListPushBack(&phead, 4);SListPushBack(&phead, 5);SListPrint(phead);SListNode* pos = SListFind(phead, 3);pos->data = 100;SListPrint(phead);SListInsertAfter(pos, 200);SListInsertAfter(pos, 300);SListInsertAfter(pos, 400);SListInsertAfter(pos, 500);SListPrint(phead);SListNode* pos2 = SListFind(phead, 1);SListInsertPrev(&phead, pos2, 101);SListInsertPrev(&phead, pos2, 102);SListInsertPrev(&phead, pos2, 103);SListInsertPrev(&phead, pos2, 104);SListPrint(phead);SListEraseAfter(pos2);SListEraseAfter(pos2);SListEraseAfter(pos2);SListPrint(phead);}void TestSList4() {SListNode* phead = NULL;SListPushBack(&phead, 1);SListPushBack(&phead, 2);SListPushBack(&phead, 3);SListPushBack(&phead, 4);SListPushBack(&phead, 5);SListPrint(phead);SListNode* pos = SListFind(phead, 5);SListErasePrev(&phead, pos);SListPrint(phead);SListErasePrev(&phead, pos);SListPrint(phead);SListErase(&phead, pos);SListPrint(phead);SListDestroy(&phead); }int main() {//TestSList1();//TestSList2();//TestSList3();TestSList4();return 0; }
本节内容到此位置,感谢您的阅读
如果对你有帮助的话,不要忘记点赞加收藏哦!!!
相关文章:

【数据结构】第三站:单链表
目录 一、顺序表的缺陷 二、链表 1.链表的概念以及结构 2.链表的分类 3.单链表的逻辑结构与物理结构 三、单链表的实现 1.单链表的定义 2.单链表的接口定义 3.单链表的接口实现 四、单链表的实现完整代码 一、顺序表的缺陷 在上一篇文章中,我们了解了顺序…...

【蓝桥杯2020】七段码
【题目描述】 七段码 HUSTOJ 题目导出文件 [蓝桥杯2020] 第十一届蓝桥杯第二次省赛—填空题E题 七段码 小蓝要用七段码数码管来表示一种特殊的文字。 上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二 极管,分别标记为 a, b, c,…...

Spark读取JDBC调优
Spark读取JDBC调优,如何调参一、场景构建二、参数设置1.灵活运用分区列实际问题:工作中需要读取一个存放了三四年历史数据的pg数仓表(缺少主键id),需要将数据同步到阿里云 MC中,Spark在使用JDBC读取关系型数…...

【文心一言】什么是文心一言,如何获得内测和使用方法。
文心一言什么是文心一言怎么获得内测资格接下来就给大家展示一下文学创作商业文案创作数理逻辑推算中文理解多模态生成用python写一个九九乘法表写古诗前言: 🏠个人主页:以山河作礼。 📝📝:本文章是帮助大家了解文心…...

CentOS8服务篇10:FTP服务器配置与管理
一、安装与启动FTP服务器 1、安装VSFTP服务器所需要的安装包 #yum -y install vsftpd 2、查看配置文件参数 Vim /etc/vsftpd/vsftpd.conf (1)是否允许匿名登录 anonymous_enableYES 该行用于控制是否允许匿名用户登录。 (2&…...

笔试强训3.14
一、选择题 1.以下说法错误的是(C) A.数组是一个对象 B.数组不是一种原生类 C.数组的大小可以任意改变 D.在Java中,数组存储在堆中连续内存空间里 相关知识点:原生/内置数组是那八个,其他的都是引用的,借…...

elasticsearch 环境搭建和基本操作
参考资料 适合后端编程人员的elasticsearch快速实战教程 ElasticSearch最新实战教程 ElasticSearch配套笔记 自制搜索引擎 https://www.elastic.co/guide/en/elasticsearch/reference/7.17/setup.html restful风格的api REST 设计风格 例如以下springboot示例 RestContr…...

IDEA操作:Springboot项目打包为jar包并运行
在IDEA环境下对Springboot项目打包为jar包且在terminal运行操作 1、 2、 3、注意:在项目目录里创建一个用来存放jar包的文件夹(res),该路径不能使用IDEA设置的默认路径,必须手动创建。 4、 5、点击ok后加载运行包 (8…...

原理底层计划---JVM
二、JVM对空间大小怎么配置?各区域怎么划? 新生代:短时间生成,可以马上回收 老生代:少部分对象会存在很久,回收策略应不同 三、JVM哪些内存区域会发生内存溢出(程序计数器不会) …...

CSDN-猜年龄、纸牌三角形、排他平方数
猜年龄 原题链接:https://edu.csdn.net/skill/practice/algorithm-a413078fb6e74644b8c9f6e28896e377/2258 美国数学家维纳(N.Wiener)智力早熟,11岁就上了大学。他曾在1935~1936年应邀来中国清华大学讲学。 一次,他参加某个重要会议…...

【Linux】软件包管理器 yum
什么是软件包和软件包管理器 在 Linux 下需要安装软件时, 最原始的办法就是下载到程序的源代码, 进行编译得到可执行程序。但是这样太麻烦了,所以有些人就把一些常用的软件提前编译好, 做成软件包 ( 就相当于windows上的软件安装程序)放在服…...

一天吃透TCP面试八股文
本文已经收录到Github仓库,该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点,欢迎star~ Github地址:https://github.com/…...

zzu天梯赛选拔
C. NANA去上课 — 简单数学 需要记录上一步处在哪个位置 然后判断如果是同一侧移动距离就是abs(x1 - x2) 如果不同就是x1 x2 #include <iostream> #include <cmath> using namespace std; #define int long long signed main() {int n; c…...

【C语言】一篇让你彻底吃透(结构体与结构体位段)
本章重点 主要讲解结构体和位移动的使用和定义与声明,并且结构体和位段在内存中是如何存储的。 文章目录结构体结构体类型的声明结构体特殊的声明结构体变量的定义和初始化结构体成员的访问结构的自引用结构体内存对齐结构体传参位段什么是位段位段的内存分配位段的…...

数据结构之二叉树构建、广度/深度优先(前序、中序、后序)遍历
一、二叉树 1.1 树 说到树,我们暂时忘记学习,来看一下大自然的树: 哈哈 以上照片是自己拍的,大家凑合看看 回归正题,那么在数据结构中,树是什么呢,通过上面的图片大家也可以理解 树是一种非…...

“国产版ChatGPT”文心一言发布会现场Demo硬核复现
文章目录前言实验结果一、文学创作问题1 :《三体》的作者是哪里人?问题2:可以总结下三体的核心内容吗?如果要续写的话,可以从哪些角度出发?问题3:如何从哲学角度来进行续写?问题4:电…...

202304读书笔记|《不被定义的女孩》——做最真实最漂亮的自己,依心而行
202304读书笔记|《不被定义的女孩》——做最真实最漂亮的自己,依心而行《不被定义的女孩》作者ASEN,很棒的书。处处透露着洒脱,通透,悦己,阅世界的自由的氛围和态度! 部分节选如下: 让自己活得…...

SpringBoot帮你优雅的关闭WEB应用程序
Graceful shutdown 应用 Graceful shutdown说明 Graceful shutdown is supported with all four embedded web servers (Jetty, Reactor Netty, Tomcat, and Undertow) and with both reactive and servlet-based web applications. It occurs as part of closing the applica…...

递归与递推
递归 直白理解:函数在其内部调用自身(自己调用自己)所有递归都可以采用递归搜索树来理解递归的特点: 一般来说代码较为简短,但是理解难度大一般时间和空间消耗较大,容易产生重复计算,可能爆栈 …...

使用<style scoped>导致的样式问题
问题描述: 今天使用开源组件库TDesign的自动补全组件时,遇到了一个样式失效问题,一开始怎么也找不到问题出在哪,后面一个偶然去掉了scoped,竟然发现样式竟然正常了,具体原因不知道在哪,有大佬知…...

Elasticsearch深入理解(十八)-集群关键指标及调优指南
1、CPU使用率 CPU使用率是指在一段时间内CPU执行程序的百分比,它是衡量系统资源利用率的一种指标。 1.1 详细说明: 在Elasticsearch中,高的CPU使用率通常意味着节点正在执行大量的计算任务,这可能是因为索引和搜索操作的负载较大…...

Transformer到底为何这么牛
从注意力机制(attention)开始,近两年提及最多的就是Transformer了,那么Transformer到底是什么机制,凭啥这么牛?各个领域都能用?一文带你揭开Transformer的神秘面纱。 目录 1.深度学习࿰…...

【Spring事务】声明式事务 使用详解
个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ 声明式事务一、编程式事务二、声明式事务&…...

学习28个案例总结
学习前 对于之前遇到的问题没有及时总结,导致做什么事情都是新的一样。没有把之前学习到接触到的内容应用上。通过这次对28个案例的学习。把之前遇到的问题总结成自己的经验,在以后的开发过程中避免踩重复性的坑。多看帮助少走弯路。 学习中 对28个案例…...

刷题Java常用方法总结
刷题Java常用方法总结 文章目录刷题Java常用方法总结快速查看:静态数组 Static Array初始化instance属性length技巧Arrays.sort从小到大排序Arrays.fill填满一个数组Arrays.copyOf / arr.clone()复制一个数组(二维数组也可以)动态数组 List & Dynamic Array初始化常规 - Ar…...

大数据技术之Hive
第1章Hive基本概念1.1 Hive1.1.1 Hive的产生背景在那一年的大数据开源社区,我们有了HDFS来存储海量数据、MapReduce来对海量数据进行分布式并行计算、Yarn来实现资源管理和作业调度。但是面对海量数据和负责的业务逻辑,开发人员要编写MR来对数据进行统计…...

第33篇:Java集合类框架总结
目录 1、集合概念 2、集合与数组的区别 3、集合框架的特性 1)高性能 2)可操作...

数据结构 | 栈的中缀表达式求值
目录 什么是栈? 栈的基本操作 入栈操作 出栈操作 取栈顶元素 中缀表达式求值 实现思路 具体代码 什么是栈? 栈是一种线性数据结构,具有“先进后出”(Last In First Out, LIFO)的特点。它可以看作是一种受限的…...

vue2前端实现html导出pdf功能
1. 功能实现方案 1.html转换成canvas后生成图片导出pdf(本文选用) html转canvas插件:html2canvas是一款将HTML代码转换成Canvas的插件;canvas生成pdf:jsPDF是一个使用Javascript语言生成PDF的开源库 2.HTML代码转出…...

用 ChatGPT 辅助学好机器学习
文章目录一、前言二、主要内容🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、前言 探索更高效的学习方法可能是有志者共同的追求,用好 ChatGPT,先行于未来。 作为一个人工智能大语言模型,ChatGPT 可以在帮助初…...