【c数据结构】队列详解!(模拟实现、OJ练习实操)

news2024/11/27 18:33:44

队列的概念

队列就像排队,先进先出,zz先到先得(队头的人先出去,队尾的人排在最后出去)

对比栈 队列示意图


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

  • 队尾:进⾏插⼊操作
  • 队头:进⾏删除操作
  • 队列的底层是链表(每一个数据是通过一个节点保存的,节点和节点之间是通过指针连接的
链表

队列的模拟实现

定义队列的结构

两个结构体,一个是其底层->链表的结构,另一个是对链表的优化,给其加上队尾和队头的限制——这就是队列。

//定义队列的结构


//为什么要两个链表呢?
//这是正常链表的结构
typedef int QDataType;
typedef struct QueueNode {
	QDataType data;
	QueueNode* next;
}QueueNode;
//对于链表的维护,给链表多一个队尾和队头的限制,这就是队列
typedef struct Queue {
	 QueueNode* phead;//指向头节点的指针---队头--删除数据
     QueueNode* ptail;//指向尾节点的指针---队尾--插入数据
     int size;//保存队列有效个数
}Queue;

Queue.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include <stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
 


//定义队列的结构


//为什么要两个链表呢?
//这是正常链表的结构
typedef int QDataType;
typedef struct QueueNode {
    QDataType data;
    QueueNode* next;
}QueueNode;
//对于链表的维护,给链表多一个队尾和队头的限制,这就是队列
typedef struct Queue {
    QueueNode* phead;//指向头节点的指针---队头--删除数据
    QueueNode* ptail;//指向尾节点的指针---队尾--插入数据
    int size;//保存队列有效个数
}Queue;

 
 
//初始化
void QueueInit(Queue* pq);
 
//入队列,队尾   插入数据
void QueuePush(Queue* pq, QDataType x);
 
//出队列,队头    删除数据
void QueuePop(Queue* pq);
 
//判断队列是否为空
bool Queuempty(Queue* pq);
 
//取队头数据
QDataType QueueFront(Queue* pq);
 
//取队尾数据
QDataType QueueBack(Queue* pq);
 
//队列有效元素个数
int QueueSize(Queue* pq);
 
//队列的销毁
void QueueDestroy(Queue* pq);

Queue.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"

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

//判断队列是否为空
bool Queuempty(Queue* pq) {
	assert(pq);
	return pq->phead == NULL && pq->ptail == NULL;
	//是空,返回true
}

//入队列,队尾   插入数据
void QueuePush(Queue* pq, QDataType x) {
	assert(pq);
	//创建新结点并对其初始化
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode*));
	if (newnode)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;

	//判断队列是否为空
	if (pq->phead == pq->ptail == NULL) {
		//此时newnode既是头结点也是尾节点
		pq->phead = pq->ptail = newnode;
	}
	else//不为空,队尾插入
	{
		//原尾结点指向新结点
		pq->ptail->next = newnode;
		//尾哨兵走到下一位(最后一结点)
		pq->ptail = pq->ptail->next;
	}
}

//出队列,队头    删除数据
void QueuePop(Queue* pq) {
	assert(pq);
	//注意空的队列没法删东西!
	//——判断队列是否为空!
	assert(!Queuempty(pq));
	
	//只有一个结点时头结点没有下一位,需要另外处理
	if (pq->ptail ==pq->ptail) //头尾哨兵指针指向相同,说明只有一个结点
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else//否则 多个结点
	{
		//创建临时的结点保存新头结点(头哨兵的下一位)的数据
		QueueNode* pcur = pq->phead->next;
		free(pq->phead);
		pq->phead = pcur;
	}
	--pq->size;

}



//取队头数据
QDataType QueueFront(Queue* pq) {
	assert(pq);
	assert(!Queuempty(pq));//队列不为空
	return pq->phead->data;
}

//取队尾数据
QDataType QueueBack(Queue* pq) {
	assert(pq);
	assert(!Queuempty(pq));//队列不为空
	return pq->ptail->data;
}

//队列有效元素个数
int QueueSize(Queue* pq) {
	assert(pq);

	return pq->size;
}

