数据结构---单链表
专栏:数据结构
个人主页:HaiFan.
专栏简介:从零开始,数据结构!!
单链表
- 前言
- 顺序表的缺陷
- 链表的概念以及结构
- 链表接口实现
- 打印链表中的元素SLTPrint
- phead->next!=NULL和phead!=NULL的区别
- 开辟空间SLTNewNode
- 尾插SLTPushBack和尾删SLTPopBack
- 头插SLTPushFront和头删SLTPopFront
- 查找SLTFind
- 在查找元素的后面插入SLTInsertAfter
- 在查找元素的后面删除SLTEraseAfter
- 销毁开辟的空间SLTDestory
- 各个接口测试
- 源代码
- 链表和顺序表的区别
前言

顺序表的缺陷
顺序表每一次扩容,都是连续的空间,支持通过下标去访问数据。
但是顺序表的头插,头删,中间删元素,需要把后面的数据覆盖前面的元素,也就是挪动元素,这就导致效率非常的低
并且,顺序表在扩容之后,可能会有一部分空间没有用,这就导致了空间浪费。
链表的概念以及结构
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
链表的结点一般是在堆上申请出来的,从堆上申请的空间,是按照一定策略来分配的,两次申请的空间可能连续,也可能不连续。
链表是每用一块空间,便开辟一块空间,因此,不会造成空间浪费。

这个图什么意思呢?
把开辟的空间当作2个合在一起的小方块,一个小方块用来存元素的值,一个方块用来存放下一个空间的地址。

当这个1就是最后一个元素的时候,这个下一块空间的地址就是NULL,因为1后面没有元素了,不能让这个地址乱指向其他的空间。
链表接口实现

这里,在结构体中要用结构体指针,指针就是地址,这个地址就是用来存放下一个空间的地址的。
typedef int SLTDataType;typedef struct SLTNode
{SLTDataType val;struct SLTNode* next;
}SLT;void SLTPrint(SLT* phead);//打印单链表中的数据SLT* SLTNewNode(SLTDataType x);//每要插入数据,就需要开一一块空间void SLTPushBack(SLT** pphead, SLTDataType x);//尾插
void SLTPopBack(SLT** pphead);//尾删void SLTPushFront(SLT** pphead, SLTDataType x);//头插
void SLTPopFront(SLT** pphead);//头删SLT* SLTFind(SLT** pphead, SLTDataType x);//查找
//单链表在pos位置之后插入x
void SLTInsertAfter(SLT* pos, SLTDataType x);//插入
//单链表在pos位置之后删除元素
void SLTEraseAfter(SLT* pos);//删除void SLTDestory(SLT** pphead);//销毁空间
打印链表中的元素SLTPrint
打印链表中的元素是最容易实现的一个接口。
void SLTPrint(SLT* phead)
{while (phead != NULL){cout << phead->val << "->";phead = phead->next;}cout << "NULL" << endl;
}
这里用一级指针,因为打印链表不会更改链表中的一些东西。
每打印出一个元素,都让phead指向下一块空间,直到走到为NULL的时候为止

phead->next!=NULL和phead!=NULL的区别

