数据结构:栈和队列与栈实现队列(C语言版)

目录

前言

1.栈

1.1 栈的概念及结构

1.2 栈的底层数据结构选择

1.2 数据结构设计代码(栈的实现)

1.3 接口函数实现代码

(1)初始化栈

(2)销毁栈

(3)压栈

(4)出栈

(5)获取栈顶元素

(6)获取栈中有效元素的个数

(7)检测栈是否为空

1.4 测试函数

2. 队列

2.1 队列概念及结构

2.2 队列的底层数据结构的选择

2.2 数据结构设计代码(队列的实现)

2.3 接口函数

(1)初始化队列

(2)销毁队列

(3)队尾入队列

(4)队头出队列

(5)获取队列头部元素

(6)获取队列尾部元素

(7)获取队列中有效元素个数

(8)检测队列是否为空

2.4 测试函数

3. 栈和队列的源代码

3.1 栈

(1)Stack.h

(2)Stack.c

(3)STtest.c

3.2 队列

(1)Queue.h

(2)Queue.c

(3)Qtest.c

总结


前言

这篇文章是关于栈和队列的C语言实现,干货满满,大家可以边看边手写代码,最后附上栈和队列的参考代码。


1.栈

1.1 栈的概念及结构

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈:栈的删除操作叫做出栈。出数据也在栈顶

这个数据结构可以理解为炸串。在最开始,插入丸子时,要插到这根签的最底部,就是入栈。开始吃的时候,一般从最上面的丸子入手,就是出栈

 

1.2 栈的底层数据结构选择

我们学过顺序表和链表两种数据结构,用那种会更好呢?

  • 相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。不用挪动数据,删除操作也很简单。
  • 而链表如果要入栈,就是链表的尾插,我们需要找到链表的尾结点,效率低。出栈也是一样。

1.2 数据结构设计代码(栈的实现)

在用C语言实现栈各种接口函数,需要创建三个文件,分别是STtest.c,Stack.c和Stack.h。

  • STtest.c文件用来测试接口函数是否能成功。
  • Stack.c文件里面放的是各种接口函数实现的代码
  • Stack.h文件放置各种头文件的声明,栈数据结构的设计和接口函数的声明。下面的代码就是放在此文件中。
typedef int STDataType;
// 下面是定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈
typedef int STDataType;
#define N 10
typedef struct Stack
{STDataType _a[N];int _top; // 栈顶
}Stack;// 支持动态增长的栈
typedef struct Stack
{STDataType* a;int top;      //栈顶int capacity; //容量
}ST;//初始化栈
void StackInit(ST* ps);
//销毁栈
void StackDestroy(ST* ps);
//压栈
void StackPush(ST* ps, STDataType x);
//出栈
void StackPop(ST* ps);
//获取栈顶元素
STDataType StackTop(ST* ps);
//获取栈中有效元素个数
int StackSize(ST* ps);
//检测栈是否为空,为空返回true
bool StackEmpty(ST* ps);

1.3 接口函数实现代码

(1)初始化栈

初始化栈一开始要断言,断言来判断ps指针是否为空,如果为空会直接终止程序并给出提示,方便之后的调试,之后的断言不再赘述。指针指向空,内部整型数据赋值为0。但是top得注意,top其实也是个下标。看下面的注释,top可以有两种赋值方式,只是表示不同意思。

void StackInit(ST* ps)
{assert(ps);ps->a = NULL;ps->top = 0;//表示指向栈顶的下一个元素//ps->top = -1 ///表示指向栈顶元素ps->capacity = 0;
}

(2)销毁栈

因为我们是以数组为基础,是动态开辟的连续空间,直接释放掉ps中的数组指针,并要置为空。

void StackDestroy(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;//易错ps->top = ps->capacity = 0;
}

(3)压栈

栈的压栈操作跟顺序表的尾插类似,先要检查内部空间容量是否足够,一开始给四个该数据结构的空间,之后的按两倍来扩容。最后就是插入数据,栈顶减一。

