栈文档之共享栈

Posted 二木成林

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了栈文档之共享栈相关的知识,希望对你有一定的参考价值。

共享栈

定义

概念

共享栈是顺序栈的变种。利用栈底位置相对不变的特性,可以让两个顺序栈共享一个一维数组空间,将两个栈的栈底分别设置在共享空间的两端,两个栈顶向共享空间的中间延申,如图所示:

其中两个栈的栈顶指针都指向栈顶元素。top0=-1 时表示 0 号栈为空,top1=MAXSIZE 时表示 1 号栈为空(这是设定,因为栈顶指针存储的是下标,而 -1MAXSIZE 都表示不合法的下标,所以用来指定初始栈空条件)。当两个栈顶指针相邻(即 top1 - top0 = 1)时,判断栈满。

共享栈能够更加有效地利用存储空间,两个栈的空间相互调节,只会在整个存储空间被栈满时才会发生上溢,存取数据的时间复杂度仍为 O(1)

我们将共享栈中左边的顺序栈称为 0 号栈,右边的顺序栈称为 1 号栈。注意,这仅是一个区分的称呼而已。

结构体

共享栈的结构体跟顺序栈的结构体定义类似,只是共享栈多一个栈顶指针变量。关于结构体有以下两种形式:

  • ①两个整型变量 top0top1 来分别存储 0 号和 1 号栈的栈顶指针。
/**
 * 共享栈结构体定义
 */
typedef struct 
    /**
     * 数据域,存储栈中元素
     */
    int data[MAXSIZE];
    /**
     * 指针域,记录 0 号栈的栈顶指针
     */
    int top0;
    /**
     * 指针域,记录 1 号栈的栈顶指针
     */
    int top1;
 SharedStack;
  • ②用一个长度为 2 的整型数组来分别存储两个栈的栈顶指针,其中 top[0] 存放 0 号栈的栈顶指针;top[1] 存储 1 号栈的栈顶指针。
/**
 * 共享栈结构体定义
 */
typedef struct 
    /**
     * 数据域,存储栈中元素
     */
    int data[MAXSIZE];
    /**
     * 指针域,记录 0 号栈和 1 号栈的栈顶指针
     */
    int top[2];
 SharedStack;

特点

共享栈的特点如下:

  • 共享栈是两个顺序栈共享一个一维数组的空间。
  • 其中两个顺序栈的栈底位置不变,因为是将两个栈的栈底分别设置在共享空间的两端,两个栈的栈底分别向共享空间的中间延申。
  • top0==-1 时表示 0 号栈为空;当 top1==MAXSIZE 表示 1 号栈为空。这是自定义的规定,因为 -1MAXSIZE 都是数组下标不可设置的值。
  • 当两个栈顶指针相邻时,则栈满。即两个栈的栈顶指针之差的绝对值为 1 表示栈满。
  • 其中 0 号栈进栈时是栈顶指针 top0 先加一再赋值;其中 1 号栈进栈时是栈顶指针 top1 先减一再赋值。因为 top0 是从 -1 往后移动,所以是增加;而 top1 是从 MAXSIZE 向前移动,所以是减一。
  • 其中 0 号栈出栈时是先取值再栈顶指针 top0 减一;其中 1 号栈出栈时是先取值再栈顶指针 top1 加一。
  • 共享栈是为了更有效地利用存储空间,两个栈的空间相互调节,只有在整个存储空间被占满时才会发生上溢。共享栈存储和取用数据的时间复杂度均为 O(1)

基本操作

注,完整代码请参考:

概述

