顺序栈的相关的实现

本文深入讲解了栈这一数据结构的概念及其实现方式,包括栈的基本操作如入栈、出栈等,并通过具体代码示例展示了如何使用顺序表来实现栈。

一、栈的基本概念

栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针。
栈是允许在同一端进行插入和删除操作的特殊线性表。允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom);栈底固定,而栈顶浮动;栈中元素个数为零时称为空栈。插入一般称为进栈(PUSH),删除则称为退栈(POP)。栈也称为后进先出表。

二、顺序栈的结构

我们先来看看栈的实现
这里写图片描述

三、栈的基本实现

1、数据结构

  typedef char  StackType; 
  7 typedef struct SeqStack{
  8     StackType* data;//使内存可以动态管理
  9     int size;//栈元素的有效个数
 10     int capacity;//栈默认的空间,data这段内存上所能容纳的元素的个数
 11     }SeqStack;
 12 

2、顺序表初始化

  3 void SeqStackInit(SeqStack* stack){
  4     if(stack==NULL){
  5         return;
  6     }
  7     stack->size=0;
  8     stack->capacity=1000;
  9     stack->data=(StackType*)malloc(stack->capacity*sizeof(StackType));
 10 }

3、栈的销毁

 void SeqStackDestroy(SeqStack* stack)//销毁函数
 13 {
 14     if(stack==NULL){
 15         return;
 16     }
 17     free(stack->data);
 18     stack->size=0;
 19     stack->capacity=0;
 20 }

4、打印函数

 void SeqStackPrint(SeqStack* stack,const char* msg)//打印函数
 23 {
 24     printf("[ %s ]\n",msg);
 25     if(stack==NULL){
 26         return ;
 27     }
 28     int i=0;
 29     for(i=0;i<stack->size;i++){
 30         printf("[%c] ",stack->data[i]);
 31     }
 32     printf("\n");
 33 }

5、扩容
扩容时,我们扩容的策略由自己设置,在这里用原大小的*2+1,原因由于STL扩容原则为*2,+1是为了避免原大小为1的可能性。扩容完毕之后,我们需要将我们以前的数据搬运过来,并且需要释放掉原来那些不用的内存,以防发生内存泄露。

void SeqStackResize(SeqStack* stack)//扩容
 36 {
 37     if(stack==NULL){
 38         return;
 39     }
 40     if((stack->size)<(stack->capacity)){
 41         return;
 42     }
 43     stack->capacity=stack->capacity*2+1;
 44 StackType* new=(StackType*)malloc(stack->capacity*sizeof(StackType));
 45            int i=0;
 46            for(i=0;i<stack->size;i++){
 47                new[i]=stack->data[i];
 48            }
 49            free(stack->data);
 50            stack->data=new;
 51 
 52 }

6、入栈


 54 void SeqStackPush(SeqStack* stack,StackType value)//入栈
 55 {
 56     if(stack==NULL){
 57         return;
 58     }
 59     if((stack->size)>=(stack->capacity)){
 60         SeqStackResize(stack);
 61     }
 62     stack->data[stack->size++]=value;
 63 }

7、出栈操作

 void SeqStackPop(SeqStack* stack)//出栈
 66 { 
 67     if(stack==NULL){
 68         return;
 69     }
 70     if(stack->size==0){
 71         return ;
 72     }//空栈
 73     --stack->size;
 74 }

8、取栈顶元素