void StackPush(ST* ps, STDataType x)
{assert(ps);if (ps->top == ps->capacity){int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);if (tmp == NULL){printf("realloc fail\n");exit(-1);}ps->a = tmp;ps->capacity = newCapacity;}ps->a[ps->top] = x;ps->top++;
}

(4)出栈

这次不仅要判断ps是否不为空指针,还要判断栈内是否有元素,这样才可以删除元素,让栈顶减一即可。

void StackPop(ST* ps)
{assert(ps);assert(!StackEmpty(ps));ps->top--;
}

(5)获取栈顶元素

这里的判断跟上个接口函数一样,只有栈内有元素,才能取栈顶元素。

STDataType StackTop(ST* ps)
{assert(ps);assert(!StackEmpty(ps));return ps->a[ps->top - 1];
}

(6)获取栈中有效元素的个数

此时的top表示的是栈顶的下一个元素的下标,刚好就是元素个数,直接返回栈顶top

int StackSize(ST* ps)
{assert(ps);return ps->top;
}

(7)检测栈是否为空

很多人会写个if语句判断,其实可以直接像下面一样写,ps->top == 0变成一个判断语句,如果为真返回一个部位0的数,如果为假返回0。

bool StackEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}

1.4 测试函数

我们写两个测试函数,第一个测试函数,是出栈和入栈的操作,可以调试查看。第二个测试函数是栈的数据打印,需要使用StackTop获取栈顶元素,然后将打印的数据出栈。

void TestStack1()
{ST st;StackInit(&st);StackPush(&st, 1);StackPush(&st, 2);StackPush(&st, 3);StackPush(&st, 4);StackPop(&st);StackPop(&st);StackPop(&st);StackPop(&st);StackPop(&st);StackDestroy(&st);
}void TestStack2()
{ST st;StackInit(&st);StackPush(&st, 1);StackPush(&st, 2);StackPush(&st, 3);StackPush(&st, 4);while (!StackEmpty(&st)){printf("%d ", StackTop(&st));StackPop(&st);}StackDestroy(&st);
}int main()
{TestStack1();TestStack2();return 0;
}

输出结果:

2. 队列

2.1 队列概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)

入队列:进行插入操作的一端称为队尾

出队列:进行删除操作的一端称为队头

 这个数据结构可以理解为在银行取号,先取号的人,就是入队列。然后先取到号的人,就先去窗口处理业务,这就是出队列。

2.2 队列的底层数据结构的选择

跟栈一样,队列也可以用顺序表和链表来实现,那哪一个更好呢?

  • 相较于数组,使用链表更优一些。队列的入队和出队,分别是链表的尾插和头删,不过我们会创建两个指针指向头结点和尾结点,所以不会有时间的消耗。
  • 而数组在头部插入和删除数据,都要挪动数据,效率较低。

链表的数据结构存储的是一个数据变量,和指向下一个结点的指针变量。我们入队列和出队列分别在队尾和队头,所以我们在队列的数据结构定义两个链表的指针变量head和tail,表示队头和队尾

2.2 数据结构设计代码(队列的实现)

跟栈的实现一样,首先要创建三个文件Qtest.c,Queue.c和Queue.h。

  • Qtest.c文件用来测试接口函数是否能成功。
  • Queue.c文件里面放的是各种接口函数实现的代码
  • Queue.h文件放置各种头文件的声明,栈数据结构的设计和接口函数的声明。下面的代码就是放在此文件中。
// 链式结构:表示队列
typedef int QDataType;
typedef struct QueueNode
{struct QueueNode* next;QDataType data;
}QueueNode;// 队列的结构
typedef struct Queue
{QueueNode* head;QueueNode* tail;
}Queue;//初始化队列
void QueueInit(Queue* pq); 
//销毁队列
void QueueDestroy(Queue* pq);
//队尾入队列
void QueuePush(Queue* pq, QDataType x);
//队头出队列
void QueuePop(Queue* pq);
//获取队列头部元素
QDataType QueueFront(Queue* pq);
//获取队列尾部元素
QDataType QueueBack(Queue* pq);
//获取队列中有效元素个数
int QueueSize(Queue* pq);
//检测队列是否为空,如果为空返回true
bool QueueEmpty(Queue* pq);

