数据结构之栈与队列

news2024/11/23 13:16:18

一.栈

1.定义:一种线性表,只允许在固定的一端进行删除和插入数据的操作,该端叫栈底,另一端叫栈顶

2.特点:先进后出

注:栈中元素出栈是一对多的(他虽然满足先进后出但是我们可以在pop数据前先获取栈顶元素并打印再pop,这样就可能改变数据在屏幕上出现的顺序)

3.思路:可以用数组实现,也可以用链表实现

数组实现更简单,链表实现较为复杂,下面小编将从两方面解释不选择链表实现的原因

1>若选择单链表,在进行删除操作时,我们不好解决栈顶先前移一位的问题

2>若选择双向链表,将占用过多的内存

4.代码实现(以数组实现栈为例):

(1)栈的结构体定义:包含数组指针,栈顶的位置,有效空间容量

typedef int STDatatype;
typedef struct Stack
{
	STDatatype* arr;
	int top;//栈顶
	int capacity;//有效空间容量
}ST;

(2)栈的初始化:将栈顶初始化为0:表示栈顶指向最后一个数据的下一个

                          将栈顶初始化为-1:表示栈顶指向最后一个数据所在位置

//栈的初始化
void STInit(ST* ps)
{
	assert(ps);
	ps->arr = NULL;
	//top指向栈顶后的一个元素,此时top等值于有效数据个数
	ps->top = 0;
	ps->capacity = 0;
}

(3)栈的销毁

//栈的销毁
void STDestory(ST* ps)
{
	assert(ps);

	free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}

(4)插入数据/入栈:先判断是否需要增容,再插入数据

//入栈
void STPush(ST* ps, STDatatype x)
{
	assert(ps);
	//判断是否需要增容
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity * 2==0 ? 4 : ps->capacity*2;
		STDatatype* tmp = (STDatatype*)realloc(ps->arr, sizeof(STDatatype) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps->arr = tmp;
		ps->capacity = newcapacity;
	}
	ps->arr[ps->top] = x;
	ps->top++;
}

(5)删除数据/出栈:先判断数组是否为空,再将top--即完成删除

//出栈
void STPop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	ps->top--;
}

(6)获取栈顶元素

//获取栈顶数据
STDatatype STTop(ST* ps)
{
	assert(ps);
	return ps->arr[ps->top-1];
}

(7)判断栈是否为空:若top==0则为空

//判断栈是否为空
bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

(8)栈中有效数据个数

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

二.队列

1.定义:一种线性表,只允许在一端(队尾)进行数据插入,在另一端(队头)进行数据删除

2.特点:先进先出

注:队列的数据出队列时是一对一的

3.思路:可以用数组实现,也可以用链表实现 

单链表实现更简单,数组实现较为复杂,是因为在使用数组实现时,进行删除数据不好记录下一次该删除数据的位置

4.代码实现(以单链表实现队列为例):

(1)队列的节点定义:指向下一个节点的指针,存储数据的数值

    队列的结构体定义:队列的头指针,尾指针,队列有效数据的个数

typedef int QueueDataType;

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

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

(2)队列的初始化

//队列的初始化
void QueueInit(Queue* pq)
{
	assert(pq);

	pq->head = NULL;
	pq->tail = NULL;
	pq->size = 0;
}

(3)队列的销毁:先逐个销毁队列的节点,再销毁队列

//队列的销毁
void QueueDestory(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	while (cur)
	{
		QNode* Next = cur->next;
		free(cur);
		cur = Next;
	}
	pq->head = NULL;
	pq->tail = NULL;
	pq->size = 0;
}

(4)插入数据:为该数据开辟一个新节点,若原队列中有数据则让尾指针向后走一步,若无则头尾    指针均指向该新节点

//队尾入数据
void QueuePush(Queue* pq, QueueDataType x)
{
	//开辟一个新节点
	QNode* node = (QNode*)malloc(sizeof(QNode));
	if (node == NULL)
	{
		perror("malloc fail");
		return;
	}
	node->val = x;
	node->next = NULL;

	//队列中没有节点
	if (pq->tail == NULL)
	{
		pq->head = node;
		pq->tail = node;
	}
	else
	{
		pq->tail->next = node;
		pq->tail = node;
	}

	pq->size++;
}

(5)删除数据:删除头指针指向的节点,并让头指针向后走一步,若只有一个节点删除后需将尾指针置空