//队列的销毁
void QueueDestroy(Queue* pq) {
	assert(pq);
	assert(!Queuempty(pq));

	//遍历pcur依次释放空间
	QueueNode* pcur = pq->phead;
	while (pcur) 
	{
		//销毁之前先把下个节点进行保存,防止丢失位置
		QueueNode* Next = pcur->next;
		free(pcur);
		//将pcur销毁之后,之前保存的next就是新的头结点
		pcur = Next;
	}

	pcur = pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

相关OJ练习题实战

1. 用队列实现栈

/*
队列是先进先出
栈是先进后出
*/
 
/*思路:
出栈:找到不为空的队列,将size-1个数据导入到另一个队列中
入栈:往空队列中插入数据
取栈顶元素
 
 
*/
 
//定义队列结构
typedef int QDataType;
typedef struct QueueNode
{
    QDataType data;
    struct QueueNode* next;
 
}QueueNode;
 
typedef struct Queue
{
    QueueNode*phead;//指向头节点的指针---队头--删除数据
    QueueNode*ptail;//指向尾节点的指针---队尾--插入数据
    int size;//保存队列有效个数
}Queue ;
 
//初始化
void QueueInit(Queue* pq)
{
    assert(pq);//传过来的不能是空指针 
 
    pq->phead = pq->ptail = NULL;//空的队列
    pq->size = 0;
}
 
//判断队列是否为空
bool Queuempty(Queue* pq)
{
    assert(pq);
 
    return pq->phead == NULL && pq->ptail == NULL;
    //如果后面的表达式成立,那么就是真,返回的是true
 
    //就是说如果这里的是空队列的话,那么就返回的是true
}
 
//入队列,队尾   插入数据
void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);
 
    //申请新节点
    QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));//申请一个节点大小的空间
    if (newnode == NULL)
    {
        perror("malloc dail!");
        exit(1);
    }
    //对newnode进行初始化操作
    newnode->data = x;
    newnode->next = NULL;
    if (pq->phead == NULL)//说明队列为空
    {
        pq->phead = pq->ptail = newnode;//那么此时的newnode不仅是头结点也是尾节点
    }
    else//队列不为空
    {
        pq->ptail->next = newnode;
        //那么此时的newnode 就是新的ptail
        pq->ptail = newnode;
    }
    pq->size++;
}
 
//出队列,队头    删除数据    从头结点开始删除数据
void QueuePop(Queue* pq)
{
    assert(pq);
    //队列为空(不可删除数据,因为没有数据)
    //队列不为空(可删除数据)
 
    assert(!Queuempty(pq));//队列为空白的话就报错
 
    //处理只有一个节点的情况,避免ptail变成野指针
    //判断只有一个节点的情况
    if (pq->ptail == pq->phead)//头尾指针相同,说明只有一个节点
    {
        free(pq->phead);//随便释放
        pq->phead = pq->ptail = NULL;
    }
    else//处理多个节点的情况
    {
        //删除队头元素
    //那么我们现将下个节点的位置进行保存
        QueueNode* next = pq->phead->next;
        //存储好之后我们直接将头结点进行释放
        free(pq->phead);
        pq->phead = next;//那么之前存的next就是新的头结点了
    }
    pq->size--;
}
 
//取队头数据
QDataType QueueFront(Queue* pq)//返回队头数据
{
    assert(pq);
    assert(!Queuempty(pq));//队列不为空
 
    return pq->phead->data;//将队头里面的数据直接返回就行了
}
 
//取队尾数据
QDataType QueueBack(Queue* pq)
{
    assert(pq);
    assert(!Queuempty(pq));//队列不为空
 
    return pq->ptail->data;
}
 
//队列有效元素个数
int QueueSize(Queue* pq)
{
    assert(pq);
    //下面这种遍历的话效率太低了
    //int size = 0;
    定义一个指针进行遍历
    //QueueNode* pcur = pq->phead;//指向队列的头结点
    //while (pcur)//pcur不为空就往后走
    //{
    //  size++;
    //  pcur = pcur->next;
    //}
    //return size;
    return pq->size;
}
 
//队列的销毁
void QueueDestroy(Queue* pq)
{
    assert(pq);
    //assert(!Queuempty(pq));//队列不为空
    //遍历
    QueueNode* pcur = pq->phead;
    while (pcur)
    {
        //销毁之前先把下个节点进行保存
        QueueNode* next = pcur -> next;
        free(pcur);
        //将Pcur销毁之后,那么之前保存的next就是新的头结点
        pcur = next;
    }
    pq->phead = pq->ptail = NULL;
    pq->size = 0;
}
 
 
 
//两个队列来实现栈
typedef struct 
{
    Queue q1;//队列1
    Queue q2;//队列2
} MyStack;
 
