广元单页网站制作/上海专业的seo推广咨询电话
目录
1. 介绍
重要性
应用场景
2. ZooKeeper 架构
服务角色
数据模型
工作原理
3. 安装和配置
下载 ZooKeeper
安装和配置
启动 ZooKeeper
验证和管理
停止和关闭
4. ZooKeeper 数据模型
数据结构和层次命名空间:
节点类型和 Watcher 机制:
5. 分布式锁
实现分布式锁的基本步骤
代码示例(Java)
避免死锁
6. 选举机制
选举机制基本流程
选举代码示例
7. 实战案例
引入 ZooKeeper 客户端依赖
创建 ZooKeeper 连接
进行节点操作
注意事项
1. 介绍
ZooKeeper是一个开源的分布式协调服务,为分布式系统提供高效的管理和协调机制。它被广泛应用于解决分布式系统中的各种共识问题,如配置管理、命名服务、分布式锁、分布式队列、选举算法等。以下是ZooKeeper在分布式系统中的重要性和应用场景:
重要性
-
一致性服务:ZooKeeper提供强一致性的数据模型,能够保证数据在分布式环境下的一致性。它采用了Paxos算法等技术,确保数据的原子性和顺序性。
-
分布式锁和同步:通过ZooKeeper,可以实现分布式系统中的锁和同步机制,确保多个节点对共享资源的互斥访问和同步操作。
-
配置管理:ZooKeeper可用于集中式管理配置信息,各个节点可以通过ZooKeeper获取最新的配置数据,实现配置的动态更新和统一管理。
-
命名服务:提供类似于目录树的结构,可以用于命名服务,帮助系统发现和定位各种服务和资源。
-
分布式协调和领导者选举:ZooKeeper提供了一套轻量级的协调机制,用于实现分布式系统中的领导者选举、Master/Slave模式等场景。
应用场景
-
分布式应用的配置管理:对于需要共享配置信息的分布式应用,ZooKeeper提供了一个可靠的配置中心,确保所有节点都能获取到最新的配置。
-
分布式锁和同步:在多个节点之间实现资源的互斥访问,如分布式任务调度、分布式缓存的缓存更新等。
-
分布式协调服务:例如,分布式集群中的领导者选举、Master/Slave模式的切换等场景。
-
分布式队列:通过ZooKeeper实现分布式队列,实现数据的有序处理和异步处理。
-
服务发现与注册:提供服务发现的功能,帮助系统在分布式环境下发现和定位各种服务。
2. ZooKeeper 架构
服务角色
-
Leader(领导者):负责处理客户端的写请求(如创建、更新、删除数据等)。它确保所有写请求按顺序被处理,并将更改广播给所有服务器。
-
Followers(追随者):复制Leader的数据状态,并处理客户端的读请求。它们参与投票选举Leader,并与Leader保持同步。
-
Observer(观察者):类似于Follower,但不参与投票。Observer接收Leader的状态更改,但不参与投票过程。它们可以减轻Leader负载并提高读取性能。
数据模型
ZooKeeper的数据模型类似于文件系统的目录结构,由节点(Node)组成,每个节点称为ZNode。ZNode可以存储数据和元数据,并具有唯一的路径标识。
工作原理
-
一致性(Consistency):ZooKeeper保持强一致性,确保所有Follower和Observer的数据与Leader保持一致。当客户端写入数据时,Leader将更改广播给所有节点,并在超过半数节点确认后提交更改。
-
可用性(Availability):ZooKeeper的集群中,只要有半数以上节点是可用的,系统就可以继续提供服务。客户端可以从任何节点读取数据。
-
分区容错性(Partition Tolerance):ZooKeeper使用多数派机制(Quorum),确保在网络分区时集群能够正常工作。即使分区发生,只要超过半数节点仍然能够互相通信,系统就能继续服务。
-
Leader选举(Leader Election):ZooKeeper使用ZAB(ZooKeeper Atomic Broadcast)协议进行Leader选举。当Leader失效时,Followers会投票选举一个新的Leader。
-
数据同步(Data Synchronization):Leader负责接收客户端写入的请求,并将更改复制到Followers和Observers。这确保了数据的一致性和可用性。
ZooKeeper通过以上机制和算法确保了其高一致性、高可用性和分区容错性,为分布式应用提供了可靠的服务。其基于ZAB协议的工作方式使得ZooKeeper能够在分布式环境下有效地管理数据和协调系统的各项任务。
3. 安装和配置
下载 ZooKeeper
- 官方网站:访问 Apache ZooKeeper 下载页面,选择最新稳定版本的 ZooKeeper。
安装和配置
-
解压文件:将下载的 ZooKeeper 压缩包解压到本地文件夹。
-
配置文件:在 ZooKeeper 安装目录下,找到
conf
文件夹,并复制zoo_sample.cfg
文件为zoo.cfg
。 -
编辑配置文件:使用文本编辑器打开
zoo.cfg
文件,配置 ZooKeeper 的相关参数,如端口号、数据目录等。确保dataDir
配置为合适的数据存储目录。
启动 ZooKeeper
-
启动服务:使用命令行进入 ZooKeeper 安装目录的
bin
文件夹,并执行以下命令启动 ZooKeeper 服务:./zkServer.sh
或者在 Windows 环境下执行:zkServer.cmd
验证和管理
-
验证服务:使用 ZooKeeper 客户端命令连接到 ZooKeeper 服务器,确保服务已启动。
./zkCli.sh -server localhost:2181
如果连接成功,将会出现 ZooKeeper 命令行提示符。
-
管理和操作:通过命令行或 ZooKeeper 的 API 进行节点的创建、读取、更新和删除操作。例如:
-
创建节点:
create /myNode myData
-
读取节点:
get /myNode
-
更新节点:
set /myNode newData
-
删除节点:
delete /myNode
-
停止和关闭
在命令行中执行以下命令关闭 ZooKeeper 服务:
./zkServer.sh stop
Windows 环境下执行:
zkServer.cmd stop
4. ZooKeeper 数据模型
数据结构和层次命名空间:
-
层次命名空间:ZooKeeper 组织为层次结构,类似于文件系统的目录结构,通过路径名来表示节点。
-
znode:每个节点在层次结构中都是一个 znode,有唯一的路径标识。
节点类型和 Watcher 机制:
ZooKeeper 节点有不同的类型,包括持久节点、临时节点、持久顺序节点和临时顺序节点。Watcher 是一种事件通知机制,可在节点状态更改时接收通知。
-
节点类型:
- 持久节点(Persistent Nodes):一旦创建,持久节点会一直存在,直到显式删除。
- 临时节点(Ephemeral Nodes):与客户端会话关联,客户端断开连接时,临时节点会被删除。
- 持久顺序节点(Persistent Sequential Nodes):与持久节点类似,但节点名称末尾会附加一个数字后缀,表示创建顺序。
- 临时顺序节点(Ephemeral Sequential Nodes):与临时节点类似,节点名称末尾有数字后缀。
-
Watcher 机制:客户端可以在节点上设置 Watcher,当节点状态发生变化(例如创建、删除、数据更新等)时,ZooKeeper 将触发 Watcher 事件通知客户端。
5. 分布式锁
分布式锁是一种用于在分布式系统中控制对共享资源访问的机制。ZooKeeper可以用于实现分布式锁,其基本思想是创建一个独占节点(即只允许一个客户端拥有的节点),并利用ZooKeeper的特性来确保每个时间只有一个客户端持有这个节点。
实现分布式锁的基本步骤
- 获取锁:客户端请求ZooKeeper创建临时顺序节点。
- 检查序号:客户端获取所有子节点并按序号排序。
- 判断锁拥有者:如果当前客户端的节点序号是最小的,表示获得锁;否则,监听次小节点,等待其删除。
- 释放锁:客户端释放节点(删除节点)。
代码示例(Java)
以下是使用 ZooKeeper 实现分布式锁的基本示例代码:
import org.apache.zookeeper.*;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;public class DistributedLock {private final static String ZOOKEEPER_ADDRESS = "localhost:2181";private final static String LOCK_PATH = "/myLock";private ZooKeeper zooKeeper;private String lockPath;private CountDownLatch countDownLatch;public DistributedLock() throws IOException, InterruptedException, KeeperException {this.zooKeeper = new ZooKeeper(ZOOKEEPER_ADDRESS, 3000, null);this.lockPath = zooKeeper.create(LOCK_PATH, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);}public void lock() throws InterruptedException, KeeperException {while (true) {List<String> children = zooKeeper.getChildren("/", false);children.sort(String::compareTo);int index = children.indexOf(lockPath.substring(1));if (index == 0) {return; // 当前客户端持有最小节点,获取锁成功}String watchNode = "/" + children.get(index - 1);final CountDownLatch latch = new CountDownLatch(1);Stat stat = zooKeeper.exists(watchNode, new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent) {if (watchedEvent.getType() == Event.EventType.NodeDeleted) {latch.countDown();}}});if (stat != null) {latch.await(); // 等待次小节点删除事件}}}public void unlock() throws KeeperException, InterruptedException {zooKeeper.delete(lockPath, -1);zooKeeper.close();}public static void main(String[] args) throws IOException, InterruptedException, KeeperException {DistributedLock distributedLock = new DistributedLock();distributedLock.lock();// 执行业务逻辑distributedLock.unlock();}
}
避免死锁
- 超时机制:为获取锁设置超时时间,超过指定时间仍未获得锁,则放弃获取锁。
- 节点删除监听:监听次小节点的删除事件,避免死锁等待。
在分布式系统中实现分布式锁时,需要注意网络波动、ZooKeeper集群状态等因素,以确保锁的可靠性和稳定性。
6. 选举机制
ZooKeeper使用ZAB(ZooKeeper Atomic Broadcast)协议实现分布式一致性,并在此基础上构建了领导者选举机制。在ZooKeeper中,节点可以是领导者(Leader)、追随者(Follower)或候选者(Candidate)。
选举机制基本流程
- 初始化:启动时所有节点都是候选者。
- 投票:每个候选者在一定时间内(选举超时时间)内向其他节点发送选举请求(投票请求),请求其他节点投票给自己。
- 投票结果:收到的第一个投票节点成为领导者,其他节点成为追随者。
- 心跳:领导者定期发送心跳以维持其地位,追随者则定期接收领导者的心跳。
选举代码示例
以下是一个基本的选举场景的代码示例,演示如何使用 ZooKeeper 实现领导者选举:
import org.apache.zookeeper.*;public class LeaderElection implements Watcher {private ZooKeeper zooKeeper;private String zNode = "/election";private String currentZNode;public LeaderElection() throws Exception {this.zooKeeper = new ZooKeeper("localhost:2181", 3000, this);}public void findLeader() throws Exception {if (zooKeeper.exists(zNode, false) == null) {currentZNode = zooKeeper.create(zNode, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);}watchPreviousNode();}private void watchPreviousNode() throws Exception {String previous = null;for (String node : zooKeeper.getChildren(zNode, false)) {if (currentZNode.equals(zNode + "/" + node)) {break;}previous = node;}if (previous != null) {zooKeeper.exists(zNode + "/" + previous, this);}}@Overridepublic void process(WatchedEvent event) {switch (event.getType()) {case NodeDeleted:try {findLeader();} catch (Exception e) {e.printStackTrace();}break;}}public static void main(String[] args) throws Exception {LeaderElection leaderElection = new LeaderElection();leaderElection.findLeader();// 等待选举结果Thread.sleep(Long.MAX_VALUE);}
}
此示例中的代码模拟了候选者通过创建临时顺序节点并监视前一个节点的变化来实现领导者选举的基本过程。
ZooKeeper的选举机制可以确保系统的领导者是唯一的,并且在节点出现故障或网络问题时能够快速重新选举新的领导者,从而保障了分布式系统的可用性和稳定性。
7. 实战案例
在 Java 中使用 ZooKeeper 主要涉及到 ZooKeeper 的连接、会话管理、数据节点的创建、读取、更新和删除等操作。以下是使用 ZooKeeper 的基本步骤和示例代码:
引入 ZooKeeper 客户端依赖
在 Maven 项目中,需要在 pom.xml
文件中引入 ZooKeeper 客户端依赖
<dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.7.0</version> <!-- 版本号根据需求进行更改 -->
</dependency>
创建 ZooKeeper 连接
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.WatchedEvent;public class ZooKeeperExample {private static final String ZOOKEEPER_HOST = "localhost:2181"; // ZooKeeper服务器地址和端口号private static final int SESSION_TIMEOUT = 5000; // 会话超时时间public static void main(String[] args) throws Exception {ZooKeeper zooKeeper = new ZooKeeper(ZOOKEEPER_HOST, SESSION_TIMEOUT, new Watcher() {@Overridepublic void process(WatchedEvent event) {// 处理 ZooKeeper 事件System.out.println("Received event: " + event);}});// 等待连接成功while (zooKeeper.getState() != ZooKeeper.States.CONNECTED) {Thread.sleep(1000);}// 连接成功后的操作System.out.println("Connected to ZooKeeper");// 进行节点操作等其他业务逻辑// 例如:创建节点、读取节点、更新节点、删除节点等操作// 关闭 ZooKeeper 连接zooKeeper.close();}
}
进行节点操作
以下是节点的基本操作示例:
- 创建节点:
// 创建一个持久节点
String path = "/testNode";
byte[] data = "Hello, ZooKeeper!".getBytes();
zooKeeper.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
- 读取节点:
// 读取节点数据
Stat stat = new Stat();
byte[] nodeData = zooKeeper.getData("/testNode", false, stat);
System.out.println("Node data: " + new String(nodeData));
- 更新节点:
// 更新节点数据
String newData = "Updated data";
zooKeeper.setData("/testNode", newData.getBytes(), stat.getVersion());
- 删除节点:
// 删除节点
zooKeeper.delete("/testNode", stat.getVersion());
注意事项
- 在实际使用中,请根据需求处理异常、关闭连接等情况。
- 使用 Watcher 监听 ZooKeeper 节点的变化。
- 请注意 ZooKeeper 的一致性、可用性和分区容错性等特性。
以上代码示例仅为基础操作,实际应用中可能会涉及更多复杂的场景和功能。后面有时间会再跟大家分享一下Zookeeper选举Leader源码分析的内容
相关文章:

ZooKeeper 使用介绍和原理详解
目录 1. 介绍 重要性 应用场景 2. ZooKeeper 架构 服务角色 数据模型 工作原理 3. 安装和配置 下载 ZooKeeper 安装和配置 启动 ZooKeeper 验证和管理 停止和关闭 4. ZooKeeper 数据模型 数据结构和层次命名空间: 节点类型和 Watcher 机制ÿ…...

模式识别与机器学习(八):决策树
1.原理 决策树(Decision Tree),它是一种以树形数据结构来展示决策规则和分类结果的模型,作为一种归纳学习算法,其重点是将看似无序、杂乱的已知数据,通过某种技术手段将它们转化成可以预测未知数据的树状模…...
Pinely Round 3 (Div. 1 + Div. 2)(A~D)(有意思的题)
A - Distinct Buttons 题意: 思路:模拟从(0,0)到每个位置需要哪些操作,如果总共需要4种操作就输出NO。 // Problem: A. Distinct Buttons // Contest: Codeforces - Pinely Round 3 (Div. 1 Div. 2) // URL: https…...

在Linux下探索MinIO存储服务如何远程上传文件
🌈个人主页:聆风吟 🔥系列专栏:网络奇遇记、Cpolar杂谈 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 📋前言一. 创建Buckets和Access Keys二. Linux 安装Cpolar三. 创建连接MinIO服务公网地…...

持续集成交付CICD:Linux 部署 Jira 9.12.1
目录 一、实验 1.环境 2.K8S master节点部署Jira 3.Jira 初始化设置 4.Jira 使用 一、实验 1.环境 (1)主机 表1 主机 主机架构版本IP备注master1K8S master节点1.20.6192.168.204.180 jenkins slave (从节点) jira9.12.1…...

Linux命令-查看内存、GC情况及jmap 用法
查看进程占用内存、CPU使用情况 1、查看进程 #jps 查看所有java进程 #top 查看cpu占用高进程 输入m :根据内存排序 topMem: 16333644k total, 9472968k used, 6860676k free, 165616k buffers Swap: 0k total, 0k used, 0k free, 6…...

nginx安装letsencrypt证书
1.安装推荐安装letsencrypt证书的客户端工具 官方推荐通过cerbot客户端安装letsencrypt 官方推荐使用snap客户端安装cerbot客户端 apt install snapd snap install --classic certbot 建立certbot软链接:ln -s /snap/bin/certbot /usr/bin/certbot 2.开始安装letse…...

docker笔记1-安装与基础命令
docker的用途: 可以把应用程序代码及运行依赖环境打包成镜像,作为交付介质,在各种环境部署。可以将镜像(image)启动成容器(container),并提供多容器的生命周期进行管理(…...

VSCode软件与SCL编程
原创 NingChao NCLib 博途工控人平时在哪里技术交流博途工控人社群 VSCode简称VSC,是Visual studio code的缩写,是由微软开发的跨平台的轻量级编辑器,支持几乎所有主流的开发语言的语法高亮、代码智能补全、插件扩展、代码对比等,…...

Opencv中的滤波器
一副图像通过滤波器得到另一张图像,其中滤波器又称为卷积核,滤波的过程称之为卷积。 这就是一个卷积的过程,通过一个卷积核得到另一张图片,明显发现新的到的图片边缘部分更加清晰了(锐化)。 上图就是一个卷…...

<JavaEE> 基于 TCP 的 Socket 通信模型
目录 一、认识相关API 1)ServerSocket 2)Socket 二、TCP字节流套接字通信模型概述 三、回显客户端-服务器 1)服务器代码 2)客户端代码 一、认识相关API 1)ServerSocket ServerSocket 常用构造方法ServerSocke…...