//队头出数据
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->size != 0);

	QNode* next = pq->head->next;
	free(pq->head);
	pq->head = next;
	if (pq->head == NULL)
	{
		pq->tail = NULL;
	}

	pq->size--;
}

(6)获取队头元素

//获取队头数据
QueueDataType QueueFront(Queue* pq)
{
	assert(pq);
	return pq->head->val;
}

(7)获取队尾元素

//获取队尾数据
QueueDataType QueueBack(Queue* pq)
{
	assert(pq);
	return pq->tail->val;
}

(8)判断队列是否为空

//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

(9)队列的大小

//获取队列有效数据个数
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

三.栈与队列的相互转化

1.用栈实现队列

. - 力扣(LeetCode)

(1)思路:栈:先进后出,队列:先进先出

               创建两个栈实现队列中数据的删除

(2)解题方法:

1>自己实现栈

2>定义一个队列结构体包含两个栈

3>队列的创建:为队列结构体malloc一块空间,防止出函数时结构体被销毁

4>队列的销毁:先销毁两个栈,再销毁队列

5>队尾插数据:当两栈均为空栈时:随便在哪个空栈的栈顶插入数据均可

                          当有一个栈不为空时:在非空栈的栈顶插入数据

6>队头删数据:将非空栈的前size-1个数据导入空栈中,再删除队头的数据。此时对下次删除来说栈中数据顺序是错乱的,故还需要将原空栈的数据导回原非空栈中。

7>判断队列为空:当两个栈均为空时,队列为空

8>获取队尾数据:即非空栈的栈顶数据

(3)代码实现:

typedef int STDatatype;
typedef struct Stack
{
	STDatatype* arr;
	int top;//栈顶
	int capacity;//有效空间容量
}ST;

//栈的初始化
void STInit(ST* ps);

//栈的销毁
void STDestory(ST* ps);

//入栈
void STPush(ST* ps, STDatatype x);

//出栈
void STPop(ST* ps);

//获取栈顶数据
STDatatype STTop(ST* ps);

//判断栈是否为空
bool STEmpty(ST* ps);

//栈的有效数据个数
int STSize(ST* ps);

//栈的初始化
void STInit(ST* ps)
{
	assert(ps);
	ps->arr = NULL;
	//top指向栈顶后的一个元素,此时top等值于有效数据个数
	ps->top = 0;
	ps->capacity = 0;
}

//栈的销毁
void STDestory(ST* ps)
{
	assert(ps);

	free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}

//入栈
void STPush(ST* ps, STDatatype x)
{
	assert(ps);
	//判断是否需要增容
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity * 2==0 ? 4 : ps->capacity*2;
		STDatatype* tmp = (STDatatype*)realloc(ps->arr, sizeof(STDatatype) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps->arr = tmp;
		ps->capacity = newcapacity;
	}
	ps->arr[ps->top] = x;
	ps->top++;
}

//出栈
void STPop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	ps->top--;
}

//获取栈顶数据
STDatatype STTop(ST* ps)
{
	assert(ps);
	return ps->arr[ps->top-1];
}

//判断栈是否为空
bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

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

typedef struct {
    ST st1;
    ST st2;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* pq=(MyQueue*)malloc(sizeof(MyQueue));
    STInit(&(pq->st1));
    STInit(&(pq->st2));
    return pq;
}

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

int myQueuePop(MyQueue* obj) {
    assert(obj);
    ST* empty=&(obj->st1);
    ST* noempty=&(obj->st2);
    if(!STEmpty(&(obj->st1)))
    {
        empty=&(obj->st2);
        noempty=&(obj->st1);
    }
    while(STSize(noempty)>1)
    {
        STPush(empty,STTop(noempty));
        STPop(noempty);
    }
    STDatatype ret=STTop(noempty);
    STPop(noempty);
    //将noempty的数据导回empty,保证下次pop时数据顺序
    while(STSize(empty)>0)
    {
        STPush(noempty,STTop(empty));
        STPop(empty);
    }
    return ret;
}

int myQueuePeek(MyQueue* obj) {
    if(!STEmpty(&(obj->st1)))
    {
        return obj->st1.arr[0];
    }
    else
    {
        return obj->st2.arr[0];
    }
}

bool myQueueEmpty(MyQueue* obj) {
    return STEmpty(&(obj->st1)) && STEmpty(&(obj->st2));
}

void myQueueFree(MyQueue* obj) {
    assert(obj);
    STDestory(&(obj->st1));
    STDestory(&(obj->st2));
    free(obj);
    obj=NULL;
}

