【数据结构】第三站:单链表
目录
一、顺序表的缺陷
二、链表
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,竟然发现样式竟然正常了,具体原因不知道在哪,有大佬知…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...

基于Java+VUE+MariaDB实现(Web)仿小米商城
仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...

解析“道作为序位生成器”的核心原理
解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制,重点解析"道作为序位生成器"的核心原理与实现框架: 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...
起重机起升机构的安全装置有哪些?
起重机起升机构的安全装置是保障吊装作业安全的关键部件,主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理: 一、超载保护装置(核心安全装置) 1. 起重量限制器 功能:实时监测起升载荷&a…...