代码是参考的康建伟老师的: https://www.cnblogs.com/kangjianwei101/p/5221816.html,以及用copilot做了一些改进
下面主要记录一些问题(核心代码附在最后)
-
对有一些边界条件有疑惑,整理了一下
函数名 if
条件判断条件含义 InitStack if (S == NULL)
检查栈指针是否为空,避免对空指针进行操作 InitStack if ((*S).base == NULL)
检查分配内存是否成功,若不成功则退出程序 DestroyStack if (S == NULL)
检查栈指针是否为空,避免对空指针进行操作 ClearStack if (S == NULL ||(*S).base == NULL)
检查栈指针是否为空,以及栈是否已经初始化 StackEmpty if (S.top == S.base)
检查栈顶指针是否与栈底指针相等,以判断栈是否为空 StackLength if (S.base == NULL)
检查栈是否已经初始化 GetTop if (S.base == NULL ||( S.top == S.base)
检查栈是否已经初始化,以及栈是否为空 Push if (S == NULL ||( (*S).base == NULL)
检查栈指针是否为空,以及栈是否已经初始化 Push if ((*S).top - (*S).base >= (*S).stacksize)
检查栈是否已满,若满则需要扩容 Pop if (S == NULL ||( (*S).base == NULL)
检查栈指针是否为空,以及栈是否已经初始化 Pop if ((*S).top == (*S).base)
检查栈是否为空,若为空则不能进行弹栈操作 StackTraverse if (S.base == NULL)
检查栈是否已经初始化,未初始化则不能遍历 -
关于遍历函数StackTraverse
StackTraverse
函数的主要目的是遍历顺序栈S
并对栈中的每个元素执行一个特定的操作。这个操作由传递给StackTraverse
的函数指针Visit
定义。Status StackTraverse(SqStack S, void(Visit)(SElemType))
Visit
参数是一个函数指针,允许将函数作为参数传递给另一个函数。这里的Visit
函数必须符合特定的格式:它需要是一个接受单个SElemType
类型参数的函数。在遍历栈时,StackTraverse
函数会对栈中的每一个元素调用Visit
函数。康建伟老师的程序中,
PrintElem
函数被用作Visit
函数,它的作用是打印一个整数元素:void PrintElem(SElemType e) { printf("%d ", e); }
这样调用
StackTraverse
函数时:StackTraverse(S, PrintElem);
-
核心代码主要就是下面这些
(严书上用的是引用,这里用的是指针,能看懂就OK)/** * 初始化 * * 构建一个空栈S。初始化成功则返回OK,否则返回ERROR。 */ Status InitStack(SqStack *S) { // 如果S为NULL,返回ERROR if (S == NULL) { return ERROR; } // 为顺序栈分配一个大小为STACK_INIT_SIZE的数组空间 (*S).base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType)); if ((*S).base == NULL) { // 存储分配失败 exit(OVERFLOW); } // 设置栈顶指针为栈底指针 (*S).top = (*S).base; // 设置栈的最大容量 (*S).stacksize = STACK_INIT_SIZE; return OK; } /* * 销毁(结构) * * 释放顺序栈所占内存。 */ Status DestroyStack(SqStack *S) { // 如果S为NULL,返回ERROR if (S == NULL) { return ERROR; } // 释放顺序栈所占内存 free((*S).base); // 栈底指针、栈顶指针置空 (*S).base = NULL; (*S).top = NULL; // 栈的最大容量置为0 (*S).stacksize = 0; return OK; } /* * 清空(内容) * * 只是清理顺序栈中存储的数据,不释放顺序栈所占内存。 */ Status ClearStack(SqStack *S) { // 如果S为NULL或者S本身就是空栈,则返回ERROR if (S == NULL || (*S).base == NULL) { return ERROR; } (*S).top = (*S).base; return OK; } /** * 判空 * * 判断顺序栈中是否包含有效数据。 */ Status StackEmpty(SqStack S) { // 如果栈顶指针和栈底指针重合,则说明栈为空 if (S.top == S.base) { return TRUE; } else { return FALSE; } } /** * 计数 * * 返回顺序栈包含的有效元素的数量。 */ int StackLength(SqStack S) { if (S.base == NULL) { return 0; } return (int)(S.top - S.base); } /** * 取值 * * 获取栈顶元素,并通过e返回。 */ Status GetTop(SqStack S, SElemType *e) { if (S.base == NULL || S.top == S.base) { return ERROR; } *e = *(S.top - 1); } /** * 压栈 * * 将元素e压入到栈顶。 */ Status Push(SqStack *S, SElemType e) { if (S == NULL || (*S).base == NULL) { return ERROR; } // 如果栈满,则追加存储空间 if ((*S).top - (*S).base >= (*S).stacksize) { // 为顺序栈追加空间 (*S).base = (SElemType *)realloc((*S).base, ((*S).stacksize + STACKINCREMENT) * sizeof(SElemType)); if ((*S).base == NULL) { // 存储分配失败 exit(OVERFLOW); } // 栈容量加上增量 (*S).top = (*S).base + (*S).stacksize; (*S).stacksize += STACKINCREMENT; } // 入栈先赋值,栈顶指针再加1 *(S->top) = e; // 也可以写成:*((*S).top)=e; S->top++; } /** * 弹栈 * * 将栈顶元素弹出,并通过e返回。 */ Status Pop(SqStack *S, SElemType *e) { if (S == NULL || (*S).base == NULL) { return ERROR; } // 如果栈为空,则返回ERROR if ((*S).top == (*S).base) { return ERROR; } // 栈顶指针减1,将栈顶元素赋值给e (*S).top--; *e = *((*S).top); return OK; } /** * 遍历 * * 用visit函数访问顺序栈S */ Status StackTraverse(SqStack S, void(Visit)(SElemType)) { if (S.base == NULL) { return ERROR; } SElemType *p = S.base; while (p < S.top) { Visit(*p++); } printf("\n"); return OK; }