栈是一种重要的数据结构,它广泛应用于各种软件系统中,这种数据结构与线性表有密切的联系。从逻辑上看,栈属于线性结构,是一种特殊的线性表。其特殊性在于栈的基本操作是线性表操作的子集,它是限定公在表尾进行插入或删除操作的线性表,是操作受限的线性表。

学习要点:

1.了解栈的概念。

2.掌握栈的数据结构定义方法和基本运算的实现方法。

3.能够使用栈这种数据结构来解决具体的问题

栈的定义

栈(Stack)是一种特殊的线性表,是限定公在表尾进行插入或删除操作的线性表。栈的表尾称为栈顶(top),处于栈顶位置的数据元素称为栈顶元素。栈的表头称为栈底(bottom),处于栈底位置的数据元素称为栈底元素。不含任何元素的表称为空栈。

下面来看栈的使用代码实现

1. 栈的顺序存储的实现

【问题描述】

实现栈的顺序存储结构的基本运算。

【算法描述】

要求通过具体的算法来实现栈的顺序存储。首先建立栈的顺序结构,对栈的各个运算的算法做详细的描述,然后在主函数中通过函数调用实现顺序栈的置空、数据元素进栈、出栈等。

#include<stdio.h>
#include<malloc.h>
#include<conio.h>
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OK 1
#define EQUAL 1
#define OVERFLOW -1
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10

typedef int ElementType ;
struct STU
{
    char name[20];
    char stuno[10];
    int age;
    int score;
};
typedef struct STU SElemType;
struct STACK
{
    SElemType *base;
    SElemType *top;
    int stacksize;
};
typedef struct STACK SqStack;
typedef struct STACK *pSqstack;
ElementType InitStack(SqStack **S);
void DestroyStack(SqStack *S);
void ClearStack(SqStack *S);
ElementType StackEmpty(SqStack S);
int StackLength(SqStack S);
ElementType GetTop(SqStack S,SElemType *e);
ElementType Push(SqStack *S,SElemType e);
ElementType Pop(SqStack *S,SElemType *e);
ElementType StackTraverse(SqStack S,ElementType (*visit)());


ElementType InitStack(SqStack **S) /* 栈的初始化 */
{
    (*S)=(SqStack *) malloc(sizeof(SqStack));
    (*S)->base=(SElemType *)malloc(STACK_INIT_SIZE *sizeof(SElemType));
    if(!(*S)->base)
        exit(OVERFLOW);
    (*S)->top=(*S)->base;
    (*S)->stacksize=STACK_INIT_SIZE;
    return OK;
}
void DestroyStack(SqStack *S) /* 栈的释放 */
{
    free(S->base);
    free(S);
}

void ClearStack(SqStack *S) /* 栈的置空 */
{
    S->top=S->base;
}

ElementType StackEmpty(SqStack S)
{
    if(S.top==S.base)
        return TRUE;
    else
        return FALSE;
}

int StackLength(SqStack S)
{
    int i;
    SElemType *p;
    i=0;
    p=S.top;
    while(p!=S.base)
    {
        p++;
        i++;
    }

    return i;
}

ElementType GetTop(SqStack S,SElemType *e)
{
    if(S.top==S.base) return ERROR;
    *e=*(S.top-1);
    return OK;
}

ElementType Push(SqStack *S,SElemType e)
{
    *(S->top++)=e;
    return OK;
}

ElementType Pop(SqStack *S,SElemType *e)
{
    if(S->top==S->base) return ERROR;
    *e=*--S->top;
    return OK;
}

ElementType StackPrintElem(SElemType * e)
{
    printf("%s %s %d %d\n",e->name,e->stuno,e->age,e->score);
}

ElementType StackTraverse(SqStack S, ElementType (*visit)())
{
    while(S.top!=S.base)
        visit(--S.top);
}

