栈与队列
0、物理结构与逻辑结构(了解)
物理结构:简单来说,就是实实在在的存储结构,可分为顺序存储结构和链式存储结构。
逻辑结构:简单来说,就是人为规定逻辑,按照一定逻辑操作的存储结构,可分为线性结构和非线性结构。
常用简单分类:
线性结构 | 非线性结构 | |
---|---|---|
逻辑结构 | 顺序表、栈、队列 | 树、图 |
顺序存储结构 | 链式存储结构 | |
---|---|---|
物理结构 | 数组 | 链表 |
1、栈
1.1 什么是栈?
栈:栈是一种线性数据结构,规定其内部的元素满足先进后出,其中最早进入元素的位置称为栈底,最后进入元素的位置称为栈顶(top)。
数组为例:(常用)
栈底 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ top
3 | 4 | 2 | 8 | 9 | 5 |
---|
链表(尾插法)为例:
1.2、栈的基本操作(数组)
1.2.1、栈的创建与初始化
思想:利用top标识栈内最后一个元素的位置,本文章利用结构体进行封装栈数组和栈顶标识(top),初始化时,将top指向-1。
创建栈:
//主要代码
struct stack{
int array[10];
int top;
};
初始化:
//主要代码
void init() {
stack.top = -1;
}
1.2.2、入栈
思想:把新的元素放入栈中,只能栈顶的一侧进入,新元素作新栈顶(top++)
入栈:
//主要代码:
void push(int data) {
stack.top++;
stack.array[stack.top] = data;
}
1.2.3、弹栈
思想:从栈顶移出元素,只能栈顶的一侧弹出,出栈元素的前一个元素作为新栈顶(top–)
弹栈:
int pop() {
return stack.array[stack.top--];
}
1.2.4、判断栈空
思想:判断top是否为-1,当栈空时,返回true,否则返回false。
判空:
bool empty() {
if (stack.top == -1)
return true;
else
return false;
}
1.2.5 完整代码:
代码编译器:VS2019
//主要代码 建立StackOperation类进行封装, StackOperation.h
#pragma once
#include <iostream>
using namespace std;
class StackOperation{
public:
void init();
void push(int data);
int pop();
bool empty();
private:
struct stack{
int array[10];
int top;
};
struct stack stack;
};
//主要代码 StackOperation.cpp
#include "StackOperation.h"
void StackOperation::init() {
stack.top = -1;
}
void StackOperation::push(int data) {
stack.top++;
stack.array[stack.top] = data;
}
int StackOperation::pop() {
return stack.array[stack.top--];
}
bool StackOperation::empty() {
if (stack.top == -1)
return true;
else
return false;
}
//示例代码运行 main.cpp
#include <iostream>
#include "StackOperation.h"
using namespace std;
int main() {
StackOperation stackOperation;
stackOperation.init();
bool find = stackOperation.empty();
if (find) {
cout << "top = -1" << endl;
}
else {
cout << "top != -1" << endl;
}
stackOperation.push(1);
find = stackOperation.empty();
if (find) {
cout << "top = -1" << endl;
}
else {
cout << "top != -1" << endl;
}
stackOperation.push(2);
int data = stackOperation.pop();
cout << data << endl;
stackOperation.pop();
find = stackOperation.empty();
if (find) {
cout << "top = -1" << endl;
}
else {
cout << "top != -1" << endl;
}
return 0;
}
2、队列
2.1、什么是队列?
队列:队列是一种线性数据结构,不同于栈的先进后出,队列的元素规定只能先进先出,队列的出口称为对头(front),队列的入口称为队尾(rear)。
数组为例:
对头 (front) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 队尾(rear)
3 | 4 | 2 | 8 | 9 | 5 |
---|
链表为例:
2.2 循环队列
2.2.1为什么引入循环队列?
如果不是循环队列,当队列不断出队时,对头左边的空间将失去作用,导致队列的容量变小,采用循环队列维持队列容量稳定。
2.2.2、循环队列
循环队列:循环队列就是在逻辑上,将所开辟空间的首尾相连(实际上并没有相连,只是人为的规定)。
规定:
~~~~ a、循环队列空时,front = rear。
~~~~ b、循环队列入队时,front = (front +1) % 队列长度
~~~~ c、循环队列出队时,rear = (rear + 1) % 队列长度 (注意:队尾指针指向的位置永远空出一个位置,即队列的最大容量比实际长度小1。)
~~~~ d、循环队列满时,front = (rear + 1) %队列长度
(实际中所说的队列基本指循环队列)
2.3、队列的基本操作(数组)
2.3.1、队列的创建与初始化
思想:利用front标识对头,rear标识队尾。本文章利用结构体进行封装队列数组、对头(front)和队尾(rear)。初始化时,front = rear = 0.
创建队列:
//主要代码:
struct queue {
int array[10];
int front;
int rear;
};
初始化:
//主要代码:
void init() {
queue.front = queue.rear = 0;
}
2.3.2、入队
思想: 把新的元素放在队列中,只能在队尾的位置上放入,且新放入元素的下一个位置成为新的队尾(rear=(rear+1)%存储长度)。
入队:
//主要代码:
void enter(int data) {
if ((queue.rear + 1) % 10 == arrayLength) {
cout << "queue full!" << endl;
return;
}
queue.array[queue.rear] = data; //data为入队元素
queue.rear = (queue.rear + 1) % arrayLength;
}
2.3.3、出队
思想:把新的元素移出队列,只能在对头的位置移出,且出队元素的下一个元素为新的对头(front=(front+1)%存储长度)。
出队:
//主要代码:
int departure() {
if (empty()) { //判空
cout << "queue empty!" << endl;
}
int departureData = queue.array[queue.front];
queue.front = (queue.front + 1) % arrayLength;
return departureData;
}
2.3.4、判断对空
思想:判断front是否等于rear,若等于,则为空,返回true,否则,返回false。
判空:
//主要代码:
bool QueueOperation::empty() {
if (queue.front == queue.rear) {
return true;
}
else
return false;
}
2.3.5、完整代码:
代码编译器:VS2019
//主要代码 创建QueueOperation进行封装 QueueOperation.h
#pragma once
#include <iostream>
using namespace std;
class QueueOperation{
public:
void init();
void enter(int data);
int departure();
bool empty();
private:
struct queue {
int array[10];
int front;
int rear;
};
struct queue queue;
int arrayLength = 10; //10为队列数组的存储长度
};
//主要代码 QueueOperation.cpp
#include "QueueOperation.h"
void QueueOperation::init() {
queue.front = queue.rear = 0;
}
void QueueOperation::enter(int data) {
if ((queue.rear + 1) % arrayLength == queue.front) {
cout << "queue full!" << endl;
return;
}
queue.array[queue.rear] = data; //data为入队元素
queue.rear = (queue.rear + 1) % arrayLength;
}
int QueueOperation::departure() {
if (empty()) {
cout << "queue empty!" << endl;
}
int departureData = queue.array[queue.front];
queue.front = (queue.front + 1) % arrayLength;
return departureData;
}
bool QueueOperation::empty() {
if (queue.front == queue.rear) {
return true;
}
else
return false;
}
//示例代码运行 main.cpp
#include <iostream>
#include "QueueOperation.h"
using namespace std;
int main() {
QueueOperation queueOperation;
queueOperation.init();
bool find = queueOperation.empty();
if (find) {
cout << "queue empty!" << endl;
}
else {
cout << "queue no empty!" << endl;
}
queueOperation.enter(1);
queueOperation.enter(2);
queueOperation.enter(3);
cout << queueOperation.departure() << endl;
cout << queueOperation.departure() << endl;
find = queueOperation.empty();
if (find) {
cout << "queue empty!" << endl;
}
else {
cout << "queue no empty!" << endl;
}
queueOperation.departure();
find = queueOperation.empty();
if (find) {
cout << "queue empty!" << endl;
}
else {
cout << "queue no empty!" << endl;
}
return 0;
}
3、STL栈
3.0、为什么要会STL栈?(了解)
在实际开发中,栈的操作具有一定的通用性,且代码在本质上也相同,最多只是栈中存储的元素类型、大小不一。因此STL栈就孕育而生,其中STL栈具有更强的通用性。
3.1、堆栈操作
3.1.0 头文件
#include <stack>
3.1.1 创建形式
stack<存储元素类型> 创建对象名
3.1.2、栈操作基本函数:
push(T object): 将传入的对象压入栈中。
pop():弹出栈顶元素,并不会返回元素。
top():返回栈顶元素,不会弹栈。
empty(): 返回一个bool值,当栈空时返回true,否则返回false。
size():返回栈中元素的个数。
3.1.3、示例演示:
代码编译器:VS2019
//示例演示 main.cpp
#include <iostream>
#include <stack>
using namespace std;
int main() {
stack<int> s1;
s1.push(1);
s1.push(2);
s1.push(3);
cout << "stack size: " << s1.size() << endl;
if (s1.empty()) {
cout << "stack empty!" << endl;
}
else {
cout << "stack no empty!" << endl;
}
cout << s1.top() << endl;
s1.pop();
cout << s1.top() << endl;
s1.pop();
s1.pop();
if (s1.empty()) {
cout << "stack empty!" << endl;
}
else {
cout << "stack no empty!" << endl;
}
return 0;
}
4、STL队列
4.0、为什么要会STL队列?(了解)
在实际开发中,队列的操作具有一定的通用性,且代码在本质上也相同,最多只是队列中存储的元素类型、大小不一。因此STL队列就孕育而生,其中STL队列具有更强的通用性。
4.1、队列操作
4.1.0、头文件
#include <queue>
4.1.1、创建形式
queue<存储元素类型> 创建对象名
4.1.2、队列操作基本函数
push(): 在队尾压入新元素。
pop():删除对头元素,并且不返回值。
front():放回对头元素,并且不删除该元素。
back():返回队尾元素,并且不删除该元素。
empty(): 返回一个bool值,当队列空时返回true,否则返回false。
size(): 返回队列中元素的个数。
4.1.3、示例演示:
代码编译器:VS2019
示例演示 main.cpp
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<char> s1;
s1.push('a');
s1.push('b');
s1.push('c');
cout << "front: " << s1.front() << endl;
cout << "rear: " << s1.back() << endl;
cout << "size: " << s1.size() << endl;
if (s1.empty()) {
cout << "queue empty!" << endl;
}
else {
cout << "queue no empty!" << endl;
}
s1.pop();
s1.pop();
s1.pop();
cout << "size: " << s1.size() << endl;
if (s1.empty()) {
cout << "queue empty!" << endl;
}
else {
cout << "queue no empty!" << endl;
}
return 0;
}