栈结构
-
栈(stack)是限定在表尾进行数据的插入、删除等操作的线性表(只允许操作一个端口的数据)
-
表尾称为栈顶,表头称为栈底 ,当没有元素的空表称为空栈,当元素的数量到达栈的容量时称为满栈 ,添加数据到栈顶中的动作称为入栈、压栈,把数据从栈顶中拿出的动作称为出栈、弹栈,正因为这个数据的添加、删除的规则,所以栈中元素满足先进后出,简称FILO表、LIFO
-
栈结构可以具备的功能
-
创建
-
销毁
-
是否满栈
-
是否空栈
-
入栈
-
出栈
-
查看栈顶元素
-
查看元素数量
注意:只有顺序栈才有需要判断栈是否满
-
1、栈结构的顺序实现
// 设计顺序栈结构 typedef struct ArrayStack { TYPE* ptr; // 存储栈元素的内存首地址 size_t cap; // 栈的容量 size_t top; // 栈顶的位置 }ArrayStack;
2、栈结构常考笔试题
-
对一个栈的入栈、出栈序列进行正确性判断
-
入栈顺序: 1 2 3 4 5
-
出栈顺序:1 2 3 4 5 正确 1 2 4 3 5 正确 2 1 5 3 4错误 5 4 3 2 1
-
四种顺序栈: top初值: 0 先入栈 top++ 空增栈 top初值:-1 top++ 再入栈 满增栈 top初值:cap-1 先入栈 top-- 空减栈 top初值:cap top-- 再入栈 满减栈
-
编程题:实现一个函数,判断序列B是否是序列A的出栈顺序
// 判断出栈顺序是否正确 bool is_pop(int* a,int* b,size_t len) { // 创建一个栈 ArrayStack* stack = create_array_stack(len); // 按照a顺序入栈 for(int i=0,j=0; i<len; i++) { push_array_stack(stack,a[i]); // 按照b的顺序出栈,一直出到无法出栈为止 int val = 0; // 栈非空,且栈顶值等于b中要出栈的值 则出栈 while(top_array_stack(stack,&val) && val == b[j]) { pop_array_stack(stack); j++; } } // 判断栈是否空,如果空,则是正确顺序 bool flag = false; if(empty_array_stack(stack)) flag = true; // 销毁栈 destroy_array_stack(stack); return flag; }
3、栈结构的链式实现
#define TYPE int typedef struct ListNode { TYPE data; struct ListNode* next; }ListNode; ListNode* create_list_node(TYPE data) { ListNode* node = malloc(sizeof(ListNode)); node->data = data; node->next = NULL; return node; } // 链式栈结构 typedef struct ListStack { ListNode* top; // 栈顶指针 指向栈顶节点 size_t size; // 节点数量 }ListStack; // 创建栈 ListStack* create_list_stack(void) { ListStack* stack = malloc(sizeof(ListStack)); // 因为栈不允许随意操作插入、删除操作,因此不需要头节点 stack->top = NULL; stack->size = 0; return stack; } // 栈空 bool empty_list_stack(ListStack* stack) {} // 入栈 void push_list_stack(ListStack* stack,TYPE data) {} // 出栈 bool pop_list_stack(ListStack* stack) {} // 栈顶 TYPE top_list_stack(ListStack* stack) {} // 节点数 size_t size_list_stack(ListStack* stack) {} // 销毁 void destroy_list_stack(ListStack* stack) {}
4、栈的应用
-
内存管理,例如栈内存,之所以叫栈内存因为它遵循栈的先进后出原则,函数调用、函数参数的传参、定义,先把数据入栈,等结束时,逆序出栈,函数的调用、结束跳转也是遵循栈结构原则
-
特殊的算法:算术表达式的转换(中缀表达式转后缀表达) 、进制转换、迷宫算法