假如现在phead是在3这块空间,那么phead->next就是指向下一块空间,因为下一块空间是NULL,所以,当你写出phead->next != NULL的时候,就会在3这里停止后面的打印。
phead !=NULL是当phead走到NULL的时候才会执行。
开辟空间SLTNewNode
链表是每用一块空间就开辟一块空间。这样不会造成空间浪费。
SLT* SLTNewNode(SLTDataType x)
{SLT* newnode = (SLT*)malloc(sizeof(SLT));newnode->next = NULL;newnode->val = x;return newnode;
}
开辟了空间之后,不要忘记把newnode->next置为NULL,不然就成为野指针了。最后把这块空间返回即可。
尾插SLTPushBack和尾删SLTPopBack
尾插的时候,先调用一下开辟空间的函数,再把开辟的空间返回,用一个结构体指针变量接收。
- 当链表为空的时候,newnode就可以当作链表中的第一块空间。
- 当链表不为空的时候,就需要先找到链表的尾部,然后把newnode链接在链表中即可
void SLTPushBack(SLT** pphead, SLTDataType x)
{SLT* newnode = SLTNewNode(x);if (*pphead == NULL){*pphead = newnode;}else{SLT* tail = *pphead;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}

要用一个临时变量走向链表最后一个元素的位置,如果不用临时变量,直接用头元素走到最后一个位置,那么,在打印元素的时候,也是从最后一个元素的位置开始打印的,前面的元素不会打印,因为我们是用指针接收的头元素的位置,通过指针直接去访问内容,指针走到最后就会导致,原本应该指向头元素的指针,就指向了最后的元素。
所以在这里用 tail->next != NULL
尾删分两种情况,当链表中只有一个元素的时候和链表中有n个元素的时候。
第一种情况好说,直接把第一个元素的空间给free掉,在置为空即可。
第二种情况就是先找到尾,但是,在找到尾部之后,不能直接把尾部free掉,而是要先知道倒数第二个元素的位置。
void SLTPopBack(SLT** pphead)
{assert(*pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SLT* tail = *pphead;while (tail->next->next != NULL){ tail = tail->next;}free(tail->next);tail->next = NULL;}
}/*SLTNode* prev = NULL;SLTNode* tail = phead;while (tail->next){prev = tail;tail = tail->next;}free(tail);prev->next = NULL;*/
这两种方法都可以。
头插SLTPushFront和头删SLTPopFront
头插特别容易,先开辟一块空间,然后把这块空间指向头元素空间。在把头元素空间指向新开辟的空间即可。

void SLTPushFront(SLT** pphead, SLTDataType x)
{SLT* newnode = SLTNewNode(x);newnode->next = *pphead;*pphead = newnode;
}
头删之前,要先判断链表中有没有元素,没有元素直接断言。
有一个元素,直接free。
多个元素,先用一个临时变量记录一下头元素指向的下一个元素的地址,然后把头元素给free掉,再让头元素=临时变量。
void SLTPopFront(SLT** pphead)
{assert(*pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SLT* head = (*pphead)->next;free(*pphead);*pphead = NULL;*pphead = head;}
}
查找SLTFind
查找元素的时候,把该空间的地址给返回即可,遍历一遍链表即可实现。
SLT* SLTFind(SLT** pphead, SLTDataType x)
{SLT* tail = *pphead;while (tail != NULL){if (tail->val == x){return tail;}tail = tail->next;}return NULL;//没有找到
}
在查找元素的后面插入SLTInsertAfter
先通过SLTFind,找到要插入的位置,然后通过断言来判断这个位置是否合法。

比如要把3插入到1和2之间,把3->next = 1->next,再把1->next = 3就能完成插入。
void SLTInsertAfter(SLT* pos, SLTDataType x)
{assert(pos);SLT* newnode = SLTNewNode(x);newnode->next = pos->next;pos->next = newnode;}
在查找元素的后面删除SLTEraseAfter
还是先断言,判断位置是否合法。

电脑上的画图实在是用不来,原谅我------。。。
void SLTEraseAfter(SLT* pos)
{assert(pos);if (pos->next == NULL){return;}SLT* newnode = pos->next;pos->next = newnode->next;free(newnode);newnode = NULL;
}
销毁开辟的空间SLTDestory
因为空间不一定是连续的,所以需要遍历链表,一个一个的释放
void SLTDestory(SLT** pphead)
{SLT* cur = *pphead;while (cur){SLT* hh = cur->next;free(cur);cur = hh;}
}
各个接口测试
void TestSLTNode()
{SLT* plist = NULL;cout << "尾插尾删" << endl;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPushBack(&plist, 4);SLTPopBack(&plist);SLTPopBack(&plist);SLTPopBack(&plist);SLTPopBack(&plist);SLTPrint(plist);
}void TestSLTNode1()
{SLT* plist = NULL;cout << "头插头删" << endl;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPrint(plist);
}void TestSLTNode2()
{SLT* plist = NULL;cout << "查找,删除,插入" << endl;SLTPushFront(&plist, -1);SLTPushBack(&plist, 1);SLTPushFront(&plist, -2);SLTPushBack(&plist, 2);SLTPushFront(&plist, -3);SLTPushBack(&plist, 3);SLTPushFront(&plist, -4);SLTPushBack(&plist, 4);SLT* ret = SLTFind(&plist, 3);if (ret){cout << ret << endl;}SLTPrint(plist);SLTInsertAfter(ret, 100);SLTInsertAfter(ret, 100);SLTInsertAfter(ret, 100);SLTPrint(plist);SLTEraseAfter(ret);SLTEraseAfter(ret);SLTPrint(plist);SLTDestory(&plist);
}int main()
{TestSLTNode();TestSLTNode1();TestSLTNode2();return 0;
}

源代码
.h文件
#pragma once#include <iostream>
#include <stdlib.h>
#include <assert.h>using namespace std;typedef int SLTDataType;typedef struct SLTNode
{SLTDataType val;struct SLTNode* next;
}SLT;void SLTPrint(SLT* phead);//打印单链表中的数据SLT* SLTNewNode(SLTDataType x);//每要插入数据,就需要开一一块空间void SLTPushBack(SLT** pphead, SLTDataType x);//尾插
void SLTPopBack(SLT** pphead);//尾删void SLTPushFront(SLT** pphead, SLTDataType x);//头插
void SLTPopFront(SLT** pphead);//头删SLT* SLTFind(SLT** pphead, SLTDataType x);//查找
//单链表在pos位置之后插入x
void SLTInsertAfter(SLT* pos, SLTDataType x);//插入
//单链表在pos位置之后删除元素
void SLTEraseAfter(SLT* pos);//删除void SLTDestory(SLT** pphead);//销毁空间
.cpp文件
#define _CRT_SECURE_NO_WARNINGS 1#include "SList.h"void SLTPrint(SLT* phead)
{while (phead){cout << phead->val << "->";phead = phead->next;}cout << "NULL" << endl;
}SLT* SLTNewNode(SLTDataType x)
{SLT* newnode = (SLT*)malloc(sizeof(SLT));newnode->next = NULL;newnode->val = x;return newnode;
}void SLTPushBack(SLT** pphead, SLTDataType x)
{SLT* newnode = SLTNewNode(x);if (*pphead == NULL){*pphead = newnode;}else{SLT* tail = *pphead;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}void SLTPopBack(SLT** pphead)
{assert(*pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SLT* tail = *pphead;while (tail->next->next != NULL){ tail = tail->next;}free(tail->next);tail->next = NULL;}
}void SLTPushFront(SLT** pphead, SLTDataType x)
{SLT* newnode = SLTNewNode(x);newnode->next = *pphead;*pphead = newnode;
}void SLTPopFront(SLT** pphead)
{assert(*pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SLT* head = (*pphead)->next;free(*pphead);*pphead = NULL;*pphead = head;}
}SLT* SLTFind(SLT** pphead, SLTDataType x)
{SLT* tail = *pphead;while (tail != NULL){if (tail->val == x){return tail;}tail = tail->next;}return NULL;//没有找到
}void SLTInsertAfter(SLT* pos, SLTDataType x)
{assert(pos);SLT* newnode = SLTNewNode(x);newnode->next = pos->next;pos->next = newnode;}void SLTEraseAfter(SLT* pos)
{assert(pos);if (pos->next == NULL){return;}SLT* newnode = pos->next;pos->next = newnode->next;free(newnode);newnode = NULL;
}void SLTDestory(SLT** pphead)
{SLT* cur = *pphead;while (cur){SLT* hh = cur->next;free(cur);cur = hh;}
}
test.cpp文件
#define _CRT_SECURE_NO_WARNINGS 1#include "SList.h"void TestSLTNode()
{SLT* plist = NULL;cout << "尾插尾删" << endl;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPushBack(&plist, 4);SLTPopBack(&plist);SLTPopBack(&plist);SLTPopBack(&plist);SLTPopBack(&plist);SLTPrint(plist);
}void TestSLTNode1()
{SLT* plist = NULL;cout << "头插头删" << endl;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPrint(plist);
}void TestSLTNode2()
{SLT* plist = NULL;cout << "查找,删除,插入" << endl;SLTPushFront(&plist, -1);SLTPushBack(&plist, 1);SLTPushFront(&plist, -2);SLTPushBack(&plist, 2);SLTPushFront(&plist, -3);SLTPushBack(&plist, 3);SLTPushFront(&plist, -4);SLTPushBack(&plist, 4);SLT* ret = SLTFind(&plist, 3);if (ret){cout << ret << endl;}SLTPrint(plist);SLTInsertAfter(ret, 100);SLTInsertAfter(ret, 100);SLTInsertAfter(ret, 100);SLTPrint(plist);SLTEraseAfter(ret);SLTEraseAfter(ret);SLTPrint(plist);SLTDestory(&plist);
}int main()
{TestSLTNode();TestSLTNode1();TestSLTNode2();return 0;
}
链表和顺序表的区别
| 不同点 | 顺序表 | 链表 |
|---|---|---|
| 存储空间上 | 物理上一定连续 | 逻辑上连续,但物理上不一定 连续 |
| 随机访问 | 支持O(1) | 不支持:O(N) |
| 任意位置插入或者删除 元素 | 可能需要搬移元素,效率低 O(N) | 只需修改指针指向 |
| 插入 | 动态顺序表,空间不够时需要 扩容 | 没有容量的概念 |
| 应用场景 | 元素高效存储+频繁访问 | 任意位置插入和删除频繁 |
| 缓存利用率 | 高 | 低 |
相关文章:
数据结构---单链表
专栏:数据结构 个人主页:HaiFan. 专栏简介:从零开始,数据结构!! 单链表前言顺序表的缺陷链表的概念以及结构链表接口实现打印链表中的元素SLTPrintphead->next!NULL和phead!NULL的区别开辟空间SLTNewNod…...
redis数据结构的底层实现
文章目录一.引言二.redis的特点三.Redis的数据结构a.字符串b.hashc.listd.sete.zset(有序集合)一.引言 redis是一个开源的使用C语言编写、支持网络、可基于内存亦可持久化的日志型、key-value的NoSQL数据库。 通常使用redis作为缓存中间件来降低数据库的压力,除此…...
【JavaSE】复习(进阶)
文章目录1.final关键字2.常量3.抽象类3.1概括3.2 抽象方法4. 接口4.1 接口在开发中的作用4.2类型和类型之间的关系4.3抽象类和接口的区别5.包机制和import5.1 包机制5.2 import6.访问控制权限7.Object7.1 toString()7.2 equals()7.3 String类重写了toString和equals8.内部类8.1…...
Java 主流日志工具库
日志系统 java.util.logging (JUL) JDK1.4 开始,通过 java.util.logging 提供日志功能。虽然是官方自带的log lib,JUL的使用确不广泛。 JUL从JDK1.4 才开始加入(2002年),当时各种第三方log lib已经被广泛使用了JUL早期存在性能问题&#x…...
产品经理有必要考个 PMP吗?(含PMP资料)
现在基本上做产品的都有一个PMP证件,从结果导向来说,不对口不会有这么大范围的人来考,但是需要因地制宜,在公司内部里,标准程序并不流畅,产品和项目并不规范,关系错综复杂。 而产品经理的职能又…...
什么是原型、原型链?原型和原型链的作用
1、ES6之前,继承都用构造函数来实现;对象的继承,先申明一个对象,里面添加实例成员<!DOCTYPE html> <html><head><meta charset"utf-8" /><title></title></head><body><script…...
条件期望4
条件期望例题----快排算法的分析 快速排序算法的递归定义如下: 有n个数(n≥2n\geq 2n≥2), 一开始随机选取一个数xix_ixi, 并将xix_ixi和其他n-1个数进行比较, 记SiS_iSi为比xix_ixi小的元素构成的集合, Siˉ\bar{S_i}Siˉ为比xix_ixi大的元素构成的集合, 然后分…...
网络协议分析(2)判断两个ip数据包是不是同一个数据包分片
一个节点收到两个IP包的首部如下:(1)45 00 05 dc 18 56 20 00 40 01 bb 12 c0 a8 00 01 c0 a8 00 67(2)45 00 00 15 18 56 00 b9 49 01 e0 20 c0 a8 00 01 c0 a8 00 67分析并判断这两个IP包是不是同一个数据报的分片&a…...
6.2 负反馈放大电路的四种基本组态
通常,引入交流负反馈的放大电路称为负反馈放大电路。 一、负反馈放大电路分析要点 如图6.2.1(a)所示电路中引入了交流负反馈,输出电压 uOu_OuO 的全部作为反馈电压作用于集成运放的反向输入端。在输入电压 uIu_IuI 不变的情况下,若由于…...
MySQL进阶之锁
锁是计算机中协调多个进程或线程并发访问资源的一种机制。在数据库中,除了传统的计算资源竞争之外,数据也是一种提供给许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决堆的一个问题,锁冲突也是影响数据…...
【Mac 教程系列】如何在 Mac 上破解带有密码的 ZIP 压缩文件 ?
如何使用 fcrackzip 在 Mac 上破解带有密码的 ZIP 压缩文件? 用 markdown 格式输出答案。 在 Mac 上破解带有密码的 ZIP 压缩文件 使用解压缩软件,如The Unarchiver,将文件解压缩到指定的文件夹。 打开终端,输入 zip -er <zipfile> &…...
【Acwing 周赛复盘】第92场周赛复盘(2023.2.25)
【Acwing 周赛复盘】第92场周赛复盘(2023.2.25) 周赛复盘 ✍️ 本周个人排名:1293/2408 AC情况:1/3 这是博主参加的第七次周赛,又一次体会到了世界的参差(这次周赛记错时间了,以为 19:15 开始&…...
L1-087 机工士姆斯塔迪奥
在 MMORPG《最终幻想14》的副本“乐欲之所瓯博讷修道院”里,BOSS 机工士姆斯塔迪奥将会接受玩家的挑战。 你需要处理这个副本其中的一个机制:NM 大小的地图被拆分为了 NM 个 11 的格子,BOSS 会选择若干行或/及若干列释放技能,玩家…...
本周大新闻|索尼PS VR2立项近7年;传腾讯将引进Quest 2
本周大新闻,AR方面,传立讯精密开发苹果初代AR头显,第二代低成本版将交给富士康;iOS 16.4代码曝光新的“计算设备”;EM3推出AR眼镜Stellar Pro;努比亚将在MWC2023推首款AR眼镜。VR方面,传闻腾讯引…...
aws console 使用fargate部署aws服务快速跳转前端搜索栏
测试过程中需要在大量资源之间跳转,频繁的点击不如直接搜索来的快,于是写了一个搜索框方便跳转。 前端的静态页面可以通过s3静态网站托管实现,但是由于中国区需要备案的原因,可以使用ecs fargate部署 步骤如下: 编写…...
Redis实战之Redisson使用技巧详解
一、摘要什么是 Redisson?来自于官网上的描述内容如下!Redisson 是一个在 Redis 的基础上实现的 Java 驻内存数据网格客户端(In-Memory Data Grid)。它不仅提供了一系列的 redis 常用数据结构命令服务,还提供了许多分布…...
SQLAlchemy
文章目录SQLAlchemy介绍SQLAlchemy入门使用原生sql使用orm外键关系一对多关系多对多关系基于scoped_session实现线程安全简单表操作实现方案CRUDFlask 集成 sqlalchemySQLAlchemy 介绍 SQLAlchemy是一个基于Python实现的ORM框架。该框架建立在 DB API之上,使用关系…...
【Linux学习笔记】8.Linux yum 命令和apt 命令
前言 本章介绍Linux的yum命令和apt命令。 Linux yum 命令 yum( Yellow dog Updater, Modified)是一个在 Fedora 和 RedHat 以及 SUSE 中的 Shell 前端软件包管理器。 基于 RPM 包管理,能够从指定的服务器自动下载 RPM 包并且安装…...
windows服务器实用(4)——使用IIS部署网站
windows服务器实用——IIS部署网站 如果把windows服务器作为web服务器使用,那么在这个服务器上部署网站是必须要做的事。在windows服务器上,我们一般使用IIS部署。 假设此时前端给你一个已经完成的网站让你部署在服务器上,别人可以在浏览器…...
Random(二)什么是伪共享?@sun.misc.Contended注解
目录1.背景简介2.伪共享问题3.问题解决4.JDK使用示例1.背景简介 我们知道,CPU 是不能直接访问内存的,数据都是从高速缓存中加载到寄存器的,高速缓存又有 L1,L2,L3 等层级。在这里,我们先简化这些复杂的层级…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