共享栈的常见操作如下:

  • void init(SharedStack *stack):初始化共享栈,即将 0 号栈的栈顶指针置为 -1 表示空栈,将 1 号栈的栈顶指针置为 MAXSIZE 表示空栈。其中 stack 表示未初始化的共享栈。
  • int isEmpty(SharedStack stack, int NUM):判断共享栈是否为空,如果为空则返回 1,否则返回 0 表示非空。其中 stack 表示共享栈。如果共享栈为空则返回 1,否则返回 0。
  • int isFull(SharedStack stack):判断共享栈是否已满。其中 stack 表示共享栈。如果共享栈已满则返回 1,否则返回 0。
  • int push(SharedStack *stack, int NUM, int ele):将元素压入共享栈中的指定序号栈中。其中 stack 表示共享栈;NUM 表示栈序号,只能是 0 号或者 1 号;ele 表示待入栈元素值。如果栈已满则不能入栈,返回 0 表示入栈失败,返回 1 表示入栈成功。
  • int pop(SharedStack *stack, int NUM, int *ele):将元素从共享栈中的指定序号栈中的栈顶元素出栈。其中 stack 表示共享栈;NUM 表示栈序号,只能是 0 号或者 1 号;ele 用来存储出栈的元素值。如果栈为空则不能出栈,返回 0 表示出栈失败,返回 1 表示出栈成功。
  • int getTop(SharedStack stack, int NUM, int *ele):获取共享栈中指定序号栈的栈顶元素。其中 stack 表示共享栈;NUM 表示栈序号,只能是 0 号或者 1 号;ele 用来存储出栈的元素值。如果栈为空则不能获取栈顶元素,返回 0 表示获取栈顶元素失败,返回 1 表示获取栈顶元素成功。
  • int size(SharedStack stack, int NUM):获取共享栈中指定序号栈的元素个数。其中 stack 表示共享栈;NUM 表示栈序号,只能是 0 号或者 1 号。返回指定序号栈中的元素个数。
  • void print(SharedStack stack, int NUM):打印指定序号栈中的所有元素。其中 stack 表示共享栈;NUM 表示栈序号,只能是 0 号或者 1 号。
  • void clear(SharedStack *stack, int NUM):清空指定序号栈中的所有元素。其中 stack 表示共享栈;NUM 表示栈序号,只能是 0 号或者 1 号。

init

初始化共享栈,即初始化 0 号栈和 1 号栈。

实现步骤:

  • 将 0 号栈的栈顶指针置为 -1
  • 将 1 号栈的栈顶指针置为 MAXSIZE

实现代码如下:

/**
 * 初始化共享栈
 * @param stack 未初始化的共享栈
 */
void init(SharedStack *stack) 
    // 1.需要同时初始化 0 号栈和 1 号栈
    // 1.1 将 0 号栈的栈顶指针指向 -1,表示 0 号栈是空栈
    stack->top[0] = -1;
    // 1.2 将 1 号栈的栈顶指针指向 MAXSIZE,表示 1 号栈是空栈
    stack->top[1] = MAXSIZE;

isEmpty

判断共享栈中指定序号栈是否为空。

实现步骤:

  • 如果 0 号栈的栈顶指针为 -1 则表示 0 号栈空。
  • 如果 1 号栈的栈顶指针为 MAXSIZE 表示 1 号栈空。

实现代码如下:

/**
 * 判断指定序号的栈是否是空栈
 * @param stack 共享栈
 * @param NUM 栈序号,只能传入 0 或者 1
 * @return 如果指定栈是空栈则返回 1,否则返回 0 表示非空栈
 */
int isEmpty(SharedStack stack, int NUM) 
    if (NUM == 0) 
        // 0 号栈为空栈的条件是,栈顶指针指向 -1
        return stack.top[0] == -1;
     else if (NUM == 1) 
        // 1 号栈为空栈的条件是,栈顶指针指向 MAXSIZE
        return stack.top[1] == MAXSIZE;
     else 
        // 随便返回一个数,表示传入的序号不合法
        return -MAXSIZE;
    

isFull

判断共享栈是否已满。

实现步骤:

  • 判断 0 号栈和 1 号栈的栈顶指针之差的绝对值是否为 1,如果为 1 则表示已满,否则不是满栈。

实现代码如下:

/**
 * 判断共享栈是否是满
 * @param stack 共享栈
 * @return 如果是栈满则返回 1,否则返回 0 表示栈未满
 */
int isFull(SharedStack stack) 
    // 如果 0 号栈和 1 号栈的栈顶元素相邻,则表示栈已满
    if (stack.top[1] - stack.top[0] == 1) 
        return 1;
     else 
        return 0;
    