2.3 接口函数

(1)初始化队列

队列初始化,只需要将队头链表指针和队尾链表指针置为空指针就好。

void QueueInit(Queue* pq)
{assert(pq);pq->head = NULL;pq->tail = NULL;
}

(2)销毁队列

因为是以链表为基础,需要用while循环释放掉每一个动态开辟的结点。

void QueueDestroy(Queue* pq)
{assert(pq);QueueNode* cur = pq->head;while (cur != NULL){QueueNode* next = cur->next;free(cur);cur = next;}pq->head = pq->tail = NULL;
}

(3)队尾入队列

队尾入队列就是链表的尾插,但是我们有tail指针,直接在tail后面插入就好。不过需要分是否为空队列两种情况,如果是空队列,head和tail指针都指向新结点,如果不是空队列,在tail之后插入。

void QueuePush(Queue* pq, QDataType x)
{assert(pq);QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));if (newnode == NULL){perror("Queue malloc fail");return;}newnode->data = x;newnode->next = NULL;if (pq->head == NULL){pq->head = pq->tail = newnode;}else{pq->tail->next = newnode;pq->tail = newnode;}
}

(4)队头出队列

在操作之前,我们需要判断队列是否有元素。然后在释放第一个结点,改变指针指向。

void QueuePop(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));QueueNode* next = pq->head->next;free(pq->head);pq->head = next;
}

(5)获取队列头部元素

QDataType QueueFront(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->head->data;
}

(6)获取队列尾部元素

QDataType QueueBack(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;
}

(7)获取队列中有效元素个数

这需要一个计数变量。

int QueueSize(Queue* pq)
{assert(pq);int n = 0;QueueNode* cur = pq->head;while (cur){n++;cur = cur->next;}return n;
}

(8)检测队列是否为空

跟栈判空相同。

bool QueueEmpty(Queue* pq)
{assert(pq);return pq->head == NULL;
}

2.4 测试函数

写两个测试函数,第一是入队列和出队列的操作,可以一步一步调试看情况。第二个测试函数,是打印队列里的数据,现获取队头的数据,然后再出队。

void TestQueue1()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);QueuePop(&q);QueuePop(&q);QueuePop(&q);QueuePop(&q);printf("%d\n", QueueBack(&q));QueueDestroy(&q);
}void TestQueue2()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);while (!QueueEmpty(&q)){QDataType front = QueueFront(&q);printf("%d ", front);QueuePop(&q);}printf("\n");
}int main()
{TestQueue1();TestQueue2();return 0;
}

输出的结果:

3. 栈和队列的源代码

3.1 栈

(1)Stack.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>typedef int STDataType;下面是定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈
//typedef int STDataType;
//#define N 10
//typedef struct Stack
//{
//	STDataType _a[N];
//	int _top; // 栈顶
//}Stack;// 支持动态增长的栈
typedef struct Stack
{STDataType* a;int top;      //栈顶int capacity; //容量
}ST;
//初始化栈
void StackInit(ST* ps);
//销毁栈
void StackDestroy(ST* ps);
//压栈
void StackPush(ST* ps, STDataType x);
//出栈
void StackPop(ST* ps);
//获取栈顶元素
STDataType StackTop(ST* ps);
//获取栈中有效元素个数
int StackSize(ST* ps);
//检测栈是否为空,为空返回true
bool StackEmpty(ST* ps);

(2)Stack.c