int main(void) /* 顺序栈的主函数 */
{
    SElemType e;
    SqStack *Sa;

    printf("\n\n------------SqStack Demo is running...-----------\n\n");
    printf("First is Push function.\n");
    InitStack(&Sa);
    strcpy(e.name,"stu1");
    strcpy(e.stuno,"100001");
    e.age=80;
    e.score=1000;
    printf("Now Stack is Empty.\n");
    StackTraverse(*Sa,StackPrintElem);
    Push(Sa,e);
    printf("Now Stack has one element.\n");
    StackTraverse(*Sa,StackPrintElem);
    strcpy(e.name,"stu3");
    strcpy(e.stuno,"100002");
    e.age=80;
    e.score=1000;
    Push(Sa,e);
    printf("Now Stack has another element.\n");
    StackTraverse(*Sa,StackPrintElem);
    printf("Now Pop Stack,the top elem put into variable e.\n");
    Pop(Sa,&e);
    printf("%s\n%s\n%d\n%d\n",e.name,e.stuno,e.age,e.score);
    printf("Let's see the left of Stack's elem:\n");
    StackTraverse(*Sa,StackPrintElem);

    printf("\n\n\nWelcom to visit http://zmofun.topcool.net\n\n");

    return 0;
}

运行结果

 

2. 栈的链式存储的实现

【问题描述】

链栈是栈的另一种存储方式,要求通过具体的算法实现链栈的倒置、出栈等运算。

【算法描述】

在设计链栈的基本运算之前,首先定义链栈的存储类型、结点类型,然后分别设计各种运算的具体函数。最后在主函数中实现链栈的各种运算时,分别调用相应的函数即可。

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

#define NULL 0

typedef char ElementType;

typedef struct stacknode
{
     ElementType data;
     struct stacknode *next;
}StackNode;

typedef struct
{
     StackNode *top;
}LinkStack;

void InitStack(LinkStack *s)
{
     s->top=NULL;
}

int StackEmpty(LinkStack *s)
{
    return s->top==NULL;
}
/* 链栈的节点是动态分配的,无须判断 Full(上溢) */
void Push(LinkStack *s, ElementType x)
{
    StackNode *p;
    p=malloc(sizeof(StackNode));
    p->next=s->top;             /* 由于是在栈顶 PUSH,所以要指向栈顶 */
    p->data=x;
    s->top=p;                   /* 插入 */
}

ElementType Pop(LinkStack *s)
{
    ElementType x;
    StackNode *p=s->top;        /* 指向栈顶 */
    if (StackEmpty(s))
    {
         printf("栈为空,不能出栈...\n");
         exit(-1);
    }
    x=p->data;
    s->top=p->next;             /* 当前的栈顶指向原栈的 next */
    free(p);
    return x;
}

ElementType StackTop(LinkStack *s)
{
    if (StackEmpty(s))
    {
         printf("栈为空,不能出栈...\n");
         exit(-1);
    }
    return s->top->data;
}

void Disp(LinkStack *s)
{
      StackNode *p=s->top;
      printf("=======================================\n");
      while (p!=NULL)
      {
         printf("\n%c",p->data);
         p=p->next;
      }
      printf("=======================================\n");
}

void RevStack(LinkStack *s)
{
     int i, n=0;
     char dat[50];
     while(!StackEmpty(s))
     {
         dat[n]=Pop(s); /* 保存退栈后的数据到数组 */
         n++;
     }
     for (i=0;i<n;i++)
        Push(s,dat[i]);
}

int main(void)
{
     LinkStack * s=(LinkStack *)malloc(sizeof(LinkStack));
     char ch,ch2,ch3;
     printf("================= 链栈操作 DEMO =================\nn");
     InitStack(s);
     printf("依次压栈 a,b,c,d,e 后,栈中的数据为:\n");
     Push(s,'a');
     Push(s,'b');
     Push(s,'c');
     Push(s,'d');
     Push(s,'e');
     Disp(s);
     printf("\n 将此栈倒置,栈中的数据序列为:\n");
     RevStack(s);
     Disp(s);
     ch=Pop(s);
     printf("\n 出栈操作开始,第一次出栈得到的数据:%c",ch);
     ch2=Pop(s);
     printf("\n 第二次出栈得到的数据:%c",ch2);
     ch3=StackTop(s);
     printf("\n 此时的栈顶元素为:%c",ch3);

     return 0;
}


运行结果:

 

3. 计算表达式的值

【问题描述】