push

将元素压入共享栈中的指定序号栈中。其中 stack 表示共享栈;NUM 表示栈序号,只能是 0 号或者 1 号;ele 表示待入栈元素值。如果栈已满则不能入栈,返回 0 表示入栈失败,返回 1 表示入栈成功。

实现步骤:

  • 参数校验,如果共享栈满,则不能入栈,无论是几号栈。
  • 如果要将元素压入 0 号栈,则先将 0 号栈的栈顶指针增一,再赋值。
  • 如果要将元素压入 1 号栈,则先将 1 号栈的的栈顶指针减一,再赋值。

实现代码如下:

/**
 * 将元素压入栈
 * @param stack 共享栈
 * @param NUM 栈序号,只能传入 0 或者 1
 * @param ele 新元素
 * @return 如果栈满则返回 0 表示入栈失败;入栈成功则返回 1
 */
int push(SharedStack *stack, int NUM, int ele) 
    // 0.参数校验,如果栈满则不能入栈
    if (isFull(*stack)) 
        return 0;
    
    // 1.根据栈序号是 0 还是 1,来决定将元素存入哪个栈
    // 1.1 将元素存入 0 号栈
    if (NUM == 0) 
        // 1.1.1 先移动 0 号栈的栈顶指针。由于 0 号栈是从 -1 开始的,所以栈顶指针是往后增
        stack->top[0]++;
        // 1.1.2 再赋值
        stack->data[stack->top[0]] = ele;
    
    // 1.2 将元素存入 1 号栈
    else if (NUM == 1) 
        // 1.2.1 先移动 1 号栈的栈顶指针。由于 1 号栈是从 MAXSIZE 开始的,所以栈顶指针是往前减
        stack->top[1]--;
        // 1.2.2 再赋值
        stack->data[stack->top[1]] = ele;
    
    return 1;

pop

将元素从共享栈中的指定序号栈中的栈顶元素出栈。其中 stack 表示共享栈;NUM 表示栈序号,只能是 0 号或者 1 号;ele 用来存储出栈的元素值。如果栈为空则不能出栈,返回 0 表示出栈失败,返回 1 表示出栈成功。

实现步骤:

  • 参数校验,如果指定序号栈是空栈,则不能出栈。
  • 如果要将 0 号栈的栈顶元素出栈,先取出 0 号栈的栈顶元素,再将栈顶指针减一,表示删除 0 号栈的栈顶元素。
  • 如果要将 1 号栈的栈顶元素出栈,先取出 1 号栈的栈顶元素,再将栈顶指针加一,表示删除 1 号栈的栈顶元素。

实现代码如下:

/**
 * 将元素出栈
 * @param stack 共享栈
 * @param NUM 栈序号,只能传入 0 或者 1
 * @param ele 用来保存出栈元素
 * @return 如果栈空则返回 0 表示出栈失败;否则返回 1 表示出栈成功
 */
int pop(SharedStack *stack, int NUM, int *ele) 
    // 0.参数校验,如果任何一个栈栈空则不能出栈
    if (isEmpty(*stack, NUM)) 
        return 0;
    
    // 1.根据栈序号来决定将哪个栈的栈顶元素出栈
    // 1.1 如果要将 0 号栈的栈顶元素出栈
    if (NUM == 0) 
        // 1.1.1 用 ele 保存 0 号栈的栈顶元素
        *ele = stack->data[stack->top[0]];
        // 1.1.2 移动栈顶指针删除元素
        stack->top[0]--;
    
    // 1.2 如果要将 1 号栈的栈顶元素出栈
    else if (NUM == 1) 
        // 1.2.1 用 ele 保存 1 号栈的栈顶元素
        *ele = stack->data[stack->top[1]];
        // 1.2.2 移动栈顶指针删除元素
        stack->top[1]++;
    
    return 1;

getTop

获取共享栈中指定序号栈的栈顶元素。其中 stack 表示共享栈;NUM 表示栈序号,只能是 0 号或者 1 号;ele 用来存储出栈的元素值。如果栈为空则不能获取栈顶元素,返回 0 表示获取栈顶元素失败,返回 1 表示获取栈顶元素成功。

