C语言实现数据结构之队列

news2024/12/21 21:50:14

目录

  • 队列
    • 一. 队列的概念及结构
    • 二. 队列的实现
      • 1. 要实现的功能
      • 2 具体的实现
        • 2.1 结构体
        • 2.2 初始化
        • 2.3 入队列
        • 2.4 出队列
        • 2.5 返回队首元素
        • 2.6 返回队尾元素
        • 2.7 队列元素个数
        • 2.8 队列判空
        • 2.9 队列销毁
    • 三. 队列相关OJ题
      • 设计循环队列
      • 用队列实现栈
      • 用栈实现队列
    • 四. 概念选择题
    • 五. 参考代码
      • Queue.h
      • Queue.c
      • test.c

队列

一. 队列的概念及结构

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

二. 队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
入队列与出队列

1. 要实现的功能

// 链式结构:表示队列
typedef struct QListNode
{
struct QListNode* _pNext;
QDataType _data;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* _front;
QNode* _rear;
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);

另外扩展了解一下,实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。环形队列可以使用数组实现,也可以使用循环链表实现。
循环队列

2 具体的实现

本次队列的实现我们基于双向链表

2.1 结构体

为了适配多种数据类型,这里使用typedef对数据类型进行重命名,便于进行统一修改。
由于链表QueueNode的节点只含有next指针和值,所以我们额外定义一个结构体Queue记录下链表的头和尾,便于快速进行相关操作。

typedef int QDataType;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType val;
}QNode;

typedef struct Queue
{
	QNode* phead; 
	QNode* ptail;
	int size;
}Queue;
2.2 初始化

初始化将记录的头和尾置空,元素个数置空

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}
2.3 入队列

入队列创建一个新节点,并放在记录好的尾节点的位置之后,成为新的尾节点,最后元素个数增加。

void QueuePush(Queue* pq, QDataType x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc failed");
		exit(1);
	}

	newnode->next = NULL;
	newnode->val = x;

	if (pq->ptail == NULL)
	{
		pq->phead = newnode;
		pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}
2.4 出队列

出队列释放掉第一个节点(头节点),然后让第二个节点成为新的头节点,最后元素个数减少。

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->size);

	QNode* next = pq->phead->next;
	free(pq->phead);
	pq->phead = next;

	if (pq->phead == NULL)//just one node
	{
		pq->ptail = NULL;
	}

	pq->size--;
}
2.5 返回队首元素

返回我们记录的头节点的值即可。

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->phead->val;
}
2.6 返回队尾元素

返回我们记录的尾节点的值即可。

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->ptail);
	return pq->ptail->val;
}
2.7 队列元素个数

返回我们记录的元素个数即可。

int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}
2.8 队列判空

返回我们记录的元素个数是否为零。

_Bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}
2.9 队列销毁

类似于单链表的销毁,依次销毁每一个节点后将头尾置空,将元素个数置空。

void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* pcur = pq->phead;
	while (pcur)
	{
		QNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

三. 队列相关OJ题

设计循环队列

题目链接:设计循环队列
循环队列

//顺序表
typedef struct 
{
    int* a;
    int head;
    int tail;
    int k;    
} MyCircularQueue;

bool myCircularQueueIsEmpty(MyCircularQueue* obj);
bool myCircularQueueIsFull(MyCircularQueue* obj);

MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue* pq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));

    //多开辟一个空间解决假溢出问题
    pq->a = malloc(sizeof(int) * (k + 1));
    pq->head = 0;
    pq->tail = 0;
    pq->k = k;

    return pq;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    obj->a[obj->tail] = value;
    obj->tail++;

    obj->tail %= (obj->k + 1);
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }   
    obj->head++;
    obj->head %= obj->k + 1;

    return true;
}

int myCircularQueueFront(MyCircularQueue* obj)
{
    if(myCircularQueueIsEmpty(obj))
    {
        return EOF;
    }
    else
    {
        return obj->a[obj->head];
    }   
}