//STInit  栈的初始化
MyStack* myStackCreate()
{
    MyStack*pst=(MyStack*)malloc(sizeof(MyStack));//创建一个栈大小的空间
    QueueInit(&pst->q1);//调用初始化函数对q1进行初始化
    QueueInit(&pst->q2);
 
    return pst;
}
 
//那么到这里我们有一个空栈,栈里面有两个队列
 
//入数据
void myStackPush(MyStack* obj, int x)
{
    //往不为空的队列插入数据
    //第一步判断那个队列是非空队列
    if(!Queuempty(&obj->q1))//如果这个队列不是空的话,我们就我那个这个队列里面入数据
    {
        //往队列内插入数据
        QueuePush(&obj->q1,x);
    }
    else
    {
        QueuePush(&obj->q2,x);
    }
 
}
//出数据
int myStackPop(MyStack* obj)
{
    //找到不为空的队列
    Queue*empQ=&obj->q1;//假设q1是空的,创建指针指向q1
    Queue*noneQ=&obj->q2;//q2不为空,指针指向q2
 
    if(!Queuempty(&obj->q1))//如果q1不为空
    {
        //创建两个指针,noneQ指向的是非空队列,empQ指向的是空队列
        noneQ=&obj->q1;//那么这个非空指针就指向了q1
        empQ=&obj->q2;//那么空指针就指向q2了
    }
    //将不为空内的size-1个数据导入到另一个队列里面
    while(QueueSize(noneQ)>1)//循环条件是非空队列里面只剩下一个有效的数据了
    {
        int front=QueueFront(noneQ);//获取这个非空队列里面的队头数据
        QueuePush(empQ,front);//往空队列里面循环插入队头数据
        QueuePop(noneQ);//因为我们这个非空队列的队头数据已经拿出去了 ,那么我们就将非空队列进行删除数据操作
    }
    //非空队列中只剩下一个数据----那么这个数据就是要出栈的数据
    int pop=QueueFront(noneQ);//获取剩下的这个元素
    QueuePop(noneQ);//进行出数据操作
    return pop;//返回我们要的值
 
}
 
//取栈顶元素  假设插入1 2 3,那么栈顶就是3   这里是2两个队列
int myStackTop(MyStack* obj)   
{
    //找到不为空的队列,取队尾元素
    if(!Queuempty(&obj->q1))//如果第一个队列不为空的话
    {
        return QueueBack(&obj->q1);//直接将取到的队尾元素进行返回就行了
    }
    else
    {
        return QueueBack(&obj->q2);
    }
}
//判读栈是否为空
bool myStackEmpty(MyStack* obj)
{
    //两个队列如果都为空的话,那么这个栈就是空的
    return Queuempty(&obj->q1)  &&  Queuempty(&obj->q2);
}
//销毁
void myStackFree(MyStack* obj)
{
    //就是栈内的连个队列的销毁
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);//将我们之前申请的栈空间进行释放掉
    obj=NULL;
}
 
/**
 * 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);
*/

2. 用栈实现队列




//定义栈的结构
typedef int STDataType;
typedef struct Stack
{
    STDataType* arr;
    int capacity;//栈的空间大小
    int top;//栈顶(插入数据和删除数据的位置)
}ST;
//初始化
void STInit(ST* ps)
{
	assert(ps);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}
//传的是地址

//销毁
void STDestory(ST* ps)
{
	assert(ps);
	if (ps->arr != NULL)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}

//栈顶-=--如数据、出数据

//栈的入数据操作
void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	//判断空间是否满了
	if (ps->capacity == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* tmp = (STDataType*)realloc(ps->arr, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
	ps->arr[ps->top++] = x;
}

//判断栈是否为空
bool StackEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}
//栈的出数据操作
void StackPop(ST* ps)
{
	assert(ps);
	//判断是否为空
	assert(!StackEmpty(ps));
	--ps->top;
}

//取栈顶元素---循环打印栈顶的数据
//返回值是栈顶的元素
STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	return ps->arr[ps->top-1];
}



//获取栈中有效个数
int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}


typedef struct {
	ST STpop;
	ST STpush;
} MyQueue;


MyQueue* myQueueCreate() {
	MyQueue* pst = (MyQueue*)malloc(sizeof(MyQueue));
	STInit(&pst->STpop);
	STInit(&pst->STpush);
	return pst;
}

void myQueuePush(MyQueue* obj, int x) {
	StackPush(&obj->STpush,x);
}