[THUPC 2024 初赛] 二进制 (树状数组单点删除+单点查询)(双堆模拟set)
题解 题目本身不难想 首先注意到所有查询的序列长度都是小于logn级别的 我们可以枚举序列长度len,然后用类似滑动窗口的方法,一次性预处理出每种字串的所有出现位置,也就是开N个set去维护所有的位置。预处理会进行O(logn)轮,每…...

机器学习算法(11)——集成技术(Boosting——梯度提升)
一、说明 在在这篇文章中,我们学习了另一种称为梯度增强的集成技术。这是我在机器学习算法集成技术文章系列中与bagging一起介绍的一种增强技术。我还讨论了随机森林和 AdaBoost 算法。但在这里我们讨论的是梯度提升,在我们深入研究梯度提升之前…...

使用GBASE南大通用负载均衡连接池
若要使用负载均衡连接池功能,需要在连接串中配置相关的关键字。有关更详细的关键字信息在 GBASE南大通用 连接参数表‛中介绍。假设存在如下场景: 现有集群中存在 4 个节点: 192.168.9.173, 192.168.9.174, 192.168.9.175, 192.168.9.17…...

Flink 数据序列化
为 Flink 量身定制的序列化框架 大家都知道现在大数据生态非常火,大多数技术组件都是运行在JVM上的,Flink也是运行在JVM上,基于JVM的数据分析引擎都需要将大量的数据存储在内存中,这就不得不面临JVM的一些问题,比如Ja…...

