数据结构——队列

目录

一、队列的定义

二、队列的实现

1. 队列的顺序存储结构

1.1. 顺序队

1. 创建顺序队

2. 删除顺序队

3. 判断队列是否为空

4. 判断队列是否已满

5. 入队

6. 出队

7. 获取队列长度

8. 获取队首元素 

1.2. 环形队

1. 创建环形队

2. 删除环形队

3. 判断环形队列是否为空 

4. 判断环形队列是否已满

5. 入队

6. 出队

7. 获取队列长度

8. 获取队首元素

2. 队列的链式存储结构

1. 创建链队

2. 删除链队

3. 判断链队是否为空

4. 入队

5. 出队

6. 获取队首元素

7. 获取链队长度 

三、队列的应用

1. 银行业务队列简单模拟

2. 求解迷宫从入口到出口的一条最短路径

四、总结


一、队列的定义

队列中的数据元素的逻辑关系呈线性关系,可以说队列也是一种线性表,队列可以像线性表一样采用顺序存储结构存储,也可以使用链式存储结构进行存储。使用顺序存储结构的队列称为顺序队,使用链式存储结构的队列称为链队。

队列和栈类似,栈只能在一端进行删除和插入操作,而队列也是一种操作受限的线性表,其限制为仅允许在表的一端进行插入操作,而在表的另一端进行删除操作。进行插入的一端称为队尾,进行删除的一端称为队首。向队列中插入新元素称为进队或入队,新元素进入队列后就成为新的队尾元素;从中删除元素称为出队或离队,元素出队后,其直接后继元素就成为队首元素。如下图所示。

二、队列的实现

1. 队列的顺序存储结构

队列使用顺序存储结构存储相对比较简单,操作和栈类似,但有几点地方需要注意,队列有两端可以操作,需要两个指针或索引,队列是否为空和入队和出队需要队考虑几种情况。

要使用顺序存储结构存储队列,需要将队列元素映射到顺序表中,顺序表地址都是连续的,队列元素可以直接按照顺序映射到属性表中,如下图所示。

只要确定了队首元素所在顺序表的位置,其他的元素按照顺序接入即可。一般队首元素是位于顺序表的首地址,不过在顺序队进行出队操作后队首元素位置会不断后移。

顺序队的定义:

template<typename T>
class MyQueue
{
private:T* data; // 队列顺序存储结构int front, rear; // 队首索引,队尾索引int size;    // 队列长度public:// 构造函数MyQueue();// 析构函数~MyQueue();// 入队bool push(T value);// 出队bool pop();// 判断队满bool full();// 判断队空bool empty();// 获取队首元素T getFront();// 获取队列长度int getSize();
};

 顺序队有两种实现方式,一种是普通的顺序队,即元素按顺序存储,入队后队尾位置不断后移,出队后队首位置也不断后移,也就是队列可存储的空间只会越来越少,就算队首出队,队列的空间也不会增多,队列会在一次次入队操作后接近满队,会存在大量的空间浪费。另一种就是改进的顺序队,即环形队,环形队会在空间不够用时,从数组首地址从新开始存储,类似于循环链表,能够循环利用数组空间。

1.1. 顺序队

顺序队按顺序存储队列元素,插入元素时与栈类似,先将队尾索引加一再将对应位置写入新元素的值,不过在第一次插入元素时需要多一步操作。删除元素是将队首索引先加一再新索引位置写入新元素的值,在队列只剩一个元素的时候需要进行特殊的处理。

1. 创建顺序队

创建一个空的顺序队需要申请一片连续的存储空间(数组)用于存储队列元素,再初始化索引front和rear以及队列长度size。front和size初始化都为-1,size初始化为0 。

	MyQueue() {data = new T[MAXSIZE2];front = rear = -1;size = 0;}
2. 删除顺序队

删除顺序队只需要将申请的存储空间全部释放即可。

	~MyQueue() {delete[] data;}
3. 判断队列是否为空

判断条件是front和rear的值为初始值-1(队列出队得只剩一个元素的时候也会将front和rear设置为初始值-1)。

	bool empty() {return (front == -1 && rear == -1);}