int myQueuePop(MyQueue* obj) {
	//1.检查popST是否为空
	   //1)不为空直接 出
	   //2)为空,pushST导入到popST,在出数据
	if (StackEmpty(&obj->STpop))
	{
		while (!StackEmpty(&obj->STpush))
		{
			StackPush(&obj->STpop, StackTop(&obj->STpush));
			StackPop(&obj->STpush);
		}
	}
	int tmp = StackTop(&obj->STpop);
	StackPop(&obj->STpop);
	return tmp;
}

int myQueuePeek(MyQueue* obj) {
	//判断pop栈是否为空
	if (StackEmpty(&obj->STpop))
	{
		//为空,将push的数据全部导入pop
		while (!StackEmpty(&obj->STpush))
		{
			//每次取push的栈顶元素
			StackPush(&obj->STpop, StackTop(&obj->STpush));
			//为保证能取下一个栈顶,记得先删除原栈顶
			StackPop(&obj->STpush);
		}
	}
	return StackTop(&obj->STpop);
}

bool myQueueEmpty(MyQueue* obj) {
	return StackEmpty(&obj->STpush) && StackEmpty(&obj->STpop);
}

void myQueueFree(MyQueue* obj) {
	STDestory(&obj->STpop);
	STDestory(&obj->STpush);
	free(obj);
	obj = NULL;
}

3. 设计循环队列

 

/*
//循环队列的容量大小是k
我们用数组作底层,数组大小为k+1,最后一个数组元素不存储数据,单纯占位置
假设我们需要4个大小的数组,那么就申请5个空间
0 1 2 3 4 这是数组下标
一开始front和rear都指向下标为0的位置,每插入一个元素,rear++
直至rear到下标为4的位置,说明空间满了
因为循环rear又应该会回到front位置

判断空间是否满了 (rear+1) % (k+1) ==  (front)
判断空间是否为空 rear == front
*/


typedef struct {
    int* arr;//动态数组的指针,因为不知道数组具体大小
    int front;
    int rear;
    int capacity;//这个是保存数组空间大小k
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
    //创建新队列
    MyCircularQueue* pst =(MyCircularQueue*)malloc(sizeof(MyCircularQueue));

    //队列里的内容初始化

    //因为队列的底层空间是数组
    //所以动态数组开辟一个空间
    pst->arr = (int*)malloc(sizeof(int)*(k+1));//我们给数组申请K+1个整型大小的空间
    pst->front = pst->rear = 0;
    pst->capacity = k;
    return pst;
}

//判断队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->rear == obj->front;
}

//判断队列是否满了
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    //capacity+1是数组的容量大小,多出的1是用来占位置的
    return (obj->rear+1) % (obj->capacity+1) == obj->front;
}


//向循环队列里面插入数据,如果成功插入就返回真
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    //先判断队列是否满了,容量满了无法插入数据
    if(myCircularQueueIsFull(obj))
    return false;

    //走到这里说明没满,可以插入数据
    obj->arr[obj->rear++]=value;
    //由于是循环,rear只会在容量大小范围内的数组中插入元素
    //即为了保证循环的效果
    /*
    假设我们的rear此时在占位置的那个位置,就是多出来的1的那个位置
    为了保证循环,我们要让rear回到数组的第一个位置 */
    obj->rear = (obj->rear) % (obj->capacity+1); //求余使得rear只会在k的范围内
    //求余结果赋给rear

     //插入完成我们就返回true
    return true;
}


//从循环队列中删除一个元素,成功删除就返回true
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    //删除元素,则队列不可为空
    if(myCircularQueueIsEmpty(obj))
    return false;//为空,返回false

    //不为空,可以删除操作
    //front换位置了,原先front的数据可被覆盖
    obj->front++;
    //同样,为了保证只在容量范围内增删数据,取余操作
    obj->front %= (obj->capacity+1);

    return true;
}

//取对首元素,返回对应值
int myCircularQueueFront(MyCircularQueue* obj) {
    //队列为空取个啥
    if(myCircularQueueIsEmpty(obj))//按题目要求,队列为空返回-1
    return -1;

    return obj->arr[obj->front];
}