2.用队列实现栈

. - 力扣(LeetCode)

(1)思路:栈:先进后出,队列:先进先出

               创建两个队列实现栈中数据的删除

(2)解题方法:

1>自己实现队列

2>定义一个栈结构体包含两个队列

3>栈的创建:为栈结构体malloc一块空间,防止出函数时结构体被销毁

4>栈的销毁:先销毁两个队列,再销毁栈

5>入栈:当两队列均为空队列时:随便在哪个空队列的队尾插入数据均可

                          当有一个队列不为空时:在非空队列的队尾插入数据

6>出栈:将非空队列的前size-1个数据导入空队列中,再删除栈顶元素。

7>判断栈为空:当两个队列均为空时,栈为空

8>获取栈顶数据:即非空队列的队尾元素

(3)代码实现:

typedef int QueueDataType;

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

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

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

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

//队尾入数据
void QueuePush(Queue* pq, QueueDataType x);

//队头出数据
void QueuePop(Queue* pq);

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

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

//获取队列有效数据个数
int QueueSize(Queue* pq);

//判断队列是否为空
bool QueueEmpty(Queue* pq);

//队列的初始化
void QueueInit(Queue* pq)
{
	assert(pq);

	pq->head = NULL;
	pq->tail = NULL;
	pq->size = 0;
}

//队列的销毁
void QueueDestory(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	while (cur)
	{
		QNode* Next = cur->next;
		free(cur);
		cur = Next;
	}
	pq->head = NULL;
	pq->tail = NULL;
	pq->size = 0;
}

//队尾入数据
void QueuePush(Queue* pq, QueueDataType x)
{
	//开辟一个新节点
	QNode* node = (QNode*)malloc(sizeof(QNode));
	if (node == NULL)
	{
		perror("malloc fail");
		return;
	}
	node->val = x;
	node->next = NULL;

	//队列中没有节点
	if (pq->tail == NULL)
	{
		pq->head = node;
		pq->tail = node;
	}
	else
	{
		pq->tail->next = node;
		pq->tail = node;
	}

	pq->size++;
}

//队头出数据
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->size != 0);

	QNode* next = pq->head->next;
	free(pq->head);
	pq->head = next;
	if (pq->head == NULL)
	{
		pq->tail = NULL;
	}

	pq->size--;
}

//获取队头数据
QueueDataType QueueFront(Queue* pq)
{
	assert(pq);
	return pq->head->val;
}

//获取队尾数据
QueueDataType QueueBack(Queue* pq)
{
	assert(pq);
	return pq->tail->val;
}

//获取队列有效数据个数
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

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


MyStack* myStackCreate() {
    MyStack* pst=(MyStack*)malloc(sizeof(MyStack));
    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) {
    Queue* empty=&(obj->q1);
    Queue* noempty=&(obj->q2);
    if(!QueueEmpty(&(obj->q1)))
    {
        empty=&(obj->q2);
        noempty=&(obj->q1);
    }
    //把前size-1个数据移到空队列中
    while(QueueSize(noempty)>1)
    {
        QueuePush(empty,QueueFront(noempty));
        QueuePop(noempty);
    }
    QueueDataType top=QueueFront(noempty);
    QueuePop(noempty);
    return top;
}

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

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

void myStackFree(MyStack* obj) {
    assert(obj);
    QueueDestory(&(obj->q1));
    QueueDestory(&(obj->q2));
    free(obj);
    obj=NULL;
}

四.循环队列

. - 力扣(LeetCode)

1.定义:一种线性结构,基于先进先出原则,将队尾与队头连接起来构成循环

2.特点:有限空间,保证先进先出,从重复使用

3.思路:可以用数组实现,也可以用链表实现

用数组实现较为简单,用链表实现比较困难,下面小编将从两个角度来解释原因:

1>若使用单链表,在删除数据时不好获取待删除数据的前一个节点的位置,无法实现队尾的改变

2>若使用双向链表,占用内存太大,而且此时在判空判满时需要比较两个节点的地址比较麻烦

4.代码实现(以数组实现为例):

(1)循环队列的结构体定义:数组指针,队头的下标,队尾下一个数据的下标,空间的大小

typedef struct {
    int* a;
    int head;//指向头
    int rear;//指向尾的下一个
    int k;//空间大小
} MyCircularQueue;

(2)循环队列的创建:

1>为循环队列malloc一块空间,防止出函数时,结构体被销毁