#include "Stack.h"void StackInit(ST* ps)
{assert(ps);ps->a = NULL;ps->top = 0;//ps->top = -1ps->capacity = 0;
}void StackDestroy(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}void StackPush(ST* ps, STDataType x)
{assert(ps);if (ps->top == ps->capacity){int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);if (tmp == NULL){printf("realloc fail\n");exit(-1);}ps->a = tmp;ps->capacity = newCapacity;}ps->a[ps->top] = x;ps->top++;
}void StackPop(ST* ps)
{assert(ps);assert(!StackEmpty(ps));ps->top--;
}STDataType StackTop(ST* ps)
{assert(ps);assert(!StackEmpty(ps));return ps->a[ps->top - 1];
}int StackSize(ST* ps)
{assert(ps);return ps->top;
}bool StackEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}

(3)STtest.c

#include "Stack.h"void TestStack1()
{ST st;StackInit(&st);StackPush(&st, 1);StackPush(&st, 2);StackPush(&st, 3);StackPush(&st, 4);StackPop(&st);StackPop(&st);StackPop(&st);StackPop(&st);StackPop(&st);StackDestroy(&st);
}void TestStack2()
{ST st;StackInit(&st);StackPush(&st, 1);StackPush(&st, 2);StackPush(&st, 3);StackPush(&st, 4);//printf("%d ", StackTop(&st));//StackPop(&st);//printf("%d ", StackTop(&st));//StackPop(&st);//StackPush(&st, 5);//StackPush(&st, 6);while (!StackEmpty(&st)){printf("%d ", StackTop(&st));StackPop(&st);}StackDestroy(&st);
}int main()
{TestStack1();//TestStack2();return 0;
}

3.2 队列

(1)Queue.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>// 链式结构:表示队列
typedef int QDataType;
typedef struct QueueNode
{struct QueueNode* next;QDataType data;
}QueueNode;// 队列的结构
typedef struct Queue
{QueueNode* head;QueueNode* tail;
}Queue;//初始化队列
void QueueInit(Queue* pq); 
//销毁队列
void QueueDestroy(Queue* pq);
//队尾入队列
void QueuePush(Queue* pq, QDataType x);
//队头出队列
void QueuePop(Queue* pq);
//获取队列头部元素
QDataType QueueFront(Queue* pq);
//获取队列尾部元素
QDataType QueueBack(Queue* pq);
//获取队列中有效元素个数
int QueueSize(Queue* pq);
//检测队列是否为空,如果为空返回true
bool QueueEmpty(Queue* pq);

(2)Queue.c

#include "Queue.h"void QueueInit(Queue* pq)
{assert(pq);pq->head = NULL;pq->tail = NULL;
}void QueueDestroy(Queue* pq)
{assert(pq);QueueNode* cur = pq->head;while (cur != NULL){QueueNode* next = cur->next;free(cur);cur = next;}pq->head = pq->tail = NULL;
}void QueuePush(Queue* pq, QDataType x)
{assert(pq);QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));if (newnode == NULL){perror("Queue malloc fail");return;}newnode->data = x;newnode->next = NULL;if (pq->head == NULL){pq->head = pq->tail = newnode;}else{pq->tail->next = newnode;pq->tail = newnode;}
}void QueuePop(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));QueueNode* next = pq->head->next;free(pq->head);pq->head = next;
}QDataType QueueFront(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->head->data;
}QDataType QueueBack(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;
}int QueueSize(Queue* pq)
{assert(pq);int n = 0;QueueNode* cur = pq->head;while (cur){n++;cur = cur->next;}return n;
}bool QueueEmpty(Queue* pq)
{assert(pq);return pq->head == NULL;
}

(3)Qtest.c

void TestQueue1()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);QueuePop(&q);QueuePop(&q);QueuePop(&q);QueuePop(&q);printf("%d\n", QueueBack(&q));QueueDestroy(&q);
}void TestQueue2()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);while (!QueueEmpty(&q)){QDataType front = QueueFront(&q);printf("%d ", front);QueuePop(&q);}printf("\n");
}int main()
{//TestQueue1();TestQueue2();return 0;
}

 


总结

栈和队列的实现其实相较于链表的实现简单一些,是因为其结构的特殊要求。之后会出一篇关于栈和队列的OJ题目。多多重复,百炼成钢!

创作不易,希望这篇文章能给你带来启发和帮助,如果喜欢这篇文章,请留下你的三连,你的支持的我最大的动力!!!

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

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