int myCircularQueueRear(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return EOF;
    }
    else
    {
        //return obj->tail == 0 ? obj->a[obj->k] : obj->a[obj->tail - 1];
        //return obj->a[(obj->tail - 1 + obj->k + 1) % (obj->k + 1)];
        return obj->a[(obj->tail + obj->k) % (obj->k + 1)];
    }
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return obj->head == obj->tail;    
}

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    return (obj->tail + 1) % (obj->k + 1) == obj->head;    
}

void myCircularQueueFree(MyCircularQueue* obj) 
{
    free(obj->a);
    free(obj);
}

/**
 * Your MyCircularQueue struct will be instantiated and called as such:
 * MyCircularQueue* obj = myCircularQueueCreate(k);
 * bool param_1 = myCircularQueueEnQueue(obj, value);
 
 * bool param_2 = myCircularQueueDeQueue(obj);
 
 * int param_3 = myCircularQueueFront(obj);
 
 * int param_4 = myCircularQueueRear(obj);
 
 * bool param_5 = myCircularQueueIsEmpty(obj);
 
 * bool param_6 = myCircularQueueIsFull(obj);
 
 * myCircularQueueFree(obj);
*/

用队列实现栈

题目链接:用队列实现栈

typedef int QDataType;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType val;
}QNode;

typedef struct Queue
{
	QNode* phead; 
	QNode* ptail;
	int size;
}Queue;

队尾插入
//void QueuePush(QNode** pphead, QNode** pptail, QDataType x);
//
队头删除
//void QueuePop(QNode** pphead, QNode** pptail);

//初始化
void QueueInit(Queue* pq);

//队尾插入
void QueuePush(Queue* pq, QDataType x);

//队头删除
void QueuePop(Queue* pq);

//取队头数据
QDataType QueueFront(Queue* pq);

//取队尾数据
QDataType QueueBack(Queue* pq);

//队列元素个数
int QueueSize(Queue* pq);

//判空
_Bool QueueEmpty(Queue* pq);

//队列的销毁
void QueueDestroy(Queue* pq);

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

void QueuePush(Queue* pq, QDataType x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc failed");
		exit(1);
	}

	newnode->next = NULL;
	newnode->val = x;

	if (pq->ptail == NULL)
	{
		pq->phead = newnode;
		pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->size);

	QNode* next = pq->phead->next;
	free(pq->phead);
	pq->phead = next;

	if (pq->phead == NULL)
	{
		pq->ptail = NULL;
	}

	pq->size--;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->phead->val;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->ptail);
	return pq->ptail->val;
}

int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

_Bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* pcur = pq->phead;
	while (pcur)
	{
		QNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

typedef struct {
    Queue q1;
    Queue q2;
} MyStack;


MyStack* myStackCreate() 
{
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    if(pst == NULL)
    {
        perror("malloc failed");
        exit(1);
    }
    QueueInit(&pst->q1);
    QueueInit(&pst->q2);
    return pst;
}

void myStackPush(MyStack* obj, int x) 
{
    if(!QueueEmpty(&(obj->q1)))
    {
        QueuePush(&(obj->q1), x);
    }
    else
    {
        QueuePush(&(obj->q2), x);
    }
}

int myStackPop(MyStack* obj) 
{
    //如果队列不为空,就把前size - 1个数据放在另一个队列中,释放最后一个节点的数据
    Queue* emp = &(obj->q1);//假设q1为空
    Queue* noemp = &(obj->q2);
    if(QueueEmpty(&(obj->q2)))//如果q2为空
    {
        emp = &(obj->q2);
        noemp = &(obj->q1);
    }

    int sz = QueueSize(noemp);
    while(sz > 1)
    {
        QueuePush(emp, QueueFront(noemp));
        QueuePop(noemp);
        sz--;
    }
    int top = QueueFront(noemp);
    QueuePop(noemp);
    return top;
}

int myStackTop(MyStack* obj) 
{
    if(!QueueEmpty(&(obj->q1)))
    {
        return QueueBack(&(obj->q1));
    }
    else
    {
        return QueueBack(&(obj->q2));
    }
}

bool myStackEmpty(MyStack* obj) 
{
    return QueueEmpty(&(obj->q1)) && QueueEmpty(&(obj->q2));
}

void myStackFree(MyStack* obj) 
{
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
}

/**
 * Your MyStack struct will be instantiated and called as such:
 * MyStack* obj = myStackCreate();
 * myStackPush(obj, x);
 
 * int param_2 = myStackPop(obj);
 
 * int param_3 = myStackTop(obj);
 
 * bool param_4 = myStackEmpty(obj);
 
 * myStackFree(obj);
*/

用栈实现队列

题目链接:用栈实现队列
用栈实现队列

typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

//初始化
void STInit(ST* pst);

//销毁
void STDestroy(ST* pst);

//插入数据(入栈)
void STPush(ST* pst, STDataType x);

//删除数据(出栈)
void STPop(ST* pst);

//获取栈顶数据
STDataType STTop(ST* pst);

//判空
_Bool STEmpty(ST* pst);

//获取数据个数
int STSize(ST* pst);

void STInit(ST* pst)
{
	assert(pst);

	pst->a = NULL;
	pst->capacity = 0;
	// top指向栈顶数据的下一个位置
	pst->top = 0;

	 top指向栈顶数据
	//pst->top = -1;
}

void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->a);

	pst->a = NULL;
	pst->capacity = 0;
	pst->top = 0;
}

void STPush(ST* pst, STDataType x)
{
	assert(pst);

	//扩容
	if (pst->top == pst->capacity)
	{
		int newcapacity = (pst->capacity == 0) ? 4 : (2 * pst->capacity);
		STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc failed");
			exit(1);
		}

		pst->a = tmp;
		pst->capacity = newcapacity;
	}

	//存放数据
	pst->a[pst->top] = x;
	pst->top++;
}

void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top--;
}

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);

	return pst->a[pst->top - 1];
}

_Bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}

int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}

typedef struct 
{
    ST s1;
    ST s2;
} MyQueue;


MyQueue* myQueueCreate() 
{
    MyQueue* pqe = (MyQueue*)malloc(sizeof(MyQueue));
    if(pqe == NULL)
    {
        perror("malloc failed");
        exit(1);
    }
    STInit(&(pqe->s1));
    STInit(&(pqe->s2));
    return pqe;
}

void myQueuePush(MyQueue* obj, int x) 
{
    if(!STEmpty(&(obj->s1)))
    {
        STPush(&(obj->s1), x);
    }
    else
    {
        STPush(&(obj->s2), x);
    }
}

int myQueuePop(MyQueue* obj)
{
	ST* emp = &(obj->s1);//假设s1为空
	ST* noemp = &(obj->s2);
	if (STEmpty(&(obj->s2)))//如果s2为空
	{
		emp = &(obj->s2);
		noemp = &(obj->s1);
	}


	int sz = STSize(noemp);
	if (sz == 1)
	{
		int top = STTop(noemp);
		STPop(noemp);
		return top;
	}
	else
	{
		while (sz > 1)
		{
			STPush(emp, STTop(noemp));
			STPop(noemp);
			sz--;
		}
		int top = STTop(noemp);
		STPop(noemp);
		ST* tmp = noemp;
		noemp = emp;
		emp = tmp;
		sz = STSize(noemp);
		while (sz > 0)
		{
			STPush(emp, STTop(noemp));
			STPop(noemp);
			sz--;
		}
		return top;
	}
}