实现步骤:

  • 参数校验,如果共享栈中指定序号栈为空则不能获取到栈顶元素。
  • 如果要获取 0 号栈的栈顶元素,则直接取出 0 号栈的栈顶指针所指向的元素。
  • 如果要获取 1 号栈的栈顶元素,则直接取出 1 号栈的栈顶指针所指向的元素。

实现代码如下:

/**
 * 获取指定序号栈的栈顶元素,但不出栈
 * @param stack 共享栈
 * @param NUM 栈序号,只能传入 0 或者 1
 * @param ele 用来保存栈顶元素
 * @return 如果栈空则返回 0 表示出栈失败;否则返回 1 表示出栈成功
 */
int getTop(SharedStack stack, int NUM, int *ele) 
    // 0.参数校验,如果任何一个栈栈空则不能出栈
    if (isEmpty(stack, NUM)) 
        return 0;
    
    // 1.用 ele 保存栈顶元素
    // 1.1 用 ele 保存 0 号栈的栈顶元素
    if (NUM == 0) 
        *ele = stack.data[stack.top[0]];
    
    // 1.2 用 ele 保存 1 号栈的栈顶元素
    else if (NUM == 1) 
        *ele = stack.data[stack.top[1]];
    
    return 1;

size

获取共享栈中指定序号栈的元素个数。其中 stack 表示共享栈;NUM 表示栈序号,只能是 0 号或者 1 号。返回指定序号栈中的元素个数。

实现步骤:

  • 如果要获取 0 号栈的元素个数,则只需要将栈顶指针加一的和,就是 0 号栈的元素个数。
  • 如果要获取 1 号栈的元素个数,则需要将 MAXSIZE 减去 1 号栈的栈顶指针,就是 1 号栈的元素个数。

实现代码如下:

/**
 * 获取共享栈中指定序号栈的元素个数
 * @param stack 共享栈
 * @param NUM 栈序号,只能传入 0 或者 1
 * @return 指定序号栈的元素个数
 */
int size(SharedStack stack, int NUM) 
    // 变量,记录栈中结点个数
    int len = 0;
    // 1.获取指定序号栈的元素个数
    // 1.1 获取 0 号栈的元素个数
    if (NUM == 0) 
        // 下标从 0 开始,所以元素个数就是下标加一
        len = stack.top[0] + 1;
    
    // 1.2 获取 1 号栈的元素个数
    else if (NUM == 1) 
        // 1 号栈的元素从后往前,所以计算栈的元素个数是 MAXSIZE 减去 1 号栈的栈顶指针
        len = MAXSIZE - stack.top[1];
    
    return len;

print

打印指定序号栈中的所有元素。其中 stack 表示共享栈;NUM 表示栈序号,只能是 0 号或者 1 号。

实现步骤:

  • 如果要打印 0 号栈中的所有元素,则从 0 号栈的栈顶元素,开始向 0 号栈的栈底遍历所有元素。注意,循环变量是逐步减一的。
  • 如果要打印 1 号栈中的所有元素,则从 1 号栈的栈顶元素,开始向 1 号栈的栈底遍历所有元素。注意,循环变量是逐步增一的。

实现代码如下:

/**
 * 打印指定序号栈中的所有元素
 * @param stack 共享栈
 * @param NUM 栈序号,只能传入 0 或者 1
 */
void print(SharedStack stack, int NUM) 
    printf("[");
    // 变量,记录栈顶指针
    int top;
    if (NUM == 0) 
        top = stack.top[0];
        for (int i = top; i >= 0; i--) 
            printf("%d", stack.data[i]);
            if (i != 0) 
                printf(", ");
            
        
     else if (NUM == 1) 
        top = stack.top[1];
        for (int i = top; i < MAXSIZE; i++) 
            printf("%d", stack.data[i]);
            if (i != MAXSIZE - 1) 
                printf(", ");
            
        
    
    printf("]\\n");

clear

清空指定序号栈中的所有元素。其中 stack 表示共享栈;NUM 表示栈序号,只能是 0 号或者 1 号。