相关文章

代码随想录算法训练营第27天—贪心算法01 | ● 理论基础 ● 455.分发饼干 ● 376. 摆动序列 ● 53. 最大子序和

理论基础 https://programmercarl.com/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 贪心算法的本质&#xff1a;由局部最优推到全局最优贪心算法的套路&#xff1a;无固定套路 455.分发饼干 https://programmercarl.com/0455.%E5%88%8…

前端面试题(一)

1、说一下vue生命周期 什么是生命周期 Vue 实例从创建到销毁的过程就是生命周期。从开始创建&#xff0c;初始化数据&#xff0c;编译模板&#xff0c;挂载 Dom 到渲染&#xff0c;更新到渲染&#xff0c;销毁等一系列过程&#xff0c;称之为生命周期。 Vue生命周期共有8个阶…

【毕业设计推荐】基于MATLAB的水果分级系统设计与实现

一、课题介绍 现在商业行为中&#xff0c;在水果出厂前都需要进行质量检测&#xff0c;需要将不同等级的水果进行分级包装&#xff0c;以保证商业利益最大化。可是传统方法都是依靠人工进行检测&#xff0c;效率低下&#xff0c;主观成分大&#xff0c;并不能很好客观地评价出货…

流畅的Python(十四)-可迭代对象、迭代器和生成器

一、核心要义 1. 使用iter内置函数处理可迭代对象的方式 2. 如何使用Python实现经典的迭代器模式 3. 生成器函数工作原理 4. 使用生成器函数或生成器表达式代替经典的迭代器 5. 使用yield from语句合并生成器 二、代码示例 1、遍历单词序列回顾 #!/usr/bin/env python …

电脑WiFi共享给电脑的网口,另一终端可通过该网口进行上网。可用于wireshark抓设备终端的包。

1、点击WinR&#xff0c;弹出命令框&#xff0c;输入services.msc 2、选中“Internet Connection Sharing”这个服务右键&#xff0c;点击属性打开&#xff0c;启动类型选择“自动”&#xff0c;确定保存 3、点击WinR&#xff0c;弹出命令框&#xff0c;输入regedit 4、找到路径…

Qt中的QGraphicView和QGraphicScene简单使用

概述&#xff1a;我们利用QGraphicView和QGraphicScene来实现一个简单的视频播放器&#xff0c;然后上面悬浮一些操作的控件&#xff0c;看看怎么来实现。 1、CcTestVideoPlayer类 模拟播放器类&#xff0c;继承QGraphicScene 1.1 CcTestVideoPlayer.h #pragma once#include…

【ArcGIS】重采样栅格像元匹配问题:不同空间分辨率栅格数据统一

重采样栅格像元匹配问题&#xff1a;不同空间分辨率栅格数据统一 原始数据数据1&#xff1a;GDP分布数据2.1&#xff1a;人口密度数据2.2&#xff1a;人口总数数据3&#xff1a;土地利用类型 数据处理操作1&#xff1a;将人口密度数据投影至GDP数据&#xff08;栅格数据的投影变…

LVS做集群四层负载均衡的简单理解

背景&#xff1a;业务中主要是TCP/SSL连接&#xff0c;要做四层负载均衡。 之前做负载均衡&#xff0c;调研了nginx&#xff08;见之前的nginx实现后端服务负载均衡和nginx负载均衡监测后台服务状态&#xff09;。 nginx作为一个应用&#xff0c;做四层负载均衡效率低。lvs是li…

非同质化权益(NFR):重塑数字资产权益的生态系统

每天五分钟讲解一个互联网知识&#xff0c;大家好我是啊浩 随着区块链技术的深入发展和普及&#xff0c;数字资产已经逐渐渗透到我们生活的方方面面。在这一背景下&#xff0c;非同质化权益&#xff08;NFR&#xff09;作为一种新型的数字资产形式&#xff0c;不仅为数字资产权…

eBPF实践篇之环境搭建

