堆栈的详细理解

1。栈的基本概念

栈(STACK)又称为堆栈,是一种“特殊”的线性表,这种线性表的插入和删除运算只允许在表的一端进行。允许进行插入和删除运算的这一端称为栈顶(TOP),不允许进行插入和删除运算的另一端则称为栈底(BOTTOM);向栈中插入一个新元素称为入栈或压栈,从栈中删除一个元素称为出栈或退栈;通常,记录栈顶元素位置的变量称为栈顶指针,处于栈顶位置的数据元素称为栈顶元素;而不含有任何数据的栈则称为空栈。图1。1就是一个栈的结构示意图。

由于栈的插入和删除运算仅在栈顶一端进行,所以最先进栈的元素一定放栈底,最后进栈的元素一定放在栈顶,最后进栈的元素也必定最先出栈。在图1。1所示栈中,元素以a1,a2, ... , an-1,an的顺序进栈,而出栈次序恰好相反是an,an-1, ... , a2,a1。可见,栈是按后进先出的原则进行操作的。因此,栈又称为后进先出表(LAST IN FIRST OUT),简称LIFO表。
栈的学习--顺序栈

2。栈的存储结构

栈的存储结构主要分两种:栈的顺序存储结构和链接存储结构。


2。1栈的顺序存储

栈的顺序存储结构称为顺序栈。顺序栈可以用一个一维数组和一个记录栈顶位置的整形变量来实现,数组用于顺序存储栈中所有的数据元素,栈顶指针用于存储栈顶元素的位置。
若将顺序栈定义为一个结构类型seqstack,其类型定义如下:

#define MAXSIZE 100
typedef int datatype;
typedef struct
{
      datatype  stack[MAXSIZE];
      int top
}seqstack;

seqstack *S;


其中,TOP 是栈顶指针,用于提示栈顶元素在数组中的下标值,其初值指向栈底,即TOP=-1。STACK是一维数组,用于存储栈中所有的数据元素。DATATYPE是栈中元素的数据类型,可根据需要而指定其具体的类型。MAXSIZE表示栈的最在存储容量。

在使用过程中,顺序栈的内容总是在不断变化的,正确识别栈的变化情况是非常重要的。采用顺序存储结构时,栈共有三种形态:空栈、满栈和非满非空栈,它们都是通过栈顶指针TOP体现出来的。下面给出这三种形态下,栈顶指针TOP的对应情况。

顺序栈的栈底可以设在数组的任意位置,栈顶是随着进栈和退栈操作不断变化的。假设我们规定:将顺序栈的栈底设在数组的底端,即S-stack[0]表示栈底元素。当S-top=-1时,则表示空栈;当S-top=MAXSIZE-1时,表示满栈。由于栈顶指针S-top是正向增长的,所以每次向栈中插入一个元素时,首先将S-top加1,用以提示新的栈顶元素,然后再把元素存放到这个位置上;每次从栈中删除一个元素时,首先取出栈顶元素,然后将S-top减1,使栈顶指针指向新的栈顶元素。由此可见,对顺序栈的插入和删除运算相当于在顺序表的表尾进行插入和删除操作,其时间复杂度为O(1)。

2。2 顺序栈的基本操作

1)。顺序栈的初始化运算
void INITSTACK(seqstack *S)
{
    S->top =-1;   
}

2)。检查顺序栈是否为空栈的运算
int EMPTY(seqstack *S)
{
    if(S->top< 0)
        return TRUE;
    else
        return NULL;
}
3)。向顺序栈中插入元素的运算

在顺序栈存储结构中,顺序栈的进栈过程如下:

(1)检查栈是否已满,若栈满,则进行“溢出”错识处理;
(2)否则,将栈顶指针加1,使之指向下一个单元;
(3)将新结点的值赋给栈顶指针所指向的单元;

seqstack *PUSH(seqstack *S, datatype x)
{
    if(S->top >= MAXSIZE-1)
    {
        printf("栈满溢出错误!\n");
        return NULL;
    }
    else
    {
        S->top++;
        S->stack[S->top]=x;
    }
    return S;
}
4)。从顺序栈中删除栈顶元素的运算

在顺序栈存储结构中,顺序栈的出栈过程如下:

(1)检查栈是否已空,若栈空,则进行“下溢”错识处理,终止程序运行;
(2)否则,保留或暂存栈顶元素以便返回给调用者;
(3)将栈顶指针减1;

datatype POP(seqstack *S)
{
    datatype x;
    if(EMPTY(S))
    {
        printf("下溢错误!\n");
        return NULL;
    }
    else
    {
        x=S->stack[S->top];
        S->top--;
        return x;
    }
}
5)。顺序栈取栈顶元素的运算

不管在哪种存储结构中,只要在出栈函数中去掉栈顶指针TOP及栈内容的修改,就可以完成取栈顶元素的操作。

int gettop_seqstack(seqstack *S)
{
    if(EMPTY(S))
    {
        printf("栈是空栈!\n");
        return NULL;
    }
    else
    {
        return (S->stack[S->top]);   
    }
}

2。3 顺序栈的简单应用

从键盘输入一批正整数,然后按相反的次序打印出来。

1)。File: stack.h

//
//File: stack.h
//
#ifndef STACK_H
#define STACK_H

#define TRUE 1
#define NULL 0
#define MAXSIZE 100

typedef int datatype;

struct _seqstack{
    datatype stack[MAXSIZE];
    int top;
};

typedef struct _seqstack seqstack;


void INITSTACK(seqstack *S);

int EMPTY(seqstack *S);

seqstack *PUSH(seqstack *S, int x);

int POP(seqstack *S);

int gettop_seqstack(seqstack *S);

#endif

2)。File: stack.c

#include "stack.h"
#include <stdio.h>


void INITSTACK(seqstack *S)
{
    S->top =-1;   
}

int EMPTY(seqstack *S)
{
    if(S->top< 0)
        return TRUE;
    else
        return NULL;
}

seqstack *PUSH(seqstack *S, datatype x)
{
    if(S->top >= MAXSIZE-1)
    {
        printf("栈满溢出错误!\n");
        return NULL;
    }
    else
    {
        S->top++;
        S->stack[S->top]=x;
    }
    return S;
}

datatype POP(seqstack *S)
{
    datatype x;
    if(EMPTY(S))
    {
        printf("下溢错误!\n");
        return NULL;
    }
    else
    {
        x=S->stack[S->top];
        S->top--;
        return x;
    }
}

int gettop_seqstack(seqstack *S)
{
    if(EMPTY(S))
    {
        printf("栈是空栈!\n");
        return NULL;
    }
    else
    {
        return (S->stack[S->top]);   
    }
}

3)。File: main.c

#include <stdio.h>
#include "stack.h"

seqstack b;
seqstack *a=&b;

int main(int argc, char* argv[])
{
    int x , n=0;

    INITSTACK(a);
    printf("\n请输入数据,以-1结束:\n");
    scanf("%d",&x);
    while(x!=-1)
    {
        a=PUSH(a,x);
        n++;
        scanf("%d",&x);
    }
    printf("n=%d\n",n);
    while(EMPTY(a)!=1)
    {
        x=POP(a);
        printf("%d ",x);
        n--;
    }
   
    return 0;
}

posted @ 2017-09-09 11:47  你好,伟  阅读(1976)  评论(0)    收藏  举报