int myQueuePeek(MyQueue* obj)
{
	ST* emp = &(obj->s1);//假设s1为空
	ST* noemp = &(obj->s2);
	if (STEmpty(&(obj->s2)))//如果s2为空
	{
		emp = &(obj->s2);
		noemp = &(obj->s1);
	}


	int sz = STSize(noemp);
	if (sz == 1)
	{
		int top = STTop(noemp);
		return top;
	}
	else
	{
		while (sz > 1)
		{
			STPush(emp, STTop(noemp));
			STPop(noemp);
			sz--;
		}
		int top = STTop(noemp);
		STPush(emp, STTop(noemp));
		STPop(noemp);
		ST* tmp = noemp;
		noemp = emp;
		emp = tmp;
		sz = STSize(noemp);
		while (sz > 0)
		{
			STPush(emp, STTop(noemp));
			STPop(noemp);
			sz--;
		}
		return top;
	}
}

bool myQueueEmpty(MyQueue* obj) 
{
    return STEmpty(&obj->s1) && STEmpty(&obj->s2);
}

void myQueueFree(MyQueue* obj) 
{
    STDestroy(&obj->s1);
    STDestroy(&obj->s2);
    free(obj);  
}

/**
 * Your MyQueue struct will be instantiated and called as such:
 * MyQueue* obj = myQueueCreate();
 * myQueuePush(obj, x);
 
 * int param_2 = myQueuePop(obj);
 
 * int param_3 = myQueuePeek(obj);
 
 * bool param_4 = myQueueEmpty(obj);
 
 * myQueueFree(obj);
*/

四. 概念选择题

  1. 循环队列的存储空间为 Q(1:100) ,初始状态为front=rear=100 。经过一系列正常的入队与退队操作后, front=rear=99 ,则循环队列中的元素个数为( )
    A 1
    B 2
    C 99
    D 0或者100
  2. 以下( )不是队列的基本运算?
    A 从队尾插入一个新元素
    B 从队列中删除第i个元素
    C 判断一个队列是否为空
    D 读取队头元素的值
  3. 现有一循环队列,其队头指针为front,队尾指针为rear;循环队列长度为N。其队内有效长度为?(假设队头不存放数据)
    A (rear - front + N) % N + 1
    B (rear - front + N) % N
    C ear - front) % (N + 1)
    D (rear - front + N) % (N - 1)
    答案
  4. D
  5. B
  6. B

五. 参考代码

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 val;
}QNode;

typedef struct Queue
{
	QNode* phead; 
	QNode* ptail;
	int size;
}Queue;

队尾插入
//void QueuePush(QNode** pphead, QNode** pptail, QDataType x);
//
队头删除
//void QueuePop(QNode** pphead, QNode** pptail);

//初始化
void QueueInit(Queue* pq);

//队尾插入
void QueuePush(Queue* pq, QDataType x);

//队头删除
void QueuePop(Queue* pq);

//取队头数据
QDataType QueueFront(Queue* pq);

//取队尾数据
QDataType QueueBack(Queue* pq);

//队列元素个数
int QueueSize(Queue* pq);

//判空
_Bool QueueEmpty(Queue* pq);

//队列的销毁
void QueueDestroy(Queue* pq);

Queue.c

#include "Queue.h"

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

void QueuePush(Queue* pq, QDataType x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc failed");
		exit(1);
	}

	newnode->next = NULL;
	newnode->val = x;

	if (pq->ptail == NULL)
	{
		pq->phead = newnode;
		pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->size);

	QNode* next = pq->phead->next;
	free(pq->phead);
	pq->phead = next;

	if (pq->phead == NULL)//just one node
	{
		pq->ptail = NULL;
	}

	pq->size--;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->phead->val;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->ptail);
	return pq->ptail->val;
}

int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

_Bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* pcur = pq->phead;
	while (pcur)
	{
		QNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

test.c

#include "Queue.h"

int main()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	QueuePush(&q, 5);

	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}

	return 0;
}

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

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

相关文章

WordPress公众号扫码登录/注册