实现步骤:

  • 如果要清空 0 号栈,只需要将 0 号栈的栈顶指针置为 -1。不需要将 0 号栈的已有元素重置为某个值。
  • 如果要清空 1 号栈,只需要将 1 号栈的栈顶指针置为 MAXSIZE。不需要将 1 号栈的已有元素重置为某个值。

实现代码如下:

/**
 * 清空 0 号栈的所有元素
 * @param stack 共享栈
 * @param NUM 栈序号,只能传入 0 或者 1
 */
void clear(SharedStack *stack, int NUM) 
    if (NUM == 0) 
        // 直接将 0 号的栈顶指针指向 -1,就表示是空栈
        stack->top[0] = -1;
     else if (NUM == 1) 
        // 直接将 1 号的栈顶指针指向 MAXSIZE,就表示是空栈
        stack->top[1] = MAXSIZE;
    

附录

附录一:初始版本

初始版本代码中 0 号和 1 号的入栈出栈操作是在不同函数中,而在上面代码,0 号和 1号的入栈或出栈操作是在同一个函数中,仅通过参数 NUM 来区分是哪个栈。其中共享栈的初始版本代码,如下:

#include<stdio.h>

/**
 * 共享栈能存储的最大元素个数
 */
#define MAXSIZE 100

/**
 * 共享栈结构体定义
 */
typedef struct 
    /**
     * 数据域,存储栈中元素
     */
    int data[MAXSIZE];
    /**
     * 指针域,记录 0 号栈的栈顶指针
     */
    int top0;
    /**
     * 指针域,记录 1 号栈的栈顶指针
     */
    int top1;
 SharedStack;

/**
 * 初始化共享栈
 * @param stack 未初始化的共享栈
 */
void init(SharedStack *stack) 
    // 1.需要同时初始化 0 号栈和 1 号栈
    // 1.1 将 0 号栈的栈顶指针指向 -1,表示 0 号栈是空栈
    stack->top0 = -1;
    // 1.2 将 1 号栈的栈顶指针指向 MAXSIZE,表示 1 号栈是空栈
    stack->top1 = MAXSIZE;


/**
 * 判断 0 号栈是否是空栈
 * @param stack 共享栈
 * @return 如果是空栈则返回 1,否则返回 0 表示非空栈
 */
int isEmptyStack0(SharedStack *stack) 
    // 0 号栈为空栈的条件是,栈顶指针指向 -1
    if (stack->top0 == -1) 
        return 1;
     else 
        return 0;
    


/**
 * 判断 1 号栈是否是空栈
 * @param stack 共享栈
 * @return 如果是空栈则返回 1,否则返回 0 表示非空栈
 */
int isEmptyStack1(SharedStack *stack) 
    // 1 号栈为空栈的条件是,栈顶指针指向 MAXSIZE
    if (stack->top1 == MAXSIZE) 
        return 1;
     else 
        return 0;
    


/**
 * 判断共享栈是否是满
 * @param stack 共享栈
 * @return 如果是栈满则返回 1,否则返回 0 表示栈未满
 */
int isFull(SharedStack *stack) 
    // 如果 0 号栈和 1 号栈的栈顶元素相邻,则表示栈已满
    if (stack->top1 - stack->top0 == 1) 
        return 1;
     else 
        return 0;
    


/**
 * 将元素压入 0 号栈
 * @param stack 共享栈
 * @param ele 新元素
 * @return 如果栈满则返回 0 表示入栈失败;入栈成功则返回 1
 */
int pushStack0(SharedStack *stack, int ele) 
    // 0.参数校验,如果栈满则不能入栈
    if (isFull(stack)) 
        return 0;
    
    // 1.由于 0 号栈是从 -1 开始的,所以栈顶指针是往后增
    stack->top0++;
    // 2.栈顶指针增加后,将新元素填入到栈顶指针指向的位置
    stack->data[stack->top0] = ele;
    return 1;


/**
 * 将元素压入 1 号栈
 * @param stack 共享栈
 * @param ele 新元素
 * @return 如果栈满则返回 0 表示入栈失败;入栈成功则返回 1
 */
