基本概念
栈是仅在表尾进行插入或者删除操作的线性表
表尾称为栈顶
表头称为栈底
栈是按后进先出(last in first out)LIFO 的线性表
入栈:插入(栈顶)元素
出栈:删除(栈顶)元素
同顺序表类似,栈也有两种存储表示方式
顺序栈:采用顺序存储结构可以模拟栈存储数据的特点,从而实现栈存储结构;
链 栈:采用链式存储结构实现栈结构;
基本操作
顺序栈
栈的顺序结构是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素。同时附设指针top 只是栈顶元素在顺序栈中的位置。
一般是top =0 表示空栈
在初始化设空栈时不应限定栈的最大容量。
可以先为栈分配一个基本容量,然后在应用过程中,当栈的空间不够使用时再逐段扩大。
栈的顺序存储表示
#define STACK_INIT_SIZE 100 //存储空间初始分配量
#define STACKINCREMENT 10 //存储空间分配增量
typedef int SElemType; //元素类型
typedef struct{
SElemType *top; //栈顶指针
SElemType *base; //在栈构造之前和销毁之后,base 的值为NULL
int stacksize; //当前已经分配的存储空间,以元素为单位
}SqStack;
初始化栈
三个步骤
1)分配存储空间
2)使栈空
3)分配基本容量
SqStack *InitStack(){
SqStack *S;
S->base = (SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));//分配存储空间
if(!S->base){
printf("存储空间分配失败");
exit(OVERFLOW);
}
S->top = S->base;//使栈空
S->stacksize = STACK_INIT_SIZE; //为存储空间分配初始量
return S;
}
我觉得最重要的是要知道栈顶元素
top = *(S->top - 1);
知道这个之后,入栈出栈这些基本操作就都明了了。
入栈
1)判断栈存储空间是否足够(如何判断???)不够该如何???
2)如何入栈?
SqStack *Push(SqStack *S,SElemType e){
printf("待入栈的元素:%d\n",e);
if(S->top - S->base >= S->stacksize){//判断存储空间是否足够
S->base = (SElemType *)realloc(S->base,
(S->stacksize + STACKINCREMENT)*sizeof(SElemType));
if(!S->base){//存储空间分配失败
printf("存储空间分配失败");
exit(OVERFLOW);
}
S->top = S->base + S->stacksize;
S->stacksize += STACKINCREMENT;
}
*S->top++ = e; //添加栈顶元素
//因为添加了元素,所以栈顶指针+1;
printf("入栈成功");
return S;
}
出栈
SElemType Pop(SqStack *S){
SElemType e = *(S->top-1);
S->top--;
printf("弹栈元素:%d\n",e);
return e;
}
获取栈顶元素
SElemType GetTop(SqStack *S){
if(S->top == S->base){
printf("栈为空");
return ERROR;
}
SElemType e = *(S->top-1);
return e;
}
输出栈中元素
void display(SqStack *S){
SElemType *t = (S->top-1);
printf("当前栈中元素为:");
while(t != (S->base-1)){
printf("%d\t",*(t));
t--;
}
}
链栈
链栈就是先进先出结构的链表
我用的教材是严蔚敏老师的数据结构书。书中对链表只用一句话就带过了。我还是记一下笔记,方便以后使用。
下面的代码是我自己写的,如有不对之处,希望指正。
将链表头部作为栈顶。
这样就能直接找到栈顶的地址,对入栈和出栈很方便。
入栈时,从链表头部插入。
出栈时,删除链表头部的首元节点
链栈的存储结构
typedef int SElemType;
typedef struct LineStack{
SElemType data; //数据域
struct LineStack * next;//指针域
}SNode,*LineStack;
链栈的初始化
和链表类似,先为链栈分配存储空间,再使链栈为空。
LineStack InitStack(){
LineStack S = (LineStack)malloc(sizeof(SNode));
S->next = NULL;//链表为空
return S;
}
入栈
出栈
因为原理和之前的线性表类似,这里直接贴上代码:
#include <stdio.h>
#include <stdlib.h>
#define STACK_INIT_SIZE 100 //存储空间初始分配量
#define STACKINCREMENT 10 //存储空间分配增量
#define OVERFLOW -2
#define ERROR 0
#define OK 1
typedef int SElemType; //元素类型
typedef struct SNode{
SElemType data; //数据域
struct SNode *next;//指针域
}SNode,*LineStack;
LineStack InitStack(){
LineStack S = (LineStack)malloc(sizeof(SNode));//分配存储空间
S->next = NULL;//链栈为空
printf("初始化链栈成功\n");
return S;
}
LineStack Push(LineStack S, SElemType e){
LineStack p = (LineStack)malloc(sizeof(SNode));
if(S->next = NULL){//如果链栈为空
p->next = NULL;
S->next = p;
p->data = e;
}
S->next = p;
p->data = e;
printf("%d入栈成功\n",e);
return S;
}
LineStack Pop(LineStack S){
LineStack p = S;
LineStack q;
if(S->next == NULL){
printf("链栈为空,退出\n");
exit(OVERFLOW);
}
q = p->next;
S = q->next;
printf("%d出栈\n",q->data);
free(p);
return S;
}
int main(){
/*初始化链栈*/
LineStack S = InitStack();
/*入栈*/
S = Push(S,1);
S = Push(S,2);
S = Push(S,3);
/*出栈*/
S = Pop(S);
S = Pop(S);
S = Pop(S);
return 0;
}
栈的应用
数制转换
数值转换的原理:
N = (N div d) * d + N mod d
刚开始看到这个公式不太懂什么意思,其实很简单
整理一下思路,
1)首先构造一个空栈
2)要用到循环 for / while/ do…while
3)要用哪一个循环?
循环结束条件:N div d == 0 ,所以可以使用while 或 do…while
当N 较小时,比如1,不用进入循环,可以排除 do…while
所以while 比较合适
4)循环结束条件是 N div d = = 0,所以可以不用设置中间变量,直接
while(N){
...
N = N / d;
...
}
我写的程序,太丑了,我回过头看真的太low了:
void conversion(int N, int d){
SqStack * S = InitStack();
int temp = N;
int res;
while(N / d != 0){
Push(S,N % d);
temp = N /d; // N div d
res = temp % d;//N mod d
Push(S,res); //入栈
}
display(S);
}
5)N mod d 的结果入栈,元素全部入栈后,再出栈。
6)注意事项:第一步直接是 N mod d 的结果进栈
完整程序:
#include <stdio.h>
#include <stdlib.h>
#define STACK_INIT_SIZE 100 //存储空间初始分配量
#define STACKINCREMENT 10 //存储空间分配增量
#define OVERFLOW -2
#define ERROR 0
#define OK 1
typedef int SElemType; //元素类型
typedef struct{
SElemType *top; //栈顶指针
SElemType *base; //在栈构造之前和销毁之后,base 的值为NULL
int stacksize; //当前已经分配的存储空间,以元素为单位
}SqStack;
SqStack *InitStack(){
SqStack *S;
S = (SqStack *)malloc(STACK_INIT_SIZE*sizeof(SqStack));
S->base = (SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));//分配存储空间
if(!S->base){
printf("存储空间分配失败\n");
exit(OVERFLOW);
}
S->top = S->base;//使栈空
S->stacksize = STACK_INIT_SIZE; //为存储空间分配初始量
return S;
}
SqStack *Push(SqStack *S,SElemType e){
if(S->top - S->base >= S->stacksize){//判断存储空间是否足够
S->base = (SElemType *)realloc(S->base,
(S->stacksize + STACKINCREMENT)*sizeof(SElemType));
if(!S->base){//存储空间分配失败
printf("存储空间分配失败\n");
exit(OVERFLOW);
}
S->top = S->base + S->stacksize;
S->stacksize += STACKINCREMENT;
}
*S->top++ = e; //添加栈顶元素
//因为添加了元素,所以栈顶指针+1;
return S;
}
SElemType GetTop(SqStack *S){
if(S->top == S->base){
printf("栈为空\n");
return ERROR;
}
SElemType e = *(S->top-1);
return e;
}
void display(SqStack *S){
SElemType *t = (S->top-1);
while(t != (S->base-1)){
printf("%d",*(t));
t--;
}
printf("\n");
}
//转换成d进制
void conversion(int N, int d){
printf("%d的%d进制:",N,d);
SqStack *S = InitStack(); //构造空栈
while(N){
Push(S, N%d);
N = N/8;
}
display(S);
}
int main(){
conversion(1348,8);
return 0;
}
我感觉这就是美的代码,简洁明了。我太爱了
括号匹配
括号匹配我觉得有点类似消消乐,只是并不是相同的括号抵消,而是( 和 ),[ 和 ]相抵消,只要输入的括号匹配,最后的栈就为空。
检验括号是否匹配的方法可用期待的迫切程度这个概念来描述。
贴上刚开始自己写的一段代码,真的太low了,还不对
void matching(){
SqStack * S = InitStack();
SElemType kuohao;
while(kuohao!=’(’ || kuohao!=’[’ || kuohao!=’)’ || kuohao!=’]’){
printf(“请输入括号,输入括号以外的字符则退出:”);
scanf("%c",&kuohao);
if(kuohao==’(’ || kuohao==’[’){
Push(S,kuohao);
printf("%c入栈成功\n",kuohao);
}
if(kuohao = = ‘)’ && GetTop(S)= =’(’){
Pop(S);
}
if(kuohao= =’[’ && GetTop(S)= =’]’){
Pop(S);
}
}
if(S->base != S->top){
printf(“括号匹配失败”);
}
if(S->base == S->top){
printf(“匹配成功”);
}
}
程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STACK_INIT_SIZE 100 //存储空间初始分配量
#define STACKINCREMENT 10 //存储空间分配增量
#define OVERFLOW -2
#define ERROR 0
#define OK 1
typedef char SElemType; //元素类型
typedef struct{
SElemType *top; //栈顶指针
SElemType *base; //在栈构造之前和销毁之后,base 的值为NULL
int stacksize; //当前已经分配的存储空间,以元素为单位
}SqStack;
SqStack *InitStack(){
SqStack *S;
S = (SqStack *)malloc(STACK_INIT_SIZE*sizeof(SqStack));
S->base = (SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));//分配存储空间
if(!S->base){
printf("存储空间分配失败\n");
exit(OVERFLOW);
}
S->top = S->base;//使栈空
S->stacksize = STACK_INIT_SIZE; //为存储空间分配初始量
return S;
}
SqStack *Push(SqStack *S,SElemType e){
if(S->top - S->base >= S->stacksize){//判断存储空间是否足够
S->base = (SElemType *)realloc(S->base,
(S->stacksize + STACKINCREMENT)*sizeof(SElemType));
if(!S->base){//存储空间分配失败
printf("存储空间分配失败\n");
exit(OVERFLOW);
}
S->top = S->base + S->stacksize;
S->stacksize += STACKINCREMENT;
}
*S->top++ = e; //添加栈顶元素
//因为添加了元素,所以栈顶指针+1;
return S;
}
SElemType Pop(SqStack *S){
SElemType e = *(S->top-1);
S->top--;
return e;
}
SElemType GetTop(SqStack *S){
if(S->top == S->base){
return ERROR;
}
SElemType e = *(S->top-1);
return e;
}
void display(SqStack *S){
SElemType *t = (S->top-1);
while(t != (S->base-1)){
printf("%c",*(t));
t--;
}
printf("\n");
}
bool StackEmpty(SqStack *S){
bool status = false;
if(S->base == S->top){
status = true;
}
return status;
}
void matching(char *mstr){
SqStack *S = InitStack();
int state = 1;
unsigned int i=0;
printf("字符串长度:%d\n",strlen(mstr));
while(i < strlen(mstr) && state){
switch (mstr[i]){
case '(':{
Push(S,mstr[i]);
i++;
break;}
case ')':{
if(GetTop(S)=='('){
Pop(S);
i++;
}else{
state = 0;
}
break;}
}
}
printf("栈中剩余元素:");
display(S);
if(StackEmpty(S)){
printf("匹配成功");
}else{
printf("匹配失败");
}
}
int main(){
matching("()()(");
return 0;
}