2>由于rear指向队尾的下一个数据,若直接开辟指定大小的空间,在插入最后一个数据时,rear会越界访问,此时我们称该情况为假溢出现象,为了解决假溢出我们可以采取以下两种措施

【1】为数组多开一块空间

【2】

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* pc=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    
    //多开一块空间,解决假溢出问题
    pc->a=(int*)malloc(sizeof(int)*(k+1));
    pc->head=0;
    pc->rear=0;
    pc->k=k;
    return pc;
}

(3)循环队列的销毁:先销毁为数组开辟的空间,再销毁循环队列

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

(4)循环队列的判空:

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    assert(obj);
    //头与尾的下一个指向同一位置即为空
    return obj->head==obj->rear;
}

(5)循环队列的判满:

bool myCircularQueueIsFull(MyCircularQueue* obj) {

    assert(obj);
    //尾的下一个和头指向的位置相同即为满
    return obj->head==(obj->rear+1)%(obj->k+1);
}

(6)循环队列插入数据:在队尾插入数据,让rear向后走一步,为了避免rear++后越界访问,需要将自增后的rear模上k+1,使其在有效下标内且可以完成循环

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    assert(obj);
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    obj->a[obj->rear]=value;
    obj->rear++;
    obj->rear%=(obj->k+1);
    return true;
}

(7)循环队列删除数据:删除队头数据,让head向后走一步,为了避免head++后越界访问,需要将自增后的head模上k+1,使其在有效下标内且可以完成循环(原理同上,就不再赘述了)

ool myCircularQueueDeQueue(MyCircularQueue* obj) {
    assert(obj);
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }

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

(8)获取队尾元素:


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

(9)获取队头元素:

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

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

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

相关文章

Tower for Mac:Git管理的新境界

Tower for Mac,让您的Git管理进入新境界!这款专为Mac用户打造的Git客户端,凭借其出色的性能和丰富的功能,成为众多开发者的首选工具。 Tower不仅支持常规的Git操作,如提交、推送和拉取,还提供了许多高级功能…

【微服务最全详解】

文章目录 微服务微服务的介绍微服务服务架构演变 微服务网关微服务的负载均衡微服务的容灾机制服务崩溃服务容灾机制微服务熔断机制微服务限流Sentinel怎么实现限流微服务限流算法1.令牌桶算法2.漏斗桶算法 服务监控日志收集 微服务 微服务的介绍 微服务是一种软件架构风格&a…

MyBatis的创建和测试

创建项目点击Spring Initializr然后点击next 点击SQL 选择里面的Mybatis Framework和Mysql Driver 按如下图片创建项目 user表中的数据 #下面这些内容是为了让MyBatis映射 #指定Mybatis的Mapper文件 mybatis.mapper-locationsclasspath:mappers/*xml #指定Mybatis的实体目录 my…

使用人人开源renren-fast快捷搭建后台管理系统

https://gitee.com/renrenio/renren-fast https://gitee.com/renrenio/renren-fast 初始化项目数据库 导入项目运行 期间遇到的坑 024-04-25 01:30:27.638 ERROR 25228 --- [ main] com.alibaba.druid.pool.DruidDataSource : init datasource error, url: jdbc:…

【安全每日一讲】API是什么?解密API背后的奥秘

什么是API? API全称Application Programming Interface,即应用程序编程接口,是一些预先定义的函数,或指软件系统不同组成部分衔接的约定,用于传输数据和指令,使应用程序之间可以集成和共享数据资源。 简单来说&#…

thinkphp8 framework和 element plus admin前后端分离系统之PHP安装教程

DIYGW-UI-PHP是一款基于thinkphp8 framework和 element plus admin开发而成的前后端分离系统。目的是结合现有diygw-ui打造一个后台API开发。 实现PHP源码前请先下载小皮面板或者宝塔。 系统已经集成了部分功能 用户管理 后台用户管理部门管理 配置公司的部门结构&#xff0…

用红黑树封装出map与set

目录 一、红黑树的改造 节点结构的定义 迭代器类的实现 红黑树中提供迭代器 红黑树的主要代码 二、set的实现 三、map的实现 四、测试代码 map与set的底层都是红黑树,所以本篇文章就分享如何用同一颗红黑树封装出map与set 所以大家可以先去看一下我的讲解红…

先有JVM还是先有垃圾回收器?很多人弄混淆了