int pushStack1(SharedStack *stack, int ele) 
    // 0.参数校验,如果栈满则不能入栈
    if (isFull(stack)) 
        return 0;
    
    // 1.由于 1 号栈是从 MAXSIZE 开始的,所以栈顶指针是往前减
    stack->top1--;
    // 2.栈顶指针变化后,将新元素填入到栈顶指针指向的位置
    stack->data[stack->top1] = ele;
    return 1;


/**
 * 将元素从 0 号栈出栈
 * @param stack 共享栈
 * @param ele 用来保存出栈元素
 * @return 如果栈空则返回 0 表示出栈失败;否则返回 1 表示出栈成功
 */
int popStack0(SharedStack *stack, int *ele) 
    // 0.参数校验,如果 0 号栈空则不能出栈
    if (stack->top0 == -1) 
        return 0;
    
    // 1.用 ele 保存 0 号栈的栈顶元素
    *ele = stack->data[stack->top0];
    // 2.然后栈顶指针减一,表示已经删除栈顶元素
    stack->top0--;
    return 1;


/**
 * 将元素从 1 号栈出栈
 * @param stack 共享栈
 * @param ele 用来保存出栈元素
 * @return 如果栈空则返回 0 表示出栈失败;否则返回 1 表示出栈成功
 */
int popStack1(SharedStack *stack, int *ele) 
    // 0.参数校验,如果 1 号栈空则不能出栈
    if (stack->top1 == MAXSIZE) 
        return 0;
    
    // 1.用 ele 保存 1 号栈的栈顶元素
    *ele = stack->data[stack->top1];
    // 2.然后栈顶指针加一,表示已经删除 1 号栈的栈顶元素
    stack->top1++;
    return 1;


/**
 * 获取 0 号栈的栈顶元素,但不出栈
 * @param stack 共享栈
 * @param ele 用来保存栈顶元素
 * @return 如果栈空则返回 0 表示出栈失败;否则返回 1 表示出栈成功
 */
int getTop0(SharedStack *stack, int *ele) 
    // 0.参数校验,如果 0 号栈空则不能出栈
    if (stack->top0 == -1) 
        return 0;
    
    // 1.用 ele 保存 0 号栈的栈顶元素
    *ele = stack->data[stack->top0];
    return 1;


/**
 * 获取 1 号栈的栈顶元素,但不出栈
 * @param stack 共享栈
 * @param ele 用来保存栈顶元素
 * @return 如果栈空则返回 0 表示出栈失败;否则返回 1 表示出栈成功
 */
int getTop1(SharedStack *stack, int *ele) 
    // 0.参数校验,如果 1 号栈空则不能出栈
    if (stack->top1 == MAXSIZE) 
        return 0;
    
    // 1.用 ele 保存 1 号栈的栈顶元素
    *ele = stack->data[stack->top1];
    return 1;


/**
 * 获取 0 号栈中的元素个数
 * @param stack 共享栈
 * @return 0 号栈的元素个数
 */
int sizeStack0(SharedStack *stack) 
    // 下标从 0 开始,所以元素个数就是下标加一
    return stack->top0 + 1;


/**
 * 获取 1 号栈中的元素个数
 * @param stack 共享栈
 * @return 1 号栈的元素个数
 */
int sizeStack1(SharedStack *stack) 
    // 1 号栈的元素从后往前,所以计算栈的元素个数是 MAXSIZE 减去 1 号栈的栈顶指针
    return MAXSIZE - stack->top1;


/**
 * 共享栈中的元素总个数
 * @param stack 共享栈
 * @return 元素总个数
 */
int size(SharedStack *stack) 
    int len0 = stack->top0 + 1;
    int len1 = MAXSIZE - stack->top1;
    // 即 0 号栈和 1 号栈的元素个数之和
    return len0 + len1;


/**
 * 打印 0 号栈中的所有元素
 * @param stack 共享栈
 */以上是关于栈文档之共享栈的主要内容,如果未能解决你的问题,请参考以下文章

栈文档之栈

数据结构之栈——多栈共享技术

栈和队列

栈和队列

两栈共享空间

数据结构&算法-共享栈