【并发设计模式】聊聊两阶段终止模式如何优雅终止线程
在软件设计中,抽象出了23种设计模式,用以解决对象的创建、组合、使用三种场景。在并发编程中,针对线程的操作,也抽象出对应的并发设计模式。 两阶段终止模式- 优雅停止线程避免共享的设计模式- 只读、Copy-on-write、Thread-Spec…...

Java实现非对称加密【详解】
Java实现非对称加密 1. 简介2. 非对称加密算法--DH(密钥交换)3. 非对称加密算法--RSA非对称加密算法--EIGamal5. 总结6 案例6.1 案例16.2 案例2 1. 简介 公开密钥密码学(英语:Public-key cryptography)也称非对称式密…...

simulinkveristandlabview联合仿真——模型导入搭建人机界面
目录 1.软件版本 2.搭建simulink仿真模型 编译错误 3.导入veristand并建立工程 4.veristand导入labview labview显示veristand工程数据 labview设置veristand工程数据 运行labview工程 1.软件版本 matlab2020a,veristand2020 R4,labview2020 SP…...

k8s中Helm工具实践
k8s中Helm工具实践 1)安装redis-cluster 先搭建一个NFS的SC(只需要SC,不需要pvc),具体步骤此文档不再提供,请参考前面相关章节。 下载redis-cluster的chart包 helm pull bitnami/redis-cluster --untar…...