目录 一、扫码过程概述 1.扫码进入公众号 2.输入关键字 3.输入验证码 4.登录验证 5.后续操作 6.基础要求 二、插件安装 三、公众号设置 五、登录页码制作 六、扫码登录测试 WordPress建设的网址,是支持用户注册的,不过不如使用“微信扫码”登录来的简单。不过要想…

IO

目录 一、IO流基本认识 1.1 字节流 1.2 字符流 1.3 高级流 二、IO流基本理解 2.1 IO流的分类 2.1.1 按照流的流向 2.1.2 按照处理数据单位 2.1.3 按照流的角色 2.2 IO流的选择 2.3 IO流的4个抽象基类 2.4 字节流和字符流的区别 2.4.1 使用场景 三、IO模型 3.1 BI…

Leetcode JAVA刷刷站(10)正则表达式匹配

一、题目概述 二、思路方向 在Java中&#xff0c;实现一个支持.和*的正则表达式匹配器&#xff0c;可以通过递归或动态规划&#xff08;DP&#xff09;的方法来完成。这里&#xff0c;我将使用动态规划的方法来解决这个问题&#xff0c;因为它更容易理解和实现。 动态规划的思…

代码随想录算法训练营43期 | Day 13 —— 二叉树part01

代码随想录算法训练营 二叉树理论基础二叉树的种类1. 满二叉树2. 完全二叉数3. 二叉搜索树3. 平衡二叉搜索树 二叉树的存储方式二叉树遍历方式二叉树的定义 二叉树的递归遍历144.前序遍历145.后序遍历94.中序遍历 二叉树迭代遍历前序遍历&#xff08;迭代法&#xff09;后序遍历…

实战项目:贪吃蛇游戏的实现(下)

前言 今天我们将继续贪吃蛇游戏的实现&#xff0c;紧接上期我们已经实现了贪吃蛇游戏的大部分基础知识&#xff0c;我们上期主要是学习了Windows系统的API函数,并实现了大部分的贪吃蛇设计&#xff0c;那这期我们将完成剩余的设计部分&#xff0c;并完成代码的实现。 好&…

UEC++学习(十六)变量添加中文注释、ui设置中文文本

&#xff08;一&#xff09;变量添加中文注释 在C 项目中创建变量&#xff0c;并在蓝图中显示变量的英文名同时附带中文注释&#xff0c;可以使用UPROPERTY 的 ToolTip 元数据属性来实现 UPROPERTY(EditAnywhere, meta (ToolTip "弹夹最大容量"))int32 MagCapacit…

目标检测算法,Yolov7本地化部署标注、训练(二)

安全帽检测、口罩检测、行为检测、目标物体检测&#xff0c;随着深度学习和计算机视觉技术的不断发展&#xff0c;目标检测成为了研究热点之一。YOLOv7作为YOLO系列的新成员&#xff0c;以其高效和准确的性能受到了广泛关注。本文将介绍如何在本地部署并利用YOLOv7完成目标检测…

StormBamboo 入侵 ISP 并滥用不安全的软件更新机制

关键要点 StormBamboo 成功入侵了一家互联网服务提供商 (ISP)&#xff0c;以毒害目标组织的 DNS 响应。不安全的软件更新机制旨在在运行 macOS 和 Windows 的受害者机器上秘密安装恶意软件。StormBamboo 部署的恶意软件包括 MACMA 恶意软件的新变种。对 MACMA 最新版本的分析表…

Python学习入门实验

&#xff08;1&#xff09;掌握python数字类型的使用方法 &#xff08;2&#xff09;掌握将数学表达式转换成python语言表达式的方法及注意 &#xff08;3&#xff09;掌握有关运算符号的特殊要求 &#xff08;4&#xff09;掌握输入、输出函数的使用方法 &#xff08;5&am…

Python与netCDF数据之全面解析空间偏相关分析详解

概要 在气象学、海洋学、环境科学等领域,netCDF(Network Common Data Form)是一种常用的数据格式,用于存储和共享多维科学数据。偏相关分析(Partial Correlation Analysis)是一种统计方法,用于研究多个变量之间的关系,同时控制其他变量的影响。本文将详细介绍如何使用…