4. 判断队列是否已满

顺序队的存储空间跟存储数组的大小有关,存储数组的大小是事先设定的宏定义值MAXSIZE,判断队尾索引是否等于MAXSIZE-1(数组地址从0开始)。

	bool full() {return rear == MAXSIZE2 - 1;}
5. 入队

入队和出队相较于栈要麻烦一点,需要多一步判断。在队列为空的时候入队不能只将rear的值加一,因为此时front为-1,只修改rear的值的话,访问队首的时候front为-1就会出错,因此需要同时修改front和rear的值,将它们的值都修改为0 。此外,顺序队因为存储结构的原因,队列是会满的(跟存储数组的大小相关),队列满时无法入队,返回false。

其他正常情况下,入队的操作为,将rear索引后移一位,将新元素的值写入新rear的位置,即将新元素插入到存储数组的末尾。如下图所示。

	bool push(T value) {// 队列满if (full()) {return false;}// 队列空,修改rear和front的值为0,否则无法访问队首元素if (empty()) {rear = front = 0;}// 其他情况,在原队尾元素的下一个位置插入元素else {rear++;}// 写入新元素的值data[rear] = value;// 入队操作后队列长度加一size++;return true;}
6. 出队

出队操作只需将front索引后移一位即可,不用修改front索引元素的值。但在队列只有一个元素的时候需要将front和rear的值都改为初始值,因为队列为空的条件是front和rear的值都为-1 。如下图。

	bool pop() {// 队列空if (empty()) {return false;}if (front == rear) {front = rear = -1;}else {front++;}size--;return true;}
7. 获取队列长度
	int getSize() {return size;}

完整MyQueue类:

#pragma once
#define MAXSIZE2 10000
#include<stdexcept>
using namespace std;
template<typename T>
class MyQueue
{
private:T* data;int front, rear;int size;public:MyQueue() {data = new T[MAXSIZE2];front = rear = -1;size = 0;}~MyQueue() {delete[] data;}bool push(T value) {// 队列满if (full()) {return false;}// 队列空,修改rear和front的值为0,否则无法访问队首元素if (empty()) {rear = front = 0;}// 其他情况,在原队尾元素的下一个位置插入元素else {rear++;}// 写入新元素的值data[rear] = value;// 入队操作后队列长度加一size++;return true;}bool pop() {// 队列空if (empty()) {return false;}// 队列只剩一个元素,出队后将front和rear的值都设为初始值// front和rear都为初始值才能判断队列为空if (front == rear) {front = rear = -1;}// 其他情况,将front索引后移一位即可else {front++;}size--;return true;}bool full() {return rear == MAXSIZE2 - 1;}bool empty() {return (front == -1 && rear == -1);}T getFront() {if (empty()) {throw out_of_range("队列为空,无法访问队首元素");}return data[front];}int getSize() {return size;}
};
8. 获取队首元素 
	T getFront() {if (empty()) {throw out_of_range("队列为空,无法访问队首元素");}return data[front];}

测试:

对队列的empty()、getSize()、push()、pop()操作都测试一遍。

	MyQueue<string> qu;cout << "队列是否为空:" << qu.empty() << "\t队列长度:" << qu.getSize() << endl;cout << "入队:'lin'" << endl;qu.push("lin");cout << "队列是否为空:" << qu.empty() << "\t队列长度:" << qu.getSize() << "\t队首元素:" << qu.getFront() << endl;cout << "入队:'zixi'" << endl;qu.push("zixi");cout << "队列是否为空:" << qu.empty() << "\t队列长度:" << qu.getSize() << "\t队首元素:" << qu.getFront() << endl;cout << "出队" << endl; qu.pop();cout << "队列是否为空:" << qu.empty() << "\t队列长度:" << qu.getSize() << "\t队首元素:" << qu.getFront() << endl;cout << "出队" << endl;qu.pop();cout << "队列是否为空:" << qu.empty() << "\t队列长度:" << qu.getSize() << endl;

测试结果:

测试结果正确。 

1.2. 环形队

1. 创建环形队

环形队只在rear和front索引操作上与顺序队不同,其他的操作都是一样的。

	CirQueue() {data = new T[MAXSIZE2];front = rear = -1;size = 0;}
2. 删除环形队
	~CirQueue() {delete[] data;}
3. 判断环形队列是否为空 
	bool empty() {return (front == -1 && rear == -1);}
4. 判断环形队列是否已满

判断环形队列是否已满与顺序队不同,顺序队只需要判断尾索引是否达到最大的索引,而环形队列的存储空间是循环利用的,队尾索引到达最大索引时会返回数组首地址再顺序往下,判断环形队列已满的条件应该时rear的下一个位置刚好时front的位置,因为环形队列时循环利用数组空间的,rear+1需要对MAXSIZE取余。下图就是一个满的环形队列。

	bool full() {return (rear + 1) % MAXSIZE2 == front;}
5. 入队

具体操作其实和顺序队很相似,只是rear加一的时候需要队MAXSIZE取余。如下图所示。

	bool push(T value) {// 队列满if (full()) {return false;}// 队列空,修改rear和front的值为0,否则无法访问队首元素if (empty()) {rear = front = 0;}else {rear = (rear + 1) % MAXSIZE2;}data[rear] = value;size++;return true;}
6. 出队

与入队一样,元素出队的时候front+1时需要对MAXSIZE取余,其余操作与顺序队一样。

	bool pop() {// 队列空if (empty()) {return false;}// 队中只有一个元素if (front == rear) {front = rear = -1;}else {front = (front + 1) % MAXSIZE2;}size--;return true;}
7. 获取队列长度
	int getSize() {return size;}
8. 获取队首元素
	T getFront() {if (empty()) {throw out_of_range("队列为空,无法访问队首元素");}return data[front];}

测试:

对于环形队列,测试需要体现它的特性,即存储空间循环利用,再一个元素出队列后,队列可用空间会增加。回了简化测试,将MAXSIZE的值改为2,先插入两个元素,再插入一个元素,此时队列满了,无法插入,进行出队操作后可以插入。

	// 循环队列CirQueue<string> qu;cout << "队列是否为空:" << qu.empty() << "\t队列长度:" << qu.getSize() << endl << endl;cout << "入队:'lin'" << endl;qu.push("lin");cout << "队列是否为空:" << qu.empty() << "\t队列长度:" << qu.getSize() << "\t队首元素:" << qu.getFront() << endl << endl; cout << "入队:'zi'" << endl;qu.push("zi");cout << "队列是否为空:" << qu.empty() << "\t队列长度:" << qu.getSize() << "\t队首元素:" << qu.getFront() << endl << endl;cout << "入队:'xi'" << endl;cout << "入队是否成功:" << qu.push("xi") << endl;cout << "队列是否为空:" << qu.empty() << "\t队列长度:" << qu.getSize() << "\t队首元素:" << qu.getFront() << endl << endl;cout << "出队" << endl;qu.pop();cout << "队列是否为空:" << qu.empty() << "\t队列长度:" << qu.getSize() << "\t队首元素:" << qu.getFront() << endl << endl;cout << "入队:'xi'" << endl;cout << "入队是否成功:" << qu.push("xi") << endl;cout << "队列是否为空:" << qu.empty() << "\t队列长度:" << qu.getSize() << "\t队首元素:" << qu.getFront() << endl << endl;cout << "出队" << endl;qu.pop();cout << "队列是否为空:" << qu.empty() << "\t队列长度:" << qu.getSize() << "\t队首元素:" << qu.getFront() << endl << endl;cout << "出队" << endl;qu.pop();cout << "队列是否为空:" << qu.empty() << "\t队列长度:" << qu.getSize() << endl;

测试结果:

 从上图可以看到,再插入两个元素”lin”和“zi”后,队列此时已满,再插入一个元素会失败,将队首出队后,"xi"就能成功插入了。

2. 队列的链式存储结构

顺序队有一个很明显的缺陷,可用空间有限,而且是实现定义的,无法动态扩充,且会出现空间浪费的情况。为了解决这些问题,可以使用链式存储结构来存储队列。链式存储就是使用链表存储。

链队实现起来其实也比较简单,因为只需要对两端进行操作,比链表的操作简单很多。

链队需要一个结点结构,包含结点的信息和下一个结点的地址,同时为其定义一个有参构造函数,定义如下:

template<typename T>
struct QueNode
{T data;QueNode* next;QueNode(T value) {data = value;next = NULL;}
};

链队的定义如下:

template<typename T>
class LkQueue
{
private:// 队首结点指针QueNode<T>* front;// 队尾结点指针QueNode<T>* rear;// 队列长度int size;public:// 无参构造,创建空链队LkQueue();// 析构函数,删除链队~LkQueue();// 判断链队是否为空bool empty();// 入队void push(T value);// 出队bool pop();// 获取队首元素T getFront();// 获取队列长度int getSize();
};
1. 创建链队

初始化front和rear指针为空指针NULL,size为0。

	LkQueue() {front = rear = NULL;size = 0;}
2. 删除链队

删除链队即删除链队存储的链表,链表删除方式之前已经介绍过了。遍历链表的每一个结点,删除即可。

	~LkQueue() {while (front != NULL){// 保存front指针,用于删除QueNode<T>* temp = front;// front继续指向下一个结点,需要在删除结点前,否则无法取nextfront = front->next;delete temp;}}
3. 判断链队是否为空

判断链队是否为空的条件式front和rear指针都为NULL;

	bool empty() {return (front == NULL && rear == NULL);}
4. 入队

链队不用担心空间不够的问题,只需要在首次入队的时候将front和rear同时指向新结点,其他情况使用尾插法插入新结点即可。

	void push(T value) {QueNode<T>* newNode = new QueNode<T>(value);// 如果是空链队,则初始化front和rear同时指向新结点if (empty()) {front = rear = newNode;}else {// 尾插法添加新结点rear->next = newNode;rear = newNode;}size++;}
5. 出队

链队出队与顺序队不一样,顺序队只需要将指针往下移就可以了,因为数组的存储空间不能只释放一块的地址,所以不需要释放空间也不需要修改该位置的值(环形队也不需要,它会在下一次插入到该位置时修改该位置的值),而链队的结点出队后不会再使用到它,而且它是单独存放在一个地址,可以直接释放。出队时,front指向front->next,同时释放front指向的地址空间。

	bool pop() {if (empty()) {return false;}// 链队和顺序队不一样,链队结点出队后,这块空间就不会再被使用了,需要删除QueNode<T>* temp = front;front = front->next;delete temp;size--;}
6. 获取队首元素
	T getFront() {if (empty()) {throw out_of_range("队列为空,无法访问队首元素");}return front->data;}
7. 获取链队长度 
	int getSize() {return size;}

完整的链队类:

#pragma once
template<typename T>
struct QueNode
{T data;QueNode* next;QueNode(T value) {data = value;next = NULL;}
};
template<typename T>
class LkQueue
{
private:QueNode<T>* front;QueNode<T>* rear;int size;public:// 无参构造,创建空链队LkQueue() {front = rear = NULL;size = 0;}// 析构函数,删除链队~LkQueue() {while (front != NULL){// 保存front指针,用于删除QueNode<T>* temp = front;// front继续指向下一个结点,需要在删除结点前,否则无法取nextfront = front->next;delete temp;}}bool empty() {return (front == NULL && rear == NULL);}void push(T value) {QueNode<T>* newNode = new QueNode<T>(value);// 如果是空链队,则初始化front和rear同时指向新结点if (empty()) {front = rear = newNode;}else {// 尾插法添加新结点rear->next = newNode;rear = newNode;}size++;}bool pop() {if (empty()) {return false;}// 链队和顺序队不一样,链队结点出队后,这块空间就不会再被使用了,需要删除QueNode<T>* temp = front;front = front->next;delete temp;size--;}T getFront() {if (empty()) {throw out_of_range("队列为空,无法访问队首元素");}return front->data;}int getSize() {return size;}
};

三、队列的应用

使用队列完成两道pta的题目来实际应用一下队列。

1. 银行业务队列简单模拟

设某银行有A、B两个业务窗口,且处理业务的速度不一样,其中A窗口处理速度是B窗口的2倍 —— 即当A窗口每处理完2个顾客时,B窗口处理完1个顾客。给定到达银行的顾客序列,请按业务完成的顺序输出顾客序列。假定不考虑顾客先后到达的时间间隔,并且当不同窗口同时处理完2个顾客时,A窗口顾客优先输出。

输入格式:

输入为一行正整数,其中第1个数字N(≤1000)为顾客总数,后面跟着N位顾客的编号。编号为奇数的顾客需要到A窗口办理业务,为偶数的顾客则去B窗口。数字间以空格分隔。

输出格式:

按业务处理完成的顺序输出顾客的编号。数字间以空格分隔,但最后一个编号后不能有多余的空格。

输入样例:

8 2 1 3 9 4 11 13 15

输出样例:

1 3 2 9 11 4 13 15
#include<iostream>
#include<queue>
using namespace std;
int main()
{int n,s,x,l=0;cin>>n;queue<int> q1,q2;while(n--){cin>>s;if(s%2==0)q2.push(s);elseq1.push(s);}while(!q2.empty() || !q1.empty()){// 格式问题,需要分两种情况输出if(l==0 && !q1.empty()){x=q1.front();cout<<x;q1.pop();x=q1.front();cout<<" "<<x;q1.pop();l++;}else{for(int i=0;i<2;i++)if(!q1.empty()){	x=q1.front();cout<<" "<<x;q1.pop();}}if(!q2.empty()){x=q2.front();if(l==0){cout<<x;l++;}elsecout<<" "<<x;q2.pop();}}
}

这是当初学数据结构时写的代码,写得有点乱,为了偷懒还直接用的c++的queue类,没有自己实现。这题也没什么难度,就是q1和q2依次出队,每轮出队,q1优先出队,而且出队两个,q2次之,每次出一个,依次输出就好了。

2. 求解迷宫从入口到出口的一条最短路径

求解迷宫从入口到出口的一条最短路径。输入一个迷宫,求从入口通向出口的一条可行最短路径。为简化问题,迷宫用二维数组 int maze[10][10]来存储障碍物的分布,假设迷宫的横向和纵向尺寸的大小是一样的,并由程序运行读入, 若读入迷宫大小的值是n(3<n<=10),则该迷宫横向或纵向尺寸都是n,规定迷宫最外面的一圈是障碍物,迷宫的入口是maze[1][1],出口是maze[n-2][n-2], 若maze[i][j] = 1代表该位置是障碍物,若maze[i][j] = 0代表该位置是可以行走的空位(0<=i<=n-1, 0<=j<=n-1)。求从入口maze[1][1]到出口maze[n-2][n-2]可以走通的路径。要求迷宫中只允许在水平或上下四个方向的空位上行走,走过的位置不能重复走,规定必须按向右、向下、向左、向上的顺序向前搜索试探,输出先到达出口的最短路径。
如下这样一个迷宫:

dddd.png

对应的二维数组表示:
int maze[10][10]={
{1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,0,0,1,1,0,0,1},
{1,0,1,1,1,0,0,0,1,1},
{1,0,0,0,1,0,0,0,1,1},
{1,0,1,0,0,0,1,0,0,1},
{1,1,1,1,0,1,1,0,1,1},
{1,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1}};

输入格式:

输入迷宫大小的整数n, 以及n行和n列的二维数组(数组元素1代表障碍物,0代表空位)。

输出格式:

输出按规定搜索试探顺序先到达出口的首条最短路径,依次输出从入口到出口可行最短路径每个位置的行列下标(i,j),每个位置间用“,”分隔。若没有通路,输出:NO。

输入样例1:

4
1 1 1 1
1 0 1 1
1 0 0 1
1 1 1 1

输出样例1:

(1,1)(2,1)(2,2)

输入样例2:

10
1 1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 0 1 0 1
1 0 0 1 0 0 0 1 0 1
1 0 0 0 0 1 1 0 0 1
1 0 1 1 1 0 0 0 0 1
1 0 0 0 1 0 0 0 0 1
1 0 1 0 0 0 1 0 0 1
1 0 1 1 1 0 1 1 0 1
1 1 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1

输出样例2:

(1,1)(2,1)(3,1)(4,1)(5,1)(5,2)(5,3)(6,3)(6,4)(6,5)(7,5)(8,5)(8,6)(8,7)(8,8)

求迷宫的最短路径用广度优先搜索最合适,广度优先搜索跟树的层次遍历一样,从根依次向下遍历,每次优先遍历一层的结点,然后再向下一层遍历。

使用广度优先搜索求解的步骤是:首先将起点可以达到的点添加进队列中,然后从这个队列中依次取结点出来遍历,当前结点扩展完结点后将子结点全部加入到队列中,重复上面的步骤直到找到一条通路,这题通路就是最短路径。由于子结点都是在父结点的兄弟结点都添加进队列后才进入的队列,因此遍历时会是前一层的结点都遍历完后才到下一层的结点,依次就可以实现广度优先遍历。为什么广度遍历求出的解是最短路径呢?因为广度优先搜索是按层次遍历的,每一层都是当前路径长度下所有的路径,每次增加一个路径长度,遍历该路径长度下所有的路径,第一次出现通路那就一定是最短的路径。

代码:

#include<iostream>
#include<queue>
#define Maxsize 100
struct Box
{int i;int j;
}e,pre[Maxsize][Maxsize];
void print(Box t);
using namespace std;
int main()
{int di_x[4]={-1,0,1,0};int di_y[4]={0,1,0,-1};int n,i,j,x,y,flag=0,tx,ty;queue<Box> qe;cin>>n;int sx,sy,fx,fy;sx=sy=1;fx=fy=n-2;	//定义起点和终点 e.i=sx;e.j=sy;qe.push(e);int mg[n][n]={0};mg[sx][sy]=-1;for(i=0;i<n;i++)for(j=0;j<n;j++)cin>>mg[i][j];while(!qe.empty()){e=qe.front();x=e.i;y=e.j;if(x==n-2 && y==n-2){ flag=1;break;}for(i=0;i<4;i++){tx=x+di_x[i],ty=y+di_y[i];if(mg[tx][ty]==0){e.i=tx;e.j=ty;pre[tx][ty]=qe.front();qe.push(e);mg[tx][ty]=-1;}}                qe.pop();}if(flag==0){cout<<"NO"<<endl;exit(0);} Box fin={fx,fy};print(fin);cout<<endl;
}
void print(Box t)
{if(t.i==1 && t.j==1){cout<<"("<<t.i<<","<<t.j<<")";return;}print(pre[t.i][t.j]);cout<<"("<<t.i<<","<<t.j<<")";
}

这个也是当初初学的时候写的代码,我记得当初还没教广度优先遍历,这题应该是要用深度优先遍历暴力求解所有路径找出最短路径的,当时我为了偷懒就直接用广度优先遍历了。

上述代码实现起来也不难,每个结点都对应数组中的一个元素,找每个结点的可通往的结点就是寻找该元素上下左右四个元素中不是障碍物的因素,然后依次将这些结点加入队列就行了,终止条件是当前点是终点。

四、总结

队列与栈一样都是访问受限的线性表,栈是只能在一端进行删除和插入操作的线性表,而队列是只能在一端进行删除操作,在另一端进行插入操作。栈由于只能在一端操作,因此实现起来会很简单,而队列是在两端操作,实现起来比栈稍微麻烦一点,因为需要考虑两端的指针关系问题。

队列能在两端操作的特点导致如果向栈一样使用顺序表存储时会出现存储空间浪费的问题,因为队首和队尾位置会不断后移,而前面的地址空间都将不会在被使用到,导致大量的空间浪费,而且这样的队列很容易满,因为存储空间不会因为元素出队而增大,因此这种简单的顺序队我们一般都不会使用,而是使用更好的环形队,环形队列能够在rear达到最大索引的时候返回首地址继续往下存储,能够循环利用地址空间,不会有空间被浪费。

虽然环形队列相比顺序队列不会浪费空间,但它仍然收到数组空间的限制,不能超出申请的数组空间大小,而数组大小申请后就不能更改,通常会申请一个较大的空间,这样会和顺序表的缺陷一样,会有部分空间浪费,或者空间容易满,解决这个问题的方法就是使用链表存储队列,使用链表存储队列就不用担心存储空间不够的问题,且存储空间是动态变化的,不会有空间浪费。

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

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

相关文章

C++导出C标准的dll动态库

1 新建项目 1.1 使用VS新建一个空项目 1.2 在属性页中将配置类型改为&#xff1a;动态库(dll) 2 添加头文件 添加文件Api.h&#xff0c;示例代码如下 #pragma once#define DLLEXPORT __declspec(dllexport)extern "C" {DLLEXPORT int getAdd(int a, int b); //求…

C++中的多态你真的了解吗?多态原理全面具体讲解

目录 1. 多态的概念 2. 多态的定义及实现 2.1 多态的构成条件 2.2 虚函数 2.3 虚函数的重写 2.4 C11 override 和 final 2.5 重载、覆盖(重写)、隐藏(重定义)的对比 3. 抽象类 3.1 概念 4. 多态的原理 4.1 虚函数表 4.2多态的原理 4.3 动态绑定与静态绑定 5. 单继…

使用helpdesk帮助台有什么好处?

Helpdesk帮助台是一套帮助IT团队管理IT工单生命周期、自动化日常工作、优化工作流程的集合&#xff0c;它可以帮助IT团队提高生产力、降低成本、改善服务水平和客户体验。 而helpdesk帮助台管理软件所带来的好处不仅限于IT运营&#xff0c;所有利益相关者都会受益&#xff0c;…

【C语言必学知识点五】指针

指针 导言一、指针与指针变量二、指针变量的创建和指针类型三、指针类型的意义3.1 指针 /- 整数3.2 指针解引用 四、野指针4.1 定义4.2 野指针的成因4.3 指针未初始化4.4 指针越界访问4.5 指针指向的空间被释放4.6 如何规避野指针 五、指针运算5.1指针-整数5.2 指针-指针5.2.1 …

短剧分销平台开发,打造短剧内容变现新模式

短剧目前已经成为了影视行业中的一匹黑马&#xff0c;短剧主要是根据爽文小说翻拍&#xff0c;将小说中精彩高潮的剧情翻拍成短剧爽文&#xff0c;使得观众沉浸在短剧中&#xff0c;欲罢不能&#xff01; 短剧分销平台是短剧推广的新模式&#xff0c;它打破了传统的分销模式。…

代码随想录算法训练营 | day51 动态规划 309.最佳买卖股票时机含冷冻期,714.买卖股票的最佳时机含手续费

刷题 309.最佳买卖股票时机含冷冻期 题目链接 | 文章讲解 | 视频讲解 题目&#xff1a;给定一个整数数组&#xff0c;其中第 i 个元素代表了第 i 天的股票价格 。 设计一个算法计算出最大利润。在满足以下约束条件下&#xff0c;你可以尽可能地完成更多的交易&#xff08;多…

启动cad显示丢失mfc140u.dll怎么办?mfc140u.dll丢失有效解决方法分享

在CAD软件或其他软件中&#xff0c;有时候会出现由于找不到mfc140u.dll文件而无法执行代码的错误提示。这个问题可能是由于多种原因引起的&#xff0c;例如文件损坏、缺失或被病毒感染等。下面将介绍五个常见的解决方法&#xff0c;并解释mfc140u.dll丢失的原因以及该文件对CAD…

7-1 六度空间 (PTA-数据结构)

“六度空间”理论又称作“六度分隔&#xff08;Six Degrees of Separation&#xff09;”理论。这个理论可以通俗地阐述为&#xff1a;“你和任何一个陌生人之间所间隔的人不会超过六个&#xff0c;也就是说&#xff0c;最多通过五个人你就能够认识任何一个陌生人。”如图1所示…

Openwrt源码下载出现“The remote end hung up unexpected”

最近项目原因需要下载openwrt21.02版本源码&#xff0c;花费了很多时间&#xff0c;找到正确方法后&#xff0c;发现可以节省很多时间&#xff0c;记录下过程&#xff0c;方便自己&#xff0c;可能方便他人。 一.问题阐述 openwrt21.02下载链接如下&#xff1a; git clone -…

Python从入门到精通六:Python数据容器

数据容器入门 为什么学习数据容器 思考一个问题&#xff1a;如果我想要在程序中&#xff0c;记录5名学生的信息&#xff0c;如姓名。 如何做呢&#xff1f; 学习数据容器&#xff0c;就是为了批量存储或批量使用多份数据 Python中的数据容器&#xff1a; 一种可以容纳多份…

直播美颜SDK开发实战:从入门到精通

直播美颜SDK的应用已经成为许多直播平台和开发者关注的焦点。本文将带领读者深入探讨直播美颜SDK的开发实战&#xff0c;从入门到精通的过程。 1.引言 直播美颜SDK是一种集成了图像处理、人脸识别、滤镜算法等技术的开发工具包。通过使用该SDK&#xff0c;开发者能够为直播应…

深度学习 Day14——P3天气识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 文章目录 前言1 我的环境2 代码实现与执行结果2.1 前期准备2.1.1 引入库2.1.2 设置GPU&#xff08;如果设备上支持GPU就使用GPU,否则使用C…

2023 re:Invent使用 PartyRock 和 Amazon Bedrock 安全高效构建 AI 应用程序

前言 本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 亚马逊云科技开发者社区, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 “Your Data, Your AI, Your Future.&#xff08;你的数据&#xff0c;你的AI&…

HarmonyOS保存应用数据

数据管理 1 概述 在移动互联网蓬勃发展的今天&#xff0c;移动应用给我们生活带来了极大的便利&#xff0c;这些便利的本质在于数据的互联互通。因此在应用的开发中数据存储占据了非常重要的位置&#xff0c;HarmonyOS应用开发也不例外。 本文将为您介绍HarmonyOS提供的数据管…

统信UOS上图形化配置系统和应用代理

原文链接&#xff1a;统信UOS上图形化配置系统和应用代理 hello&#xff0c;大家好啊&#xff0c;今天我要给大家介绍的是在统信UOS操作系统上如何通过图形化界面配置系统代理和应用代理。在许多公司的内网环境中&#xff0c;直接访问互联网可能受到限制&#xff0c;但通常会提…

智慧工地源码:为施工企业提供专业落地的解决方案

智慧工地利用物联网、大数据、AI等核心技术&#xff0c;实时采集现场数据&#xff0c;自动分析&#xff0c;精准分析、智能决策、科学评价&#xff0c;形成一套数据驱动的新型管理模式。为施工企业提供生产提效、安全可控、成本节约的项目管理解决方案&#xff0c;提升项目部管…

关于linux 磁盘占用排查问题

1.关于磁盘 查看整体磁盘占用大小 df -h 2. 先排除mysql 数据大小 查询库的大小 SELECT table_schema AS "Database", ROUND(SUM(data_length index_length) / 1024 / 1024, 2) AS "Size (MB)" FROM information_schema.TABLES GROUP BY table_schema…

理解Mysql索引原理及特性

作为开发人员&#xff0c;碰到了执行时间较长的sql时&#xff0c;基本上大家都会说”加个索引吧”。但是索引是什么东西&#xff0c;索引有哪些特性&#xff0c;下面和大家简单讨论一下。 1 索引如何工作&#xff0c;是如何加快查询速度 索引就好比书本的目录&#xff0c;提高数…

【力扣】19. 删除链表的倒数第 N 个结点

19. 删除链表的倒数第 N 个结点 相比于昨天&#xff0c;感觉刷题越来越轻松了~ 我进步了&#xff01; 以后刷题力度要加快了&#xff0c;因为我报了蓝桥杯&#xff01;加油~ 法一&#xff1a;计算链表长度 思路&#xff1a; 首先用个函数来计算出该链表的长度&#xff0c;然…

C语言之⽂件操作

一为啥需要文件&#xff1f; 如果没有⽂件&#xff0c;我们写的程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&#xff0c;数据就丢失了&#xff0c;等再次运⾏程序&#xff0c;是看不到上次程序的数据的&#xff0c;如果要将数据进⾏持久化的保…