一、栈
1.栈的概念及结构
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
2.栈的实现
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。
1.栈的创建
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
2.初始化
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
3.销毁
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
4入栈
void StackPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);
if (tmp == NULL) {
perror("realloc fail\n");
exit(-1);
}
ps->a = tmp;
ps->capacity = newCapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
5.出栈
void StackPop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
ps->top--;
}
6.返回栈顶元素
STDataType StackTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
7.判断是否为空
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
8.返回栈的大小
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
二、队列
1.队列的概念及结构
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为对头。
2.队列的实现
队列也可以数组和链表的结构实现,使用链表的结构更优一些,因为如果有数组的结构,出队列在数组的头上出数组,效率会比较低。
1.队列的创建
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
2.初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
}
3.销毁
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur) {
QNode* next = cur->next;
free(cur);
cur = next;
}
}
4.入队
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL) {
perror("malloc fail\n");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
if (pq->tail == NULL)
pq->head = pq->tail = newnode;
else {
pq->tail->next = newnode;
pq->tail = newnode;
}
}
5.出队
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
if (pq->head->next == NULL) {
free(pq->head);
pq->head = pq->tail = NULL;
}
else {
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
}
6.返回队头数据
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
7.返回队尾数据
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
8.判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
9.返回队列的长度
int QueueSize(Queue* pq)
{
int size = 0;
QNode* cur = pq->head;
while (cur) {
++size;
cur = cur->next;
}
return size;
}
三、栈和队列的面试题
1.有效的括号OJ链接
class Solution {
public:
bool isValid(string s) {
//使用C++中的STL(无需自己造轮子)
stack<char>ST;
int i=0;
while(s[i])
{
if(s[i]=='('||s[i]=='{'||s[i]=='[')//将‘(’、‘[’、‘{’放入栈中
{
ST.push(s[i]);
i++;
}
else
{
if(ST.empty())
return false;
if((ST.top()=='{'&&s[i]=='}')||(ST.top()=='('&&s[i]==')')||(ST.top()=='['&&s[i]==']'))//取出栈顶的元素与所在s的位置进行匹配
{
ST.pop();
i++;
}
else
return false;
}
}
if(!ST.empty())
return false;
else
return true;
}
};
2.用队列实现栈OJ链接
class MyStack {
//定义两个MyStack类的成员为两个队列分别为q1,q2
private:
queue<int> q1;
queue<int> q2;
public:
MyStack()
{
}
//将q1中插入元素x
void push(int x) {
q1.push(x);
}
//如果q1不为空的话将q1中的元素插入q2中
int pop() {
if(!q1.empty())
{
while(q1.size()>1)
{
q2.push(q1.front());
q1.pop();
}
int ret=q1.front();
q1.pop();
return ret;
}
//反之
else
{
while(q2.size()>1) //注意判断一下q1,q2是否为空
{
q1.push(q2.front());
q2.pop();
}
int ret=q2.front();
q2.pop();
return ret;
}
}
int top() {
if(!q1.empty())
return q1.back();
else
return q2.back();
}
bool empty() {
return q1.empty()&&q2.empty();
}
};
/**
* Your MyStack object will be instantiated and called as such:
* MyStack* obj = new MyStack();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->top();
* bool param_4 = obj->empty();
*/
3.用栈实现队列OJ链接
class MyQueue {
//定义两个栈一个栈用来出数据,一个栈用来插入数据
private:
stack<int> PushST;
stack<int> PopST;
public:
MyQueue() {
}
//将数据放入插入数据的栈中
void push(int x) {
PushST.push(x);
}
//如果此时出数据的栈空为空时则将数据导入出数据的栈中
int pop() {
if(PopST.empty())
{
while(!PushST.empty())
{
PopST.push(PushST.top());
PushST.pop();
}
}
int ret=PopST.top();
PopST.pop();
return ret;
}
int peek() {
if(PopST.empty())
{ while(!PushST.empty())
{
PopST.push(PushST.top());
PushST.pop();
}
}
return PopST.top();
}
bool empty() {
return PushST.empty()&&PopST.empty();
}
};
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue* obj = new MyQueue();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->peek();
* bool param_4 = obj->empty();
*/
4.设计循环队列OJ链接
class MyCircularQueue {
//利用数组进行求解比较简单
//定义一个vector容器
//即一个队列的长度、头、尾
private:
vector<int>v;
int n;
int head;
int tail;
public:
MyCircularQueue(int k)
{
//指定该容器的长度为为队列长度+1
//并且进行初始化操作
v.resize(k+1);
n=k;
head=tail=0;
}
//入队列
bool enQueue(int value) {
//如果此时队列满了无法进行入队列的操作
if(isFull())
{
return false;
}
//若队列没满则进行数据的填入
v[tail]=value;
tail=(tail+1)%(n+1);
return true;
}
//出队列
bool deQueue() {
//如果此时的队列为空的话无法进行出队列的操作
if(isEmpty())
{
return false;
}
head=(head+1)%(n+1);
return true;
}
//取队头值
int Front() {
if(isEmpty())
return -1;
return v[head];
}
//取队尾的值
int Rear() {
//如果此时为空的话返回-1
if(isEmpty())
return -1;
return v[(tail+n)%(n+1)];
}
bool isEmpty() {
return tail==head;
}
bool isFull() {
if((tail+1)%(n+1)==head)
return true;
else
return false;
}
};
/**
* Your MyCircularQueue object will be instantiated and called as such:
* MyCircularQueue* obj = new MyCircularQueue(k);
* bool param_1 = obj->enQueue(value);
* bool param_2 = obj->deQueue();
* int param_3 = obj->Front();
* int param_4 = obj->Rear();
* bool param_5 = obj->isEmpty();
* bool param_6 = obj->isFull();
*/