//取对尾元素,返回对应值
int myCircularQueueRear(MyCircularQueue* obj) {
    //队列为空取个啥
    if(myCircularQueueIsEmpty(obj))//按题目要求,队列为空返回-1
    return -1;

    //正常情况你肯定以为这么写return obj->arr[obj->rear];
    //但是若rear在下标为0呢?返回数组下标为-1的值?不纯纯搞笑吗

    //定义一个指针来指向rear-1
    int prev = obj->rear-1;
    if(obj->rear == 0)
    {
        //保证循环效果,rear下标为0的时候rear-1在最后一个下标处
        prev = obj->capacity;
    }
    return obj->arr[prev];
}


void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    free(obj);
    obj=NULL;
}

希望对你有帮助

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

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

相关文章

68 Netty

68 Netty 参考资料 【硬核】肝了一月的Netty知识点 概念 Netty 是一个高性能、异步事件驱动的网络应用框架&#xff0c;简化了 Java 网络编程&#xff0c;适用于构建高效、可扩展的网络服务器和客户端。 Netty 是基于 Java NIO 的异步事件驱动的网络应用框架&#xff0c;使…

访问远程桌面或共享文件夹,输入正确凭证,但提示登录没有成功或者用户名密码不正确

可以在目标机器试试以下方法&#xff1a; winR 打开 "gpedit.msc" 本地组策略编辑器&#xff0c;导航到 计算机配置 > Widnows 设置 > 安全设置 > 本地策略 > 安全选项 找到 网络访问&#xff1a;本地账户的共享和安全模型&#xff0c;把 仅来宾 改为 …

介绍各种编程语言

记得点个赞再看哦 常见的编程语言 在当今的计算机编程领域&#xff0c;有许多种编程语言&#xff0c;以下是一些常见的编程语言&#xff1a; Python&#xff1a;是一种代表简单思想的语言&#xff0c;具有极其简单的语法&#xff0c;是FLOSS&#xff08;自由/开放源码软件&…

简单解析由于找不到xinput1_3.dll,无法继续执行代码的详细解决方法

电脑上突然跳出“由于找不到xinput1_3.dll&#xff0c;无法继续执行代码”的提示&#xff0c;这着实令人心烦&#xff0c;特别是当你正着急使用相关软件或者程序的时候。别担心&#xff0c;其实有五种科学有效的解决办法。大家得清楚&#xff0c;xinput1_3.dll是一个在众多软件…

快速总结HAT

HAT&#xff1a;Activating More Pixels in Image Super-Resolution Transformer 图像恢复(Image restoration)是计算机视觉中的一个经典问题&#xff0c;它的目的是从给定的低质量&#xff08;LQ&#xff09;输入重建高质量&#xff08;HQ&#xff09;图像。 在SwinIR基础上…

Codeforces 977 Div2 A-B

课上找空做了 A 原题 A. Meaning Mean 思路 贪心即可 代码 #include <bits/stdc.h> #define int long long using namespace std;const int N 110;int n, m, k, x, y, z; int w[N], f[N];void solve() {cin >> n;for (int i 1; i < n; i )cin >>…

理解计算机系统_程序的机器级表示(特别篇):对比move和leaq看汇编语言中数据的传递,变量和指针的映射,指针的实现

前言 以<深入理解计算机系统>(以下称“本书”)内容为基础&#xff0c;对程序的整个过程进行梳理。本书内容对整个计算机系统做了系统性导引,每部分内容都是单独的一门课.学习深度根据自己需要来定 引入 汇编代码传递数据的机制令人费解.而这部分内容又是比较基础的,需要…

自适应气泡小计