推荐算法架构7:特征工程(吊打面试官,史上最全!)
系列文章,请多关注 推荐算法架构1:召回 推荐算法架构2:粗排 推荐算法架构3:精排 推荐算法架构4:重排 推荐算法架构5:全链路专项优化 推荐算法架构6:数据样本 推荐算法架构7:特…...

Web前端 ---- 【Vue】vue路由守卫(全局前置路由守卫、全局后置路由守卫、局部路由path守卫、局部路由component守卫)
目录 前言 全局前置路由守卫 全局后置路由守卫 局部路由守卫之path守卫 局部路由守卫之component守卫 前言 本文介绍Vue2最后的知识点,关于vue的路由守卫。也就是鉴权,不是所有的组件任何人都可以访问到的,需要权限,而根据权限…...

uniapp点击tabbar之前做判断
在UniApp中,可以通过监听 tabBar 的 click 事件来在点击 tabBar 前做判断。具体步骤如下: 在 pages.json 文件中配置 tabBar,例如: {"pages":[{"path":"pages/home/home","name":"h…...

DLLNotFoundException:xxx tolua... 错误打印
DLLNotFoundException:xxx tolua... 错误打印 一、DLLNotFoundException介绍二、Plugins文件夹文件目录结构如下: 三、Plugins中的Android文件夹四、Plugins中的IOS文件夹这里不说了没测试过不过原理应该也是选择对应的平台即可五、Plugins中的x86和X86_64文件夹 一…...

Python量化投资——金融数据最佳实践: 使用qteasy+tushare搭建本地金融数据仓库并定期批量更新【附源码】
用qteasytushare实现金融数据本地化存储及访问 目的什么是qteasy什么是tushare为什么要本地化使用qteasy创建本地数据仓库qteasy支持的几种本地化仓库类型配置本地数据仓库配置tushare 的API token 配置本地数据源 —— 用MySQL数据库作为本地数据源下载金融历史数据 数据的定期…...

【投稿】北海 - Rust与面向对象(二)
模板方法 Rust提供了trait,类似于面向对象的接口,不同的是,将传统面向对象的虚函数表从对象中分离出来,trait仍然是一个函数表,只不过是独立的,它的参数self指针可以指向任何实现了该trait的结构。 从对象中…...

HarmonyOS构建第一个ArkTS应用(FA模型)
构建第一个ArkTS应用(FA模型) 创建ArkTS工程 若首次打开DevEco Studio,请点击Create Project创建工程。如果已经打开了一个工程,请在菜单栏选择File > New > Create Project来创建一个新工程。 选择Application应用开发&a…...

阿里云 ARMS 应用监控重磅支持 Java 21
作者:牧思 & 山猎 前言 今年的 9 月 19 日,作为最新的 LTS (Long Term Support) Java 版本,Java 21 正式 GA,带来了不少重量级的更新,详情请参考 The Arrival of Java 21 [ 1] 。虽然目前 Java 11 和 Java 17 都…...

C++ 类的析构函数和构造函数
构造函数 类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。主要用来在创建对象时初始化对象即为对象成员变量赋初始值。 构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用…...

STM32——CAN协议
文章目录 一.CAN协议的基本特点1.1 特点1.2 电平标准1.3 基本的五个帧1.4 数据帧 二.数据帧解析2.1 帧起始和仲裁段2.2 控制段2.3 数据段和CRC段2.4 ACK段和帧结束 三.总线仲裁四.位时序五.STM32CAN控制器原理与配置5.1 STM32CAN控制器介绍5.2 CAN的模式5.3 CAN框图 六 手册寄存…...

数据结构-如何巧妙实现一个栈?逐步解析与代码示例
文章目录 引言1.栈的基本概念2.选择数组还是链表?3. 定义栈结构4.初始化栈5.压栈操作6.弹栈操作7.查看栈顶和判断栈空9.销毁栈操作10.测试并且打印栈内容栈的实际应用结论 引言 栈是一种基本但强大的数据结构,它在许多算法和系统功能中扮演着关键角色。…...