VTK-vtkStructuredGrid学习

vtkStructuredGrid是具有规则拓扑和不规则几何的数据集。可以理解为单元格顺序沿着坐标轴排列&#xff0c;但是每个单元格可以不一样。看了很多文字解释&#xff0c;感觉不清楚&#xff0c;直接用图解验证&#xff1a; 1.使用CAD随意绘制个网格草图 2.获取这些点信息&#xff…

Sealos 就是小团队的神器

作者&#xff1a;阳明。Kubernetes 布道师&#xff0c;公众号 K8s 技术圈主理人 最近我们新开发了一个项目 fastclass.cn&#xff0c;这个项目是一个独立开发者的学习网站&#xff0c;我们的目标是帮助你使用 Figma、Python、Golang、React、VUE、Flutter、ChatGPT 等设计构建真…

【linux】linux中如何通过systemctl来创建和管理服务

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

【网络】从零认识IPv4

目录 IP地址定义 网络标识和主机标识 子网掩码 IPv4地址的分类 全局地址和私有地址 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 IP地址定义 IP是网络中每台设备的唯一标识符&#xff0c;用于识别和定位计算机、服务器、路由器等设备&#xff0c;以便它们能够在网络上…

VictoriaMetrics快速入门

文章目录 Multitenancy集群部署启动vmstorage服务启动vminsert服务启动 vmselect服务 配置使用集群大小调整和可伸缩性grafana展示参考资料 VictoriaMetrics是快速&#xff0c;经济高效且可扩展的时间序列数据库。它可以用作Prometheus的长期远程存储。 VictoriaMetrics集群包含…

鸿蒙开发5.0【同页面内的点击操作响应时延问题】分析思路案例

1. 场景导入 同页面内点击操作时延是指&#xff0c;应用内手指点击从离开屏幕开始&#xff0c;到页面发生变化的时间。常见场景包括点击后界面元素变化&#xff0c;弹出弹窗或者loading动画等场景。 2. 性能指标 2.1 性能衡量起始点介绍 1.点击操作响应时延的性能衡量的起点…

GitLab-CI/CD指南

由于公司没有运维&#xff0c;写go服务时各个环境编译部署还是略显麻烦&#xff0c;由于代码管理使用的是 gitlab&#xff0c;所以决定使用 gitlab 自带的 CI/CD 来做自动编译和部署&#xff0c;这样每次提交代码以后就可以自动部署到服务器上了。 gitlab 本身只有 CI/CD 的接…

金蝶云星辰V1与旺店通·企业版对接集成采购入库单查询(列表+详情)连通创建其他入库单(其他)

金蝶云星辰V1与旺店通企业版对接集成采购入库单查询&#xff08;列表详情&#xff09;连通创建其他入库单(其他) 接入系统&#xff1a;金蝶云星辰V1 金蝶云星辰基于金蝶云苍穹云原生PaaS平台构建&#xff0c;聚焦小型企业在线经营和数字化管理&#xff0c;提供财务云、税务云、…

操作系统中的进程:深入解析与理解

文章目录 一、什么是进程&#xff1f;&#x1f914;二、进程的特性 &#x1f31f;三、进程的组成 &#x1f9e9;四、进程的状态与转换 &#x1f504;&#x1f500;五、进程的调度与管理 &#x1f527;&#x1f500;六、代码示例&#xff08;C&#xff09;创建进程进程等待&…

scanf中%c前加不加空格的区别

%c前加空格可以让scanf跳过空白字符&#xff08;如空格、制表符、换行符等&#xff09;&#xff0c;直接读取非空白字符。如果不加空格就会读取空白字符。 可以用两段测试客官有无慧根的程序来说明这个问题&#xff0c;测试代码如下&#xff1a; #include <stdio.h> in…