View 代码 <div class"mas-view"><div class"m-2"><span>新新消息消新消息消息新消息新消息新消息新消息新消息新消息新消息新消息新息</span></div></div>CSS 样式 .mas-view{width: 100%;height: auto;border: 1px…

[M数学] lc3164. 优质数对的总数 II(因数分解+倍增+推公式+思维+好题)

文章目录 1. 题目来源2. 题目解析 1. 题目来源 链接&#xff1a;3164. 优质数对的总数 II 2. 题目解析 挺不错的一道 因数分解、倍增 的题目&#xff0c;需要一定的思维和推公式的能力才能解决。灵神的题解已经非常清晰易懂了&#xff0c;可以直接去看。 倍增思路&#xff…

Kafka 消费者位置提交方式及适用场景

在使用 Kafka 进行消息处理时&#xff0c;消费者的位置提交是一个非常重要的环节。它决定了消费者在下次启动时从哪里开始读取消息。今天&#xff0c;我们就来深入探讨一下 Kafka 消费者位置提交方式有哪些&#xff0c;以及在什么场景下使用。 一、Kafka 消费者位置提交的重要…

Linux的zookeeper安装部署

1.zookeeper是一个分布式的,开放源码的分布式应用程序协调服务,是hadoop和HBASE的重要组件 2.下载zookeeper安装包zookeeper安装包https://archive.apache.org/dist/zookeeper/zookeeper-3.5.9/ 移动到Linux解压 解压到/export/server文件夹 命令: tar -xvf apache-zooke…

《Linux从小白到高手》综合应用篇:详解Linux系统调优之内存优化

本篇介绍Linux服务器系统内存调优。 内存是影响Linux性能的主要因素之一&#xff0c;内存资源的充足与否直接影响应用系统的使用性能。内存调优的主要目标是合理分配和利用内存资源&#xff0c;减少内存浪费&#xff0c;提高内存利用率&#xff0c;从而提升系统整体性能。 1.内…

选择智能工单系统的理由,功能与效益分析

智能工单管理系统提升企业客户服务效率和质量&#xff0c;具备多渠道接收、智能分配、自动化处理等功能。ZohoDesk等系统通过实时响应、数据分析等优化服务流程&#xff0c;成为企业提升竞争力的关键工具。 一、智能工单管理系统的概念与优势 1. 智能工单管理系统概念 智能工…

【三】【算法】P1007 独木桥,P1012 [NOIP1998 提高组] 拼数,P1019 [NOIP2000 提高组] 单词接龙

P1007 独木桥 独木桥 题目背景 战争已经进入到紧要时间。你是运输小队长&#xff0c;正在率领运输部队向前线运送物资。运输任务像做题一样的无聊。你希望找些刺激&#xff0c;于是命令你的士兵们到前方的一座独木桥上欣赏风景&#xff0c;而你留在桥下欣赏士兵们。士兵们十分愤…

H3C GRE VPN基本配置实验

H3C GRE VPN基本配置实验 实验拓扑 ​​ 实验需求 按照图示配置 IP 地址在 R1 和 R3 上配置默认路由使公网区域互通在 R1 和 R3 上配置 GRE VPN&#xff0c;使两端私网能够互相访问&#xff0c;Tunnel 口 IP 地址如图在 R1 和 R3 上配置动态路由协议来传递两端私网路由 实…

盘点2024年双十一最值得入手的好物,双十一必买清单大汇总

随着科技的飞速发展&#xff0c;数码产品已成为我们生活中不可或缺的伙伴。2024年双十一购物狂欢节即将来临&#xff0c;众多消费者早已摩拳擦掌&#xff0c;准备在这个年度盛事中淘到心仪的数码好物。在这个信息爆炸的时代&#xff0c;如何从琳琅满目的商品中挑选出性价比高、…

项目管理系统介绍,核心概念与操作技巧

项目管理系统通过分解任务、管理工时、规划项目等提升效率&#xff0c;支持多种使用场景&#xff0c;具备高度可定制性&#xff0c;适合不同用户群体&#xff0c;注重数据安全&#xff0c;能与其他软件集成。ZohoProjects因全面功能、低价和友好界面受中小企业青睐。 一、项目管…

视频背景音乐怎么提取出来?音乐爱好者必看:视频音轨提取指南

在数字媒体时代&#xff0c;视频成为了一种非常流行的信息传播方式。有时候&#xff0c;我们在观看视频时会被其中的背景音乐所吸引&#xff0c;想要将其提取出来单独欣赏或用于其他用途。那么&#xff0c;视频背景音乐怎么提取出来呢&#xff1f;本文将为您详细介绍几种提取视…

【Windows】【DevOps】Windows Server 2022平台启用WinRM实现远程powershell登陆 采用自签名证书开启HTTPS方案

快速配置开启WinRM(HTTP) quiciconfig 在目标服务器上&#xff0c;管理员权限启动powershell&#xff0c;执行指令 winrm quickconfig 输入y&#xff0c;完整日志如下 PS C:\Windows\system32> winrm quickconfig 已在此计算机上运行 WinRM 服务。 WinRM 没有设置成为了…

探索SAM:介绍、应用与衍生方向

Segment Anything Model&#xff08;简称SAM&#xff09;是Facebook Research团队开发的一项先进的图像分割技术。它通过使用深度学习模型&#xff0c;能够识别并分割出图像中的各个物体。SAM的创新之处在于其能够通过不同的交互方式&#xff08;如鼠标悬停、点击、框选和全图分…