计算用运算符后缀法表示的表达式的值。后缀表达式也称逆波兰表达式,比中缀表达式计算起来更方便简单些,中缀表达式计算存在着括号的匹配问题,所以在计算表达式值时一般都是先转换成后缀表达式,再用后缀法计算表达式的值。如表达式(a+b*c)/d-e 用后缀法表示应为 abc*+d/e-1。只考虑四则算术运算,且假设输入的操作数均为 1 位十进制数(0~9),并且输入的后缀形式表达式不含语法错误。

#include<stdio.h>
#include<stdlib.h>

#define add 43
/* 运算符加号'+'的 ASCII 码 */
#define subs 45
/* 运算符减号'-'的 ASCII 码 */
#define mult 42
/* 运算符乘号'*'的 ASCII 码 */
#define div 47
/* 运算符除号'/'的 ASCII 码 */
#define MAXSIZE 100
typedef struct
{
    int stkdata[MAXSIZE];
    /* 用数组来表示栈空间,定义长度为 MAXSIZE 的堆栈 */
    int top ;
    /* 栈顶 */
}STKzone;
typedef STKzone *STK;

typedef enum{ok,error} status;
STKzone expSTKzone;
STK expSTK;
STK initSTK(STKzone *stack_zone)
{
    /* 执行栈初始化,建栈指针 */
    STK p;
    p=stack_zone;
    p->top=0;

    return p;
}

status push(int *term,STK pstk)
{
    /* 将一结构型数据送入栈中 */
    if(pstk->top==MAXSIZE)
        return error; /* 栈满,进栈失败 */
    pstk->stkdata[pstk->top] =*term;
    (pstk->top)++;/* 栈顶指针移动 */
    return ok;
}/* push */
bool emptySTK(STK pstk)
{

    return(pstk->top==0);
}
status pop(int *pdata, STK pstk)
{
    /* 从栈中取出一结构型数据 */
    if(emptySTK(pstk))
        return error;
    (pstk->top)--; /* 退栈 */
    *pdata =pstk->stkdata[pstk->top];
    return ok;
}
void synerror()
{
    printf("\n 表达式语法错!");
    exit(-1);
}
int eval(char tag,int a1,int a2)
{
    switch(tag)
    {
    case add:return(a1+a2);
    case subs:return(a1-a2);
    case mult:return(a1*a2);
    case div:return(a1/a2);
    }
}

int main()
{
    char c;
    int opd1,opd2,temp,c1;
    expSTK=initSTK(&expSTKzone);
    printf("\n 后置表达式: ");
    while((c=getchar())!='\n')
    {
        if(c== ' ')
            continue;
        if((c>47)&&(c<58))
            /* 判断是否是 0~9 的字符 */
        {
            putchar(c);
            c1=c-48;
            /* 把输入的字符型数字转换成数字 */
            if(push(&c1,expSTK)==error) /* 运算分量进栈 */
            {
                printf("\n 表达式太长\n");
                exit(-1);
            }
        }
        else if((c==add)||(c==subs)||(c==mult)||(c==div))
        {
            putchar(c);
            if(pop(&opd1,expSTK)==error) /* 将运算量 1 出栈 */
                synerror();
            if(pop(&opd2,expSTK)==error) /* 将运算量 2 出栈 */
                synerror();
            temp=eval(c,opd2,opd1); /* 计算得到结果 */
            push(&temp,expSTK); /* 将运算结果进栈 */
        }
        else synerror(); /* 出现非法字符 */
    } /* while */
    if(pop(&opd1,expSTK)==error) synerror();
    if(!(emptySTK(expSTK))) synerror();
    printf("=%-3d\n",opd1);

    return 0;
}

运行结果:

 

4. 递归程序设计实训例题:求 Fibonacci 数列函数的实现前 n 项的值,n 由键盘输入,每行输出 4 项。

 

【问题描述】

由题意可知,Fibonacci 数列的第一项、第二项的值都为 1,从第三项起,每一项的值均是其前面两项值之和。

#include<stdio.h>
#include<malloc.h>

long fib(int i)
{
    if(i==1||i==2)
        return(1);
    else
        return(fib(i-1)+fib(i-2));
}

int main()
{
    int i,n;
    long fib();
    printf("Please input fibnacci number:");
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        printf("fib(%d)=%2ld   ",i,fib(i));
        if(i%4==0)
            printf("\n");
    }
    
    return 0;
}

运行结果:

 

更多推荐