` int  SeqStackTop(SeqStack* stack,StackType *value)//取栈顶元素
 77 {
 78 
 79     if(stack==NULL){
 80           return ;
 81      }
 82       if(stack->size==0){
 83           return ;//空栈
 84       }
 85       *value=stack->data[stack->size-1];
 86       return   *value;
 87 }
 88 
 89 

9、进行测试函数的实现

///////////////////////////////////////////////////////////
///////////////////////test.c///////////////////////////////
///////////////////////////////////////////////////////////
#define TEST_HEADER printf("\n=================%s=============\n",__FUNCTION__);

void test1(){
    SeqStack stack;
    SeqStackInit(&stack);
}
void test2(){
    SeqStack stack;
    SeqStackInit (&stack);
    SeqStackPush(&stack,'a');
    SeqStackPush(&stack,'b');
    SeqStackPush(&stack,'c');   
    SeqStackPush(&stack,'d');   
    SeqStackPush(&stack,'e');   
    SeqStackPrint(&stack,"入栈五个元素");
}
void test3(){

    SeqStack stack;
    SeqStackInit (&stack);
    SeqStackPush(&stack,'a');
    SeqStackPush(&stack,'b');
    SeqStackPush(&stack,'c');   
    SeqStackPush(&stack,'d');   
    SeqStackPush(&stack,'e');   
    SeqStackPrint(&stack,"入栈五个元素");
    SeqStackPop(&stack);
    SeqStackPrint(&stack,"出栈一个元素");
}

    void test4(){

    SeqStack stack;
    SeqStackInit (&stack);
    SeqStackPush(&stack,'a');
    SeqStackPush(&stack,'b');
    SeqStackPush(&stack,'c');   
    SeqStackPush(&stack,'d');   
   // SeqStackPush(&stack,'e');   
    SeqStackPrint(&stack,"入栈五个元素");
    StackType value;
    int ret= SeqStackTop(&stack,&value);
    printf("expected ret = %c, actual ret = %c\n", value);
    printf("expected value = %c, actual value = %c\n", ret);
}


int main(){



//    test1();
  //  test2();
    test3();
    test4();

    return 0;
}

`

