顺序存储
顺序队列推荐使用循环队列,防止在递归、循环过程中数组越界。代码长度主要因为注释和打印过程,本身很简单。
// StackQueue.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// 对于栈来说:top指向栈顶元素的位置
// 顺序队列得用循环队列
// 对于顺序队列,rear指向最后一个元素位置的后一个位置,牺牲一个节点来判断是满还是空
// 初始化:Q.front = Q.rear = 0
// 进队:Q.rear = (Q.rear + 1) % M
// 出队:Q.front = (Q.front + 1) % M
// 队空:Q.front == Q.rear
// 队满:(Q.rear + 1) % M == Q.front
// 队列长度: (Q.rear - Q.front + M) % M
#include <iostream>
using namespace std;
const int M = 4;
struct record
{
int x;
int y;
};
typedef struct StackNode
{
record data[M];
int top;
}*SeStack;
typedef struct QueNode
{
record data[M];
int front, rear;
}*SeQue;
SeStack S = new StackNode;
SeQue Q = new QueNode;
void InitStack(SeStack S)
{
S->top = -1;
}
void InitQue(SeQue Q)
{
//考虑循环队列,首尾都为0,这样添加元素后rear++,front不动
//队列:先进先出,尾进头出
Q->front = Q->rear = 0;
}
void StackPush(SeStack S, record val)
{
if (S->top < M)
{
S->top++;
S->data[S->top] = val;
}
else
cout << "Stack is full" << endl;
}
void QuePush(SeQue Q, record val)
{
if ((Q->rear + 1) % M == Q->front)
cout << "Queue is full" << endl;
else
{
Q->data[Q->rear] = val;
Q->rear = (Q->rear + 1) % M;
}
}
bool StackEmpty(SeStack S)
{
if (S->top == -1)
return true;
else
return false;
}
bool QueEmpty(SeQue Q)
{
if (Q->front == Q->rear)
return true;
else
return false;
}
void StackPop(SeStack S)
{
if (!(StackEmpty(S)))
{
S->top--;
}
else
cout << "Stack is empty" << endl;
}
void QuePop(SeQue Q)
{
if (!QueEmpty(Q))
{
Q->front = (Q->front + 1) % M;
}
else
cout << "Queue is Empty" << endl;
}
void StackPrint(SeStack S)
{
for (int i = 0; i < S->top + 1; i++)
{
cout << "S->data[" << i << "].x:" << S->data[i].x << "\tS->data[" << i << "].y:" << S->data[i].y << endl;
}
}
//int QueLength(SeQue Q)
//{
// int length = (Q->rear - Q->front + M ) % M;
// return length;
//}
void QuePrint(SeQue Q)
{
int length = (Q->rear - Q->front + M) % M;
if (QueEmpty(Q))
cout << "Queue is Empty" << endl;
else
{
for (int i = Q->front, j = 0; j < length; i = (i + 1) % M, j++)
{
cout << "Q->data[" << j << "].x:" << Q->data[i].x << "\tQ->data[" << j << "].y:" << Q->data[i].y << endl;
//Q->front = (Q->front + 1) % M;
}
}
}
int main()
{
record a{}, b{}, c{}, d{};
a.x = 1;
a.y = 1;
b.x = 2;
b.y = 2;
c.x = 3;
c.y = 3;
d.x = 4;
d.y = 4;
cout << "InitStack" << endl;
InitStack(S);
cout << "push(a)" << endl;
StackPush(S, a);
StackPrint(S);
cout << "push(b)" << endl;
StackPush(S, b);
StackPrint(S);
cout << "pop()" << endl;
StackPop(S);
StackPrint(S);
cout << "InitQue" << endl;
InitQue(Q);
cout << "push(a)" << endl;
QuePush(Q, a);
QuePrint(Q);
cout << "push(b)" << endl;
QuePush(Q, b);
QuePrint(Q);
cout << "puch(c、d)" << endl;
QuePush(Q, c);
QuePush(Q, d);
QuePrint(Q);
cout << "pop()" << endl;
QuePop(Q);
QuePrint(Q);
cout << "push(d) again" << endl;
QuePush(Q, d);
QuePrint(Q);
cout << "pop()" << endl;
QuePop(Q);
QuePrint(Q);
}
输出结果
链式存储
加的很多输出只是为了测试写的逻辑是否正确,使用时应该删除,链栈和链队列使用自定义节点record。
// Stack_Queue_DS.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
using namespace std;
//数据格式
struct record
{
int x;
int y;
};
typedef struct StackNode
{
record data;
StackNode* next;
}*LinkStack;
typedef struct QueNode
{
record data;
QueNode* next;
}*Que;
typedef struct
{
Que front;
Que rear;
}LinkQue;
/*
//为S new一个空间后,S notnull,如果不new,S null
LinkStack S = new StackNode;
*/
//这样声名的话,对应的要用顺序插入法,否则会报nullptr
LinkStack S;
LinkStack S1;
//LinkStack S2;
LinkQue Q;
LinkQue Q1;
//带头结点的方法
void StackPush(LinkStack& S, record val)
{
//这里临时节点p必须申请空间,否则p只是一个指针(地址),不能使用p->data,会报错:未初始化的局部变量p
LinkStack p = new StackNode;
/*p->data.x = val.x;
p->data.y = val.y;*/
p->data = val;
/*
//头插法
p->next = S->next;
S->next = p;
*/
//直接插入法
p->next = S;
S = p;
}
//测试通过,函数正确
bool StackEmpty(LinkStack& S)
{
if (S == NULL)
{
//cout << "判空函数这样认为:NULL" << endl;
return true;
}
else
{
//cout << "判空函数这样认为:notNULL" << endl;
return false;
}
}
void StackPop(LinkStack& S)
{
if (StackEmpty(S))
{
cout << "栈为空!" << endl;
return;
}
else
{
LinkStack temp = new StackNode;
temp = S;
S = S->next;
delete temp;
}
}
void StackPrint(LinkStack& S)
{
while(!StackEmpty(S))
{
cout << "****" << endl;
StackPush(S1, S->data);
cout << "S->data.x:" << S->data.x << " S->data.y:" << S->data.y << endl;
StackPop(S);
}
while(!StackEmpty(S1))
{
cout << "++++" << endl;
cout << "S1->data.x:" << S1->data.x << " S1->data.y:" << S1->data.y << endl;
StackPush(S, S1->data);
StackPop(S1);
}
}
void InitQue(LinkQue& Q)
{
Q.front = Q.rear= new QueNode;
}
void QuePush(LinkQue& Q, record val)
{
Que temp = new QueNode;
temp->data = val;
Q.rear->next = temp;
Q.rear = temp;
}
bool QueEmpty(LinkQue& Q)
{
if (Q.front == Q.rear)
return true;
else
return false;
}
void QuePop(LinkQue& Q)
{
if(!QueEmpty(Q))
{
//删除的时候好像可以不申请临时节点的空间
Que temp;
temp = Q.front;
Q.front = Q.front->next;
delete temp;
}
}
//队列:先进先出!尾进头出!!
void PrintQue(LinkQue& Q)
{
while(!QueEmpty(Q))
{
cout << "*****************" << endl;
cout << "Q.front->next->date.x:" << Q.front->next->data.x << " Q.front->next->data.y:" << Q.front->next->data.y << endl;
QuePush(Q1, Q.front->next->data);
//QuePop(Q);//这是队列又不是栈!!!
Q.front = Q.front->next;
}
while(!QueEmpty(Q1))
{
cout << "+++++++++++++++++" << endl;
cout << "Q1.front->next->data.x:" << Q1.front->next->data.x << " Q1.front->next->data.y:" << Q1.front->next->data.y << endl;
QuePush(Q, Q1.front->next->data);
Q1.front = Q1.front->next;
}
}
void main() {
//S = NULL;
//S->next = NULL;
/*if (S == NULL)
cout << "NULL" << endl;
else
cout << "NotNULL" << endl;
StackEmpty(S);*/
record a{};
a.x = 1;
a.y = 2;
record b{};
b.x = 3;
b.y = 4;
StackPush(S, a);
StackPush(S, b);
StackPrint(S);
/*if (S == NULL)
cout << "NULL" << endl;
else
cout << "NotNULL" << endl;
StackEmpty(S);*/
StackPop(S);
StackPrint(S);
StackPrint(S);
//指针测试
int x = 5;
//int* p = new int;
int* p = &x;
cout << p << " " << *p << " " << &p << endl;
//delete p;
//cout << p << " " << *p << " " << &p << endl;
//如果int* p =new int,报错:引发了异常: 读取访问权限冲突。
//p 是 0x8123。问题:空指针/野指针,也就是说delete了
//如果int* p = &x,报错:(会自动跳到一个delete_scalar.cpp的文件内)已在 Stack_Queue_DS.exe 中执行断点指令(__debugbreak()语句或类似调用)。
//问题:内存越界,但是注释掉打印仍然这么报错,delete注释就不再报错,推测为没有申请空间不能delete,但是为什么pop函数里可以这样?
//指针到底需不需要delete,是由其指向的内存区域决定的
//栈中的变量,是由程序自动进行管理的,当变量作用域结束后,程序就会自动释放,因此其内存区域不需要手动delete
//堆则是一种容量大,但效率很低的内存区域,需要用户手动去进行管理(自动管理会影响程序性能),必须手动delete
//所以答案就是,指向栈内存的指针不需要delete,指向堆内存的指针需要delete
InitQue(Q);
InitQue(Q1);
QuePush(Q, a);
QuePush(Q, b);
PrintQue(Q);
QuePop(Q);
PrintQue(Q);
}