是先有垃圾回收器再有JVM呢,还是先有JVM再有垃圾回收器呢?或者是先有垃圾回收再有JVM呢?历史上还真是垃圾回收更早面世,垃圾回收最早起源于1960年诞生的LISP语言,Java只是支持垃圾回收的其中一种。下面我们就来刨析刨析…

ue引擎游戏开发笔记(38)——实现敌人接收攻击伤害,并作出反应

1.需求分析: 现在已经显示造成实际伤害,但敌人对实际伤害并未产生反馈,例如还击,或者死亡倒地等等,实现敌人对于受击的反馈。 2.操作实现: 1.思路:在动画蓝图中添加死亡动画,并通过…

wefaf

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话: 知不足而奋进,望远山而前行&am…

Python 渗透测试:反弹 shell (反弹 后门 || 程序免杀)

什么叫 反弹 shell 反弹 shell (Reverse Shell) 是一种常见的渗透测试技术,它指的是受害者主机主动连接攻击者的主机,从而让攻击者获得对受害者主机的控制权。在一个典型的反弹 shell 攻击中,攻击者会在自己的主机上监听一个特定的端口,然后诱使目标主机主动连接到这个端口。当…

Cadence 16.6 绘制PCB封装时总是卡死的解决方法

Cadence 16.6 绘制PCB封装时总是卡死的解决方法 在用Cadence 16.6 PCB Editor绘制PCB封装时候,绘制一步卡死一步,不知道怎么回事儿,在咨询公司IT后,发现是WIN系统自带输入法的某些热键与PCB Editor有冲突,导致卡死。 …

网络地址转换(nat,easy ip,nat server)资源上传

实验概述 由内到外 nat,easy ip,转换的是源ip nat server 由外到内,转换的是目的IP 实验拓扑 结果验证 nat实验得到结果 1.ar1到ar3没有路由也可以访问 2.ar3配置telent后ar1也可以通过telnet远程配置 esay ip 如果ar2 g0/0/1接口ip非固…

Qwen 开源标杆

Qwen的博客 在线体验Qwen开源版本、非常丝滑 不算量化、已经开源的Qwen1.5 版本有9个: 0.5B、1.8B、4B、7B、14B、32B、72B、110B、MoE-A2.7B 闭源已经发展到 Qwen-Max-0428、网页端从2.1升级到2.5 Qwen API详情 一些记录: 1、Qwen1.5 110B&#x…

汇舟问卷:5年专业经验,海外渠道查无需烦恼!

大家好,我是汇舟问卷,拥有五年的行业经验,专注于海外问卷渠道查。 在海外问卷渠道查领域,我们拥有专业的知识和经验。无需为购买大量海外邮箱而烦恼,更无需担忧账号被封禁的风险。我们提供全天候24小时的服务&#xf…

通过视频生成实现基于物理的3D对象交互——PhysDreamer

随着虚拟现实(VR)和增强现实(AR)技术的飞速发展,用户对于虚拟体验的真实性提出了更高的要求。在这样的背景下,PhysDreamer应运而生,它是一项创新的技术,能够为静态3D对象赋予逼真的物理交互动态,极大地丰富了虚拟环境的…

Windows内核函数 - ASCII字符串和宽字符串

本章介绍了Windows内核中字符串处理函数、文件读写函数、注册表读写函数。这些函数是DDK提供的运行时函数,他们比标准C语言的运行时函数功能更丰富。普通的C语言运行时库是不能在内核模式下使用的,必须使用DDK提供的运行时函数。 和应用程序一样&#xf…

四川景源畅信:如何更好的为抖音小店做引流?

在数字化营销的浪潮中,抖音小店作为新兴的电商形态,正以其独特的社交属性和流量优势吸引着众多商家的目光。如何为抖音小店引流,成为许多店主心中的疑问。本文将深入探讨有效提升店铺流量的策略,助你在抖音平台上快速崛起。 一、内…

云飞云共享云桌面如何降低电脑投入成本?

云飞云共享云桌面作为一种创新的云计算解决方案,以其独特的优势在业界赢得了众多认可。其中,它极大地降低了电脑投入成本,为企业和个人用户带来了实实在在的经济效益。那么,云飞云共享云桌面是如何实现这一点的呢? 设…

pytest教程-46-钩子函数-pytest_sessionstart

领取资料,咨询答疑,请➕wei: June__Go 上一小节我们学习了pytest_report_testitemFinished钩子函数的使用方法,本小节我们讲解一下pytest_sessionstart钩子函数的使用方法。 pytest_sessionstart 是 Pytest 提供的一个钩子函数&#xff0c…