<think>根据用户需求,我们需要实现一个数据结构,并处理输序列完成出栈操作,按指定格式输结果。 引用[4]提供了一个C++实现,我们可以参考其结构。但用户没有指定语言,根据之前引用中Java和C++都有现,但用户最后提到的是C++代码,所以这里用C++实现。 用户需求:输整数序列,完成出栈操作并按格式输。 注意:引用[4]中的代码框架已经提供了的基本操作:初始化(Init)、(push)、出栈(pop)、取顶(top)。但是,用户的需求可能需要我们根据输序列来执行操作。 根据引用[4]中的main函数,它读取一个整数n(表示操作次数),然后循环n次,每次读取一个整数e。当e为-1时执行出栈操作并输出栈顶元素,否则执行操作。 但用户希望按指定格式输结果,我们可以参考以下输格式: 输格式:首先输一个整数n,表示接下来有n行输。每行输一个整数,非负整数表示操作,-1表示出栈操作。注意,当输0时程序结束(引用[4]中while(cin>>n&&n!=0))。 输格式:当遇到出栈操作时(即输-1),如果为空,则输"POP ERROR";否则,输出栈顶元素并执行出栈操作(即先输出栈顶元素再出栈)。操作不产生输。 但是,引用[4]的代码中push函数在遇到-1时执行出栈操作并输,否则。而main函数中,先输一个整数n,然后循环n次调用push函数。然而,该代码在输0时结束循环。 然而,用户提供的引用[4]代码中,push函数的设计是将输整数e作为参数?但实际上在push函数内部读取整数,这与通常的操作不符。我们重新设计: 根据用户需求,我们需要一个,支持: 1. 初始化 2. :将元素压顶 3. 出栈:弹出栈顶元素,并返回该元素(同时删除) 4. 取顶:获取顶元素但不弹 同时,程序流程: 输:首先输一个整数n,表示操作次数。接下来n行,每行一个整数,如果整数>=0,表示操作(将该整数);如果整数=-1,表示出栈操作(需要输出栈顶元素并弹,若空则输错误信息)。 输:每次出栈操作对应一行输:如果不空,输出栈顶元素;如果空,输"POP ERROR"。 注意:引用[4]中的代码在push函数里读取整数,这不太合理。我们修改为:在main函数中读取输,然后根据输值决定操作。 重新设计代码结构: 1. 定义结构(使用数组或指针) 2. 初始化 3. 函数:将元素压顶 4. 出栈函数:弹出栈顶元素(注意空情况) 5. 获取顶元素函数(同样需要处理空) 我们参考引用[4]的结构定义,但稍作修改: 由于需要处理多个测试用例(输0结束),每个测试用例以n开始(n表示操作次数)。 具体步骤: while(输n && n!=0) 初始化 循环n次: 输一个整数x 如果x>=0,则 如果x==-1,则: 如果不空,则输出栈顶元素并出栈 如果空,输"POP ERROR" 注意:每次出栈操作都要输一行。 另外,引用[4]中的结构: typedef struct { int* base; // 底指针 int* top; // 顶指针 int stacksize; // 的最大容量 } sqstack; 我们使用这个结构,并实现以下函数: InitStack(sqstack &s): 初始化,分配maxsize大小的数组,base指向它,top初始等于base,stacksize=maxsize。 Push(sqstack &s, int e): 将e。注意:如果满,根据题目需求可以不考虑(因为maxsize=100,且题目没有说超过的情况)。 Pop(sqstack &s): 出栈,移动top指针(top--)。注意空判断。 GetTop(sqstack s): 获取顶元素,返回*(s.top-1)。注意空判断。 但是,由于题目要求输出栈顶元素后出栈,所以我们可以先调用GetTop,再调用Pop。 根据以上分析,我们编写代码。 注意:引用[4]中,push函数内部读取整数,而我们改为由main读取,然后调用Push或Pop。因此,我们需要修改。 代码步骤: 1. 包含头文件 2. 定义结构和相关函数 3. main函数:循环读取n,当n不为0时,对每个测试用例: 初始化 循环n次: 读取一个整数x 如果x>=0,调用Push(s, x) 如果x==-1: 判断是否为空(s.top == s.base) 为空则输"POP ERROR" 不为空则:输GetTop(s),然后调用Pop(s) 注意:每个测试用例结束后,需要释放的内存吗?在下一个测试用例开始时会重新初始化,所以我们可以不释放(因为maxsize固定,且程序运行时间短)。但为了严谨,可以在每个测试用例最后销毁(delete[] s.base)。 重新调整:在循环体内,每个测试用例开始前初始化,结束后销毁(释放动态分配的内存)。 下面编写完整代码: </think>以下是用C++实现结构,根据输序列完成/出栈操作并按指定格式输的代码: ```cpp #include <iostream> #define MAXSIZE 100 #define OK 0 #define ERROR -1 #define OVERFLOW -2 using namespace std; typedef struct { int* base; // 底指针 int* top; // 顶指针 int stacksize; // 容量 } SqStack; // 初始化 int InitStack(SqStack &s) { s.base = new int[MAXSIZE]; if (!s.base) return OVERFLOW; s.top = s.base; s.stacksize = MAXSIZE; return OK; } // 操作 int Push(SqStack &s, int e) { if (s.top - s.base >= s.stacksize) return OVERFLOW; *s.top++ = e; return OK; } // 出栈操作 int Pop(SqStack &s) { if (s.top == s.base) return ERROR; s.top--; return OK; } // 获取顶元素 int GetTop(SqStack s) { if (s.top == s.base) return ERROR; return *(s.top - 1); } int main() { int n; SqStack s; InitStack(s); // 初始化 while (cin >> n && n != 0) { if (n > 0) { // 正整数 Push(s, n); // cout << "Push(" << n << ")" << endl; // 调试用 } else if (n == -1) { // -1执行出栈 if (s.top == s.base) { cout << "POP ERROR" << endl; } else { int top = GetTop(s); Pop(s); cout << top << endl; // cout << "Pop()->" << top << endl; // 调试用 } } } delete[] s.base; // 释放内存 return 0; } ``` ### 代码说明: 1. **结构**:使用顺序存储结构实现,包含: - `base`(底指针) - `top`(顶指针) - `stacksize`(容量) 2. **核心操作**: - `InitStack`:初始化,分配内存空间 - `Push`:元素顶指针上移 - `Pop`:元素出栈顶指针下移 - `GetTop`:获取顶元素(不删除) 3. **输/输规则**: - 输整数:执行操作 - 输`-1`:执行出栈操作 - 空时出栈:输`"POP ERROR"` - 非空时出栈:输出栈顶元素值 - 输`0`:结束程序 4. **操作示例**: ```plaintext 输序列: 1 2 -1 3 -1 -1 0 输结果: 2 // 弹2 3 // 弹3 POP ERROR // 空无法弹 ``` ### 的基本特性: 1. **后进先(LIFO)**:最后的元素最先出栈 2. **操作限制**:仅能在顶进行插)和删除(出栈)操作 3. **时间复杂度**:$O(1)$,出栈$O(1)$,获取顶$O(1)$ ### 应用场景: 1. 函数调用(存储返回地址和局部变量) 2. 表达式求值(中缀转后缀表达式) 3. 撤销操作(如编辑器中的Ctrl+Z) 4. 括号匹配验证 5. 深度优先搜索(DFS) [^1]: 的压/弹序列验证问题 [^2]: 操作的指令还原算法 [^3]: 的后进先(LIFO)特性 [^4]: 的基本操作实现参考 [^5]: 序列的合法性判断
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值