数据结构与算法-栈与队列
往期内容 1-链表 2-栈与队列 3-字符串 4-树 5-图 6-贪心算法 7-递归与分治 8-排序 9-查询 10-动态规划 11-STL库
基本概念
栈:先进后出,后进先出 队列:先进先出,后进后出
一、栈
栈的存储结构有两种:线性顺序结构和链式存储结构
1.1 顺序存储结构
实质是一个线性表
#define MAXSIZE 10
typedef int SElemType;
struct SqStack
{
SElemType data[MAXSIZE];
int top;
};
1.2 共享栈
线性存储结构必须事先确定数组存储空间的大小,如果不够用,需要扩展数组的容量,非常麻烦。 一个指针指向栈1另一个指向栈2,当top1和top2相差为1栈满
#define MAXSIZE 10
typedef int SElemType;
struct SqStack
{
SElemType data[MAXSIZE];
int top1;
int top2;
};
1.3 链式存储结构
typedef int SElemType;
struct StackNode
{
SElemType data;
StackNode *next;
};
typedef StackNode *LinkStackPtr;
typedef struct LinkStack
{
LinkStackPtr top;
int count;
}LinkStack;
二、栈基本操作
2.1入栈push
bool Push(SqStack *S,SElemType e)
{
if(S->top==(MAXSIZE-1))
{
return false;
}
(*S).top++;
S->data[S->top]=e;
return true;
}
bool Push(SqStack *S,SElemType e,int stackNumber)
{
if(S->top1+1==S->top2)
{
return false;
}
if(stackNumber==1)
{
S->top1++;
S->data[S->top1]=e;
}
if(stackNumber==2)
{
S->data[--S->top2]=e;
}
return true;
}
bool Push(LinkStack *S,SElemType e)
{
LinkStackPtr s=(LinkStackPtr)malloc(sizeof(StackNode));
s->data=e;
s->next=S->top;
S->top=s;
S->count++;
return true;
}
2.2 出栈pop
bool Pop(SqStack *S,SElemType *e)
{
if(S->top==-1)
{
return false;
}
*e=S->data[S->top];
S->top--;
return true;
}
bool Pop(SqStack *S,SElemType *e,int stackNumber)
{
if(stackNumber==1)
{
if(S->top1==-1)
{
return false;
}
*e=S->data[S->top1];
S->top1--;
}
if(stackNumber==2)
{
if(S->top2==MAXSIZE)
{
return false;
}
*e=S->data[S->top2++];
}
return true;
}
bool Pop(LinkStack *S,SElemType *e)
{
LinkStackPtr p;
if(S->count==-1)
return false;
*e=S->top->data;
p=S->top;
S->top=p->next;
free(p);
S->count--;
return true;
}
三、队列
队列用数组构建容易尝试越界,因此采用循环队列的方法。同时队列还可以采用链式存储的方法。
3.1 循环队列
#define MAXSIZE 13
typedef int QElemType;
struct SqQueue
{
QElemType data[MAXSIZE];
int front;
int rear;
};
3.2 链式存储结构
typedef int QElemType;
typedef struct QNode
{
QElemType data;
QNode *next;
}QNode,*QueuePtr;
struct LinkQueue
{
QueuePtr front,rear;
};
四、链式存储结构
4.1 入队
- 循环队列
使用两个指针front和rear分别纪录队首和队尾的位置, 入队的时候改变队尾指针 (Q->rear+1)%MAXSIZE;, 出队时候改变队首指针 (Q->front+1)%MAXSIZE; 队伍的长度为: (Q.rear-Q.front+MAXSIZE)%MAXSIZE; 当队首和队尾相等时,队列为空 (Q->rear+1)%MAXSIZE==Q->front 当队首和队尾相差1时,队列为满 Q->rear==Q->front
bool InitQueue(SqQueue *Q)
{
Q->front=0;
Q->rear=0;
return true;
}
int QueueLength(SqQueue Q)
{
return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
bool EnQueue(SqQueue *Q,QElemType e)
{
if((Q->rear+1)%MAXSIZE==Q->front)
return false;
Q->data[Q->rear]=e;
Q->rear=(Q->rear+1)%MAXSIZE;
return true;
}
bool EnQueue(LinkQueue *Q,QElemType e)
{
QueuePtr s=(QueuePtr)malloc(sizeof(QNode));
if(!s)
return false;
s->data=e;
s->next=NULL;
Q->rear->next=s;
Q->rear=s;
return true;
}
4.2 出队
bool DeQueue(SqQueue *Q,QElemType *e)
{
if(Q->rear==Q->front)
{
cout<<"空"<<endl;
return false;
}
*e=Q->data[Q->front];
Q->front=(Q->front+1)%MAXSIZE;
return true;
}
bool DeQueue(LinkQueue *Q,QElemType *e)
{
QueuePtr p;
if(Q->front==Q->rear)
return false;
p=Q->front->next;
*e=p->data;
Q->front->next=p->next;
if(p==Q->rear)
Q->rear=Q->front;
free(p);
return true;
}
五、Leetcode刷题
5.1 常用的stack queue priority_queue
stack S | 功能 |
---|
S.top() | 取出栈顶元素 | S.empty() | 栈是否为空 | S.push(x) | 将x压入栈中 | S.pop() | 弹出栈顶元素 | S.size() | 栈的存储元素个数 |
queue Q | 功能 |
---|
Q.front() | 取出队列头部元素 | Q.back() | 取出队列尾部元素 | Q.empty() | 队列是否为空 | Q.push(x) | 将x压入队列中 | Q.pop() | 弹出队列头部元素 | Q.size() | 队列的存储元素个数 |
priority_queue | 功能 |
---|
priority_queue<int> big_heap | 默认构造大顶堆 | priority_queue<int,vector<int>,greater<int>> small_heap | 构造小顶堆 | priority_queue<int,vector<int>,less<int>> big_heap | 构造大顶堆 | big_heap.top() | 取出堆顶元素 | big_heap.empty() | 堆是否为空 | big_heap.push(x) | 将x压入堆中 | big_heap.pop() | 弹出堆顶元素 | big_heap.size() | 堆的存储元素个数 |
备注:堆的操作与栈的操作完全一致
5.2 队列实现栈
Leetcode-225 用队列实现栈 思路:先将该数据放入临时队列中,在将原始队列中的数据也放入队列中,在将临时队列中的数据弹入到原始队列中
class MyStack {
public:
queue<int> res_queue;
MyStack() {
}
void push(int x) {
queue<int> temp_queue;
temp_queue.push(x);
while(!res_queue.empty())
{
temp_queue.push(res_queue.front());
res_queue.pop();
}
while(!temp_queue.empty())
{
res_queue.push(temp_queue.front());
temp_queue.pop();
}
}
int pop() {
int num=res_queue.front();
res_queue.pop();
return num;
}
int top() {
return res_queue.front();
}
bool empty() {
return res_queue.empty();
}
};
5.3 栈实现队列
Leetcode-232 用栈实现队列 思路:先将原始栈中数据弹入到临时栈中,再将该输入压入原始栈中,在将临时栈中的数据弹入到原始栈中。
class MyQueue {
public:
stack<int> res_stack;
MyQueue() {
}
void push(int x) {
stack<int> temp_stack;
while(!res_stack.empty())
{
temp_stack.push(res_stack.top());
res_stack.pop();
}
res_stack.push(x);
while(!temp_stack.empty())
{
res_stack.push(temp_stack.top());
temp_stack.pop();
}
}
int pop() {
int x=res_stack.top();
res_stack.pop();
return x;
}
int peek() {
return res_stack.top();
}
bool empty() {
return res_stack.empty();
}
};
5.4 最小栈
Leetcode-155 最小栈 思路:使用一个栈存放当前最小的元素
class MinStack {
public:
MinStack() {
}
stack<int> minStack;
stack<int> resStack;
void push(int val) {
resStack.push(val);
if(minStack.empty())
{
minStack.push(val);
}
else
{
if(val<minStack.top())
{
minStack.push(val);
}
else
{
minStack.push(minStack.top());
}
}
}
void pop() {
resStack.pop();
minStack.pop();
}
int top() {
return resStack.top();
}
int getMin() {
return minStack.top();
}
};
5.5 栈的压入、弹出序列
Leetcode-31 栈的压入、弹出序列 思路:用栈模拟新的过程,并于popped比较,相同则弹出,知道栈为空停止
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
if(pushed.size()==0) return true;
int i=0;
int j=0;
stack<int> resultStack;
while(i<pushed.size())
{
resultStack.push(pushed[i]);
while(!resultStack.empty() && resultStack.top()==popped[j])
{
resultStack.pop();
j++;
}
i++;
}
return resultStack.empty();
}
};
5.6 数组中的第K个最大元素
Leetcode-215 数组中的第K个最大元素 思路:维护一个size为k的小顶堆,弹出堆顶的元素
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int ,vector<int>,greater<int>> Q;
for(int i=0;i<k;i++)
{
Q.push(nums[i]);
}
for(int i=k;i<nums.size();i++)
{
if(nums[i]>Q.top())
{
Q.pop();
Q.push(nums[i]);
}
}
return Q.top();
}
};
5.7 数据流中的中位数
Leetcode-295 数据流中的中位数
class MedianFinder {
public:
priority_queue<int ,vector<int>,greater<int>> min_queue;
priority_queue<int ,vector<int>,less<int>> max_queue;
MedianFinder() {
}
void addNum(int num) {
if(max_queue.empty())
{
max_queue.push(num);
}
else if(max_queue.size()==min_queue.size())
{
if(num>max_queue.top())
{
min_queue.push(num);
}
else
{
max_queue.push(num);
}
}
else if(max_queue.size()>min_queue.size())
{
if(num>max_queue.top())
{
min_queue.push(num);
}
else
{
min_queue.push(max_queue.top());
max_queue.pop();
max_queue.push(num);
}
}
else
{
if(num<min_queue.top())
{
max_queue.push(num);
}
else
{
max_queue.push(min_queue.top());
min_queue.pop();
min_queue.push(num);
}
}
}
double findMedian() {
if(min_queue.size()==max_queue.size())
return (min_queue.top()+max_queue.top())/2.0;
else if(min_queue.size()>max_queue.size())
return min_queue.top();
else
return max_queue.top();
}
};
|