文章目录 前言实验环境前置知识配置开发环境最后 前言 你好&#xff0c;我是醉墨居士&#xff0c;本次我们学习一下eBPF&#xff0c;我们基于libbpf-bootstrap来进行我们的eBPF程序开发&#x1f917; 实验环境 一台Debian12操作系统的计算机&#xff0c;我使用的是Debian12.…

什么是索引?它们在MySQL中是如何工作的?什么是视图(View)?它们有什么用?

什么是索引&#xff1f;它们在MySQL中是如何工作的&#xff1f; 索引在MySQL中是一个数据结构&#xff0c;它帮助快速查询数据库中的数据。没有索引&#xff0c;查询可能需要遍历整个数据库表&#xff0c;这称为全表扫描&#xff0c;对于大型表来说非常慢。 索引的工作原理是创…

SpringBoot案例(黑马学习笔记)

这个案例呢&#xff0c;就是Tlias智能学习辅助系统。 参考接口文档完成后端功能的开 发&#xff0c;然后结合前端工程进行联调测试即可。 完成后的成品效果展示&#xff1a; 准备工作 需求&环境搭建 需求说明 部门管理 部门管理功能开发包括&#xff1a; ● 查询部门列…

亚信安慧AntDB数据库与流式处理的有机融合

流式处理的概念 2001年9月11日&#xff0c;美国世贸大楼被袭击&#xff0c;美国国防部第一次将“主动预警”纳入国防的宏观战略规划。而IBM作为当时全球最大的IT公司&#xff0c;承担了大量基础支撑软件研发的任务。其中2009年正式发布的IBM InfoSphere Streams&#xff0c;就是…

杰理-按键多次按下识别多击

杰理-按键多次按下识别多击 #define ALL_KEY_EVENT_CLICK_ONLY 0 //是否全部按键只响应单击事件

自动化测试高效学习路线指导,提高你百倍自学效率

前言 从各方来的朋友&#xff0c;能够相聚这篇文章是大家的缘分&#xff0c;也是我的荣幸。 接下来&#xff0c;我要开始和大家讲讲如何从0开始学Python自动化测试。 不论是转行自动化测试还是功能测试进阶自动化还是开发转自动化测试的伙伴&#xff0c;这篇自动化测试工程师…

Zookeeper客户端命令、JAVA API、监听原理、写数据原理以及案例

1. Zookeeper节点信息 指定服务端&#xff0c;启动客户端命令&#xff1a; bin/zkCli.sh -server 服务端主机名:端口号 1&#xff09;ls / 查看根节点下面的子节点 ls -s / 查看根节点下面的子节点以及根节点详细信息 其中&#xff0c;cZxid是创建节点的事务id&#xff0c…

Rocky Linux 运维工具 firewall-cmd

一、firewall-cmd​的简介 ​​firewall-cmd​是基于firewalld的防火墙管理工具。用户可以使用它来配置、监控和管理防火墙规则&#xff0c;包括开放端口、设置服务规则等。 二、firewall-cmd​​的参数说明 序号参数描述1​​–zone指定防火墙区域2–add-portxxx/tcp允许特定…

tkinterFrame框架+标签框架LabelFrame+Toplevel窗口的使用

1.在tkinter中&#xff0c;Frame是一个容器小部件用于组织和管理其他小部件。它可以作为一个独立的可见区域&#xff0c;也可以作为其他小部件的父容器。 import tkinter as tk import tkinter.ttk as ttk import tkinter.messagebox as mbm tk.Tk() m.title("tkinter L…

MSSQL渗透测试

目录 mssql数据库连接提权至服务器权限 拿到目标的IP地址&#xff0c;我们先对IP地址进行信息收集&#xff0c;收集信息资产&#xff0c;同时使用nmap对IP地址进行扫描 nmap -sC -sV IP从扫描的结果中&#xff0c;我们能知道目标服务器是windows操作系统&#xff0c;使用的是m…

DAY10-内容安全过滤技术概述

文件过滤技术流程: 应用行为控制技术具体: