堆栈,也属于线性表,其操作为线性表操作的子集。即,它是一种受限的线性表,它只允许在自己的表尾进行插入和删除操作。在栈中,表尾被称为栈顶(top
),而表头称为栈底(bottom
)。
假设栈 last in first out
)的线性表(LIFO)。
结构示意图如下:
由于堆栈的操作是线性表的子集,可以采用链表或者数组等线性结构来模拟堆栈。
这里只是用链表来表示栈。顺序表的实现,只需要维护两个指针,栈顶(top
)和栈底(bottom
),是线性表的操作子集,这里不再描述。
向堆栈内压入数据,新数据位于栈顶位置。
void push(Element e, Stack *stack)
{
StackNode *node = stack_node_new(e, stack->head);
stack->head = node;
stack->length++;
}
删除栈顶的元素并返回该元素。
Element pop(Stack *stack)
{
if (is_empty(stack))
{
return NULL;
}
StackNode *node = stack->head;
stack->head = node->next;
stack->length--;
Element e = node->e;
free_node(node);
return e;
}
此操作涉及节点回收
void free_node(StackNode *node)
{
if (node)
{
node->e = NULL;
node->next = NULL;
free(node);
}
}
由于堆栈后进先出的特性,因此有很多经典的应用场景。
leetcode 十进制与其它进制的转换。 其计算过程如下
N = (N div d)x d + N mod d
以 1024 由10进制
转8进制
为例。
value | div | mod |
---|---|---|
1024 | 128 | 0 |
128 | 16 | 0 |
16 | 2 | 0 |
2 | 0 | 2 |
因此获取8进制
表示为 0x2000
观察其计算过程,需要将其计算的最终结构反转。因此,使用堆栈来存储结构,然后在弹出即可。
void conversion(int N, int d)
{
Stack *stack = stack_new();
while (N)
{
int temp = N % d;
push(&temp, stack);
N = N / d;
}
while (!is_empty(stack))
{
Element e = pop(stack);
printf("%d", *(int *)e);
}
}
leetcode 检测括号的合法性,所谓合法即:括号在正确的位置上成对出现。例如:
(((())))
==> 合法的()(()))(
==> 不合法
bool isValid(string s) {
// map<char,char> brackets= {
// {'}','{'},
// {']','['},
// {')','['},
// };
stack<char> stack1 ;
for(int i=0;i<s.size();i++){
char temp = s[i];
if (temp=='{' || temp=='[' || temp=='('){
stack1.push(temp);
}else {
if (stack1.empty()) return false;
if (temp == '}' && stack1.top() != '{') return false;
if (temp == ')' && stack1.top() != '(') return false;
if (temp == ']' && stack1.top() != '[') return false;
stack1.pop();
}
}
return stack1.empty();
}
迷宫问题,即从入口到出口是一个经典的程序设计问题。当采取穷举法
去求解时,需要采用沿着某一个方向向前探索,若能走通,则继续前进,否则回退到上个节点。因此,需要有一个数据结构来存储这种行走的路径,此时栈是一个很好的选择。
详细请见 迷宫问题
表达式求值,是编译原理之中最基本的一个问题。它的实现是栈的典型应用之一。
假设四种运算操作x,/,+,-
首先明确其运算表达式的计算顺序
- 先乘除,后加减
因此两个运算符的运算优先级之间只有三种关系
A
高于B
A
等于B
A
低于B
这里采用两个栈来存储,一个存储运算符OPTR
,另外一个存储待运算的数值记作OPND
。
这是一个采用堆栈进行计算的好例子,将上一步的运算结果push
到堆栈中,当遇到一个运算符时,pop
出两个元素。
int evalRPN(vector<string> &tokens)
{
stack<int> elements;
for (string token : tokens)
{
if (token == "+" || token == "-" || token == "/" || token == "*")
{
int c;
int b = elements.top();
elements.pop();
int a = elements.top();
elements.pop();
if (token == "+")
c = a + b;
else if (token == "-")
c = a - b;
else if (token == "/")
c = a / b;
else
c = a * b;
elements.push(c);
}
else
{
elements.push(stoi(token));
}
}
return elements.top();
}