【精选】数据结构-栈详解(类C语言版)

155 阅读7分钟

目录

栈的定义

概念

栈的抽象数据类型定义

顺序栈的基本操作

 存储方式

顺序栈的表示

顺序栈的初始化

顺序栈判断是否为空

清空顺序栈

 销毁顺序栈

顺序栈的入栈

顺序栈的出栈

 取顺序栈的栈顶元素

链栈的基本操作

链栈的表示

链栈的初始化

判断链栈是否为空

链栈的入栈

链栈的出栈

取栈顶元素

栈与递归

分治法求解递归问题算法的一般形式

尾递归转变为循环结构

单向递归转变为循环结构


栈的定义

概念

栈 (stack) 是限定仅在表尾进行插入或删除操作的线性表。 因此, 对栈来说, 表尾端有其特殊含义, 称为栈顶 (top), 相应地, 表头端称为栈底 (bottom)。 不含元素的空表称为空栈。

栈又称为后进先出 (Last In First Out, LIFO) 的线性表。

栈的抽象数据类型定义

ADT Stack {

数据对象:

        D = {ai | ai ∈ElemSet , i = 1,2,...,n,n≥0 }

数据关系:

        R1 = { <ai-1, ai > | ai-1, ai ∈ D, i=2,...,n }

        约定an端为栈顶,a1端为栈底。

基本操作:初始化、进栈、出栈、取栈顶元素等

}ADT Stack

顺序栈的基本操作

 存储方式

同一般线性表的顺序存储结构完全相同。

利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素。栈底一般在低地址端。

· 附设top指针,指示栈顶元素在顺序栈中的位置。

· 另设base指针,指示栈底元素在顺序栈中的位置。

(但是,为了方便操作,通常top指示真正栈顶元素之上的下标地址。)

· 另外,用stacksize表示栈可使用的最大容量。

 空栈:base==top是栈空标志。

栈满:top-base==stacksize。

 下图所示栈中元素和栈指针之间的关系

顺序栈的表示

#define MAXSIZE 100
typedef struct {
    SElemType *base; // 栈底指针
    SElemType *top;  // 栈顶指针
    int stacksize;   // 栈可用最大容量
} SqStack;

顺序栈的初始化

Status InitStack(SqStack &S) {    // 构造一个空栈
    S.base = new SElemType[MAXSIZE];    // 或S.base = (SElemType*)malloc(MAXSIZE*sizeof(SelemType));
    if (!S.base)    exit(OVERFLOW);     // 存储分配失败
    S.top = S.base;                     // 栈顶指针等于栈底指针
    S.stacksize = MAXSIZE;
    return OK;
}

顺序栈判断是否为空

栈顶指针等于栈底指针,就认为顺序栈为空

Status StackEmpty(SqStack S) {
    // 若栈为空,返回TRUE;否则返回FALSE    
    if (S.top == S.base)
        return TRUE;
    else
        return FALSE;
}

 

清空顺序栈

清空顺序栈就是将栈顶指针移到栈底指针。

Status ClearStack(SqStack S) {
    if(S.base)   S.top = S.base;
    return OK;
}

 销毁顺序栈

Status DestroyStack(SqStack &S) {
    if(S.base) {
        delete S.base;
        S.stacksize = 0;
        S.base = S.top = NULL;
    }
    return OK;
}

顺序栈的入栈

① 判断是否栈满,若满则出错(上溢)。

② 元素e压入栈顶。

③ 栈顶指针加1。

Status Push(SqStack &S, SElemType e) {
    if(S.top - S.base == S.stacksize)    // 栈满
        return ERROR;
    *S.top++=e;            // 可以分开写,*S.top=e;S.top++;
    return OK;
}

顺序栈的出栈

① 判断是否栈空,若空则出错(下溢)。

② 获取栈顶元素e。

③ 栈顶指针减1。

Status Pop(SqStack &S, SElemType &e) {
    // 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
    if(S.top == S.base)    // 等价于if(StackEmpty(S))
        return ERROR;
    e = *--S.top;          // 可分解为两步--S.top; e = *S.top;
    return OK;
}

 取顺序栈的栈顶元素

SElemType GetTop(SqStack S) {
    // 返回S的栈顶元素,不修改栈顶指针
    if(S.top != S.base)    // 栈非空
        return *(S.top-1)  // 返回栈顶元素的值,栈顶指针不变
}

链栈的基本操作

链栈的表示

链栈是运算受限的单链表,只能在链表头部进行操作。

· 链表的头指针就是栈顶。

· 不需要头结点。

· 基本不存在栈满的情况。

· 空栈相当于头指针指向空。

· 插入和删除仅在栈顶处执行。

注意:链栈中的指针方向。

typedef struct StackNode {
    SElemType data;
    struct StackNode *next;
} StackNode, *LinkStack;
LinkStack S;

链栈的初始化

void InitStack(LinkStack &S) {
    // 构造一个空栈,栈顶指针置为空
    S=NULL;
    return OK;
}

判断链栈是否为空

Status StackEmpty(LinkStack S) {
    if(S==NULL) return TRUE;
    else return FALSE;
}

链栈的入栈

Status Push(LinkStack &S, SElemType e) {
    p = new StackNode;        // 生成新结点p
    p -> data = e;            // 将新结点数据域置为e
    p -> next = S;            // 将新结点插入栈顶
    S = p;                    // 修改栈顶指针
    return OK;
}

链栈的出栈

Status Pop(LinkStack &S, SElemType &e) {
    if (S == NULL) return ERROR;
    e = S -> data;
    p = S;
    S = S -> next;
    delete p;
    return OK;
}

取栈顶元素

SElemType GetTop(LinkStack S) {
    if (S != NULL)
        return S -> data;
}

栈与递归

分治法求解递归问题算法的一般形式

void p (参数表) {
    if(递归结束条件) 可直接求解步骤;     ----- 基本项
    else p(较小的参数);                 -----归纳项
}

例如

long Fact(long n) {
    if(n == 0) return 1;          // 基本项
    else return n * Fact(n-1);    // 归纳项
}

尾递归转变为循环结构

long Fact(long n) {
    if(n == 0) return 1;
    else return n * Fact(n-1);
}

以上递归可以写成循环结构

long Fact(long n) {
    t = 1;
    for(i = 1; i <= n; i++)    t = t*i;
    return t;
}

单向递归转变为循环结构

虽然有一处以上的递归调用语句,但各次递归调用语句的参数只和主调函数有关,相互之间参数无关,并且这些递归调用语句处于算法的最后。

long Fib(long n) {    // Fibonacci数列
    if(n==1||n==2) return 1;
    else return Fib(n-1) + Fib(n-2);
}

 转换为循环结构

long Fib(long n) {
    if(n==1||n==2) return 1;
    else {
        t1 = 1; t2 = 1;
        for(i=3;i<=n;i++){
            t3=t1+t2;
            t1=t2;t2=t3;
        }
        return t3;
    }
}