栈
栈(stack)是限定仅在表尾进行插入或删除操作的线性表,因此,对于栈来说,表尾端有其特殊含义,称为栈顶,相应的,表头端称为栈底,不含元素的栈称为空栈
栈有一个重要的性质,就是先进后出,First ln Last Out(FILO)。
给几个元素,求其合法的出栈顺序个数,采用卡特兰数(1 / (n + 1)) * C[n, 2n]
构造代码(C)
#include <stdio.h>
#include <stdlib.h>
typedef struct Stack {
int * data;
int top;
int size;
};
Stack initStack(int n) {
Stack* s = (Stack*)malloc(sizeof(Stack));
s->data = (int*)malloc(sizeof(int));
s->top = -1; // 当有元素进来的时候变成0
s->size = n; // 为栈分配的初始大小
return s;
}
Stack* freeStack(Stack* s) {
if (!s) return s;
free(s->data);
free(s);
return NULL;
}
int push(Stack* s, int n) {
if (!s) {
return 0;
}
if (s->top == s->size - 1){
if (!expand(s)) {
return 0;
}
else {
return 1;
}
}
s->data[++s->top] = n;
return 1;
}
int isEmpty(Stack* s) {
return !s || s->top == -1;
}
int pop(Stack* s) {
return s->data[s->top--];
}
void showStack(Stack* s) {
while (isEmpty(s)) {
return;
}
int i = 0;
for (; i <= s->top; i++) {
printf("%d,", s->data[i]);
}
}
// 栈的扩容
int expand(Stack* s) {
if (!s) {
return 0;
}
int expSize = s->size;
int* tmp = NULL;
while (expSize) {
tmp = (int*)realloc(s->data, sizeof(int) * (s->size + expsize));
if (tmp) { // 申请成功
break;
}
expSize >>= 1;
}
if (!tmp) {
return 0;
}
s->data = tmp;
s->size += expSize;
return 1;
}
栈的基本应用
一个一个写构造太麻烦了,我直接用cpp的STL吧(C++STL里面的stack和queue是适配器,不是容器,他们是从deque或者vector的一部分构成的)
数制转换
#include <iostream>
#include <stack>
std::stack<int> sCon;
int main() {
int inputN;
std::cin >> inputN;
while (inputN) {
sCon.push(inputN % 8);
inputN /= 8;
}
while (!sCon.empty()) {
std::cout << sCon.top() << std::ends;
sCon.pop();
}
return 0;
}
括号匹配
class Solution {
public:
bool isValid(string s) {
stack<int> sk;
for (int i = 0; i < s.size(); i++) {
if (s[i] == '(') sk.push(')');
else if (s[i] == '{') sk.push('}');
else if (s[i] == '[') sk.push(']');
/*
sk.empty()这一个是因为当右括号把相对应的左括号都取出来后,
不是上面的三种左括号,而是进来了一个右括号,但是栈为空,说明没有匹配
该右括号的左括号了,因此这个右括号冗余了,因此返回错误。
*/
else if (sk.empty() || sk.top() != s[i]) return false;
else sk.pop();
}
return sk.empty();
}
};
表达式求值
#include <iostream>
#include <stack>
#include <string>
#include <ctype.h>
#include <math.h>
std::stack<int> sNum;
std::stack<char> sSymbol;
int main() {
std::string inputStr;
std::cin >> inputStr;
for (int i = 0; i < inputStr.size(); i++) {
if (isdigit(inputStr[i])) {
sNum.push(inputStr[i] - '0');
}
else {
if (inputStr[i] != ')') {
sSymbol.push(inputStr[i]);
}
else if (inputStr[i] == ')'){
char sTop = sSymbol.top();
sSymbol.pop();
while (sTop != '(') {
int f1 = sNum.top();
sNum.pop();
int f2 = sNum.top();
sNum.pop();
int f = 0;
if (sTop == '+') {
f = f1 + f2;
} else if (sTop == '-') {
f = f1 - f2;
} else if (sTop == '*') {
f = f1 * f2;
} else if (sTop == '/') {
f = f1 / f2;
} else if (sTop == '^') {
f = pow(f1, f2);
}
sNum.push(f);
sTop = sSymbol.top();
sSymbol.pop();
}
}
}
}
while (!sSymbol.empty()) {
char sTop = sSymbol.top();
sSymbol.pop();
int f1 = sNum.top();
sNum.pop();
int f2 = sNum.top();
sNum.pop();
int f = 0;
if (sTop == '+') {
f = f1 + f2;
} else if (sTop == '-') {
f = f1 - f2;
} else if (sTop == '*') {
f = f1 * f2;
} else if (sTop == '/') {
f = f1 / f2;
} else if (sTop == '^') {
f = pow(f1, f2);
}
sNum.push(f);
}
std::cout << sNum.top() << std::endl;
return 0;
}
行编辑内容
#include <iostream>
#include <stack>
#include <string>
#include <algorithm>
int main() {
std::string inputStr;
std::cin >> inputStr;
std::stack<char> sk;
for (int i = 0; i < inputStr.size(); i++) {
// 退格键
if (inputStr[i] == '#') {
sk.pop();
}
else if (inputStr[i] == '@') {
std::stack<char> skNew;
sk = skNew;
}
else {
sk.push(inputStr[i]);
}
}
std::string strResult;
while (!sk.empty()) {
strResult.push_back(sk.top());
sk.pop();
}
// 其实就是swap, ++first --last
reverse(strResult.begin(), strResult.end());
std::cout << strResult << std::endl;
return 0;
}
队列
队列(queue)是可以表尾进行插入或表头删除操作的线性表,因此,对于队列来说,表尾端有其特殊含义,称为队头,相应的,表头端称为队尾,不含元素的队列称为空队列
队列有一个重要的性质,就是先进先出,First ln First Out(FIFO)。
构造代码(C)
和栈差不多,不做概述了
双端队列
除了传统的队列之外,还有一种数据结构叫做双端队列(deque),双端队列是限定插入和删除操作在表的两端进行的线性表
deque应用较少
循环队列
一般情况下,队列的两个指针front和rear分别指向队头和队尾,front=rear=0,因此,每当插入新的队列元素时,尾指针加1;每当删除某个元素,头指针加1
在队列中,头指针指向队头元素,尾指针指向队尾元素的下一个位置
当队头指针不断向后的过程中,这就导致队头前面的位置会空出来?浪费了空间,因此引入循环队列!
当新增元素进入的时候按照传统应该是front=rear队列满了(rear指向最后一个元素的下一个位置),但是还不够, 因为队列空的时候也是front=rear,所以无法判断是空是满!有两个处理方法:
- 可以设置一个标志位判断队列是空是满,在循环队列中留一个元素的位置,一般在front的前面,当rear到达时说明是满的(当为空的时候rear=front,满的时候rear+1=front)
- 另外设置一个标志位来标志是空是满