前言
在软件应用中,栈这种后进先出数据结构的应用非常普遍。因此栈也成为了广大程序猿必须要掌握并且能够熟练运用的一种数据结构。
一、栈的相关定义
允许插入和删除的一端称为栈顶,另一端为栈底。栈又称为后进先出的线性表。简称LIFO结构
按照存储结构可以分为两种
二、栈的顺序存储结构及实现
栈的结构定义
typedef int SElementType;
typedef struct
{
SElementType data[MAXSIZE];
int top; // 用于栈顶指针
}SqStack; //该结构体包含了顺序栈的两个重要属性:栈的空间大小、栈顶
三、栈的链式存储结构及实现
栈只是用栈顶来做插入和删除操作,在链栈中,栈顶放在链表的头部。对于链栈来讲,基本不存在满栈的情况。对于空栈,链表原定义是头指针指向空,那么链栈的空其实就是top = NULL。
链栈的结构代码如下:
typedef struct StackNode
{
int data;
struct StackNode *next;
}StackNode,*LinkStackPtr;
typedef struct LinkStack
{
LinkStackPtr top;
int count;
}LinkStack;// 链式栈的两个重要属性:栈顶、栈中的元素个数
栈的链式存储结构—进栈操作
status Push(LinkStack *S,int e)
{
LinkStackPtr MyStack = malloc(sizeof (StackNode));
MyStack->data = e;
MyStack->next = S->top;// 将当前的栈顶元素直接赋值给新节点的直接后继
S->top = MyStack ; // 将新的节点赋值给栈顶指针
S->count++;
return OK;
}
栈的链式存储结构—出栈操作
// 若栈不为空,则删除S栈顶元素,用e返回其值,并返回OK,否则返回ERROR
status Pop(LinkStack *S,int *e)
{
LinkStackPtr p;
if (StackEmpty(*S))
{
return ERROR;
}
*e = S->top->data;
p = S->top;// 将栈顶节点赋值给p.
S->top = S->top->next; // 使得栈顶指针下移一位,指向后一节点。
free(p);
S->count--;
return OK;
}
四、实战运用
1、回文链表
题目描述:

题目链接
解题思路:1、构建一个栈。2、向栈里填充链表中的元素。3、遍历链表和栈中的元素,如果全部相等则是回文链表,否则不是。
题解:
// C语言版
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
// 定义链式存储结构的栈
struct stack{
int data;
struct stack*next;
};
bool isPalindrome(struct ListNode* head){
struct ListNode* cur = head;
struct stack* stack = NULL; // 先构建一个栈尾元素,NULL
while (cur != NULL){ // 构建一个栈,并向栈中加入元素
struct stack* MytempStack = malloc(sizeof (struct stack));
MytempStack->data = cur->val;
MytempStack->next = stack;
stack = MytempStack; // 头插法构建起栈
cur = cur->next;
}
struct ListNode*temp = head;
while(stack != NULL && temp != NULL){
if (stack->data == temp->val){
stack = stack->next;
temp = temp->next;
}else{
return false;
}
}
return true;
}
2、有效的括号
题目描述:

题目链接
解题思路:采用的栈(顺序存储结构的栈)。遍历字符串S。当遇到一个左括号时,就将这个左括号放入栈顶。这样当我们在遍历过程中遇到一个右括号时,此时,我们就可以取出栈顶的左括号并判断它们是否是相同类型的括号,如果不是相同类型的括号,或者是栈中没有左括号,那么字符串s无效,返回False。为了快速判断括号的类型。可以使用哈希表存储每一种括号。哈希表的键为右括号,值为相同类型的左括号。
遍历结束后,如果我们的栈中没有了左括号,说明我们将字符串S中的所有左括号进行了闭合,返回TRUE,否则返回False。
有效字符串的长度一定为偶数。
题解:
// c语言版
char pairs(char a){
if (a == '}') return '{';
if (a == ']') return '[';
if (a == ')') return '(';
return 0;
}
bool isValid(char * s){
int n = strlen(s);
if (n % 2 == 1){
return false;
}
int stack[n+1] ; //顺序存储结构的 栈
int top = 0;// 栈顶指针
for (int i = 0; i < n; i++){
char ch = pairs(s[i]);
if (ch){
if (top == 0 || stack[top-1] != ch){
return false;
}
top--;
}else{
stack[top++] = s[i];
}
}
return top == 0;
}
3、最小栈
题目描述:
解决思路:创建栈A,有元素来入栈、有元素出出栈。创建最小栈B,B中存放的永远是栈A中的最小元素。
解答:
// C语言版
typedef struct MinStackNode{
int data;
struct MinStackNode *next;
} Stacknode,*StackPtr;
typedef struct Stack{
StackPtr top; // 栈顶。
int count; // 栈中元素个数。
} MinStack;
/** initialize your data structure here. */
MinStack* mystack_s; // 存放最小元素的栈
MinStack* minStackCreate() {
MinStack* mystack_p = malloc(sizeof(struct Stack));
StackPtr node = malloc (sizeof (Stacknode));
mystack_s = malloc (sizeof(struct Stack));
mystack_p->top = NULL; // 空栈
mystack_p->count = 0;
mystack_s->top = node;
node->data = INT_MAX;
mystack_s->count = 1;
return mystack_p;
}
void minStackPush(MinStack* obj, int val) {
StackPtr stacknode = malloc(sizeof (Stacknode));
stacknode->data = val;
stacknode->next = obj->top;
obj->top = stacknode;
obj->count++;
StackPtr stacknode_c = malloc(sizeof (Stacknode));
stacknode_c->data = (val < mystack_s->top->data) ? val : mystack_s->top->data;
stacknode_c->next = mystack_s->top;
mystack_s->top = stacknode_c;
mystack_s->count++;
}
void minStackPop(MinStack* obj) {
StackPtr stacknodetmp = malloc(sizeof (Stacknode));
if (obj->top != NULL){
stacknodetmp = obj->top;
obj->top = obj->top->next;
free(stacknodetmp);
obj->count--;
stacknodetmp = mystack_s->top;
mystack_s->top = mystack_s->top->next;
free(stacknodetmp);
mystack_s->count--;
}
}
int minStackTop(MinStack* obj) {
return obj->top->data;
}
int minStackGetMin(MinStack* obj) {
return mystack_s->top->data;
}
void minStackFree(MinStack* obj) {
StackPtr stacknodetmp = malloc(sizeof (Stacknode));
while (obj->top != NULL){
stacknodetmp = obj->top;
obj->top = obj->top->next;
free(stacknodetmp);
obj->count--;
stacknodetmp = mystack_s->top;
mystack_s->top = mystack_s->top->next;
free(stacknodetmp);
mystack_s->count--;
}
}
/**
* Your MinStack struct will be instantiated and called as such:
* MinStack* obj = minStackCreate();
* minStackPush(obj, val);
* minStackPop(obj);
* int param_3 = minStackTop(obj);
* int param_4 = minStackGetMin(obj);
* minStackFree(obj);
*/
// JAVA版
class MinStack {
Deque<Integer> xStack;
Deque<Integer> minStack;
/** initialize your data structure here. */
public MinStack() {
xStack = new LinkedList<Integer>();
minStack = new LinkedList<Integer>();
minStack.push(Integer.MAX_VALUE);
}
public void push(int val) {
xStack.push(val);
minStack.push(Math.min(minStack.peek(),val));
}
public void pop() {
xStack.pop();
minStack.pop();
}
public int top() {
return xStack.peek();
}
public int getMin() {
return minStack.peek();
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(val);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/