题目描述:
定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。
要求函数min,push,pop的时间复杂度都是O(1).
解法1:另外设计一个最小栈做辅助结构,记录栈中的最小元素。元素栈中保存要入栈的元素。最小栈保存当前的最小元素。那么:
1.入栈时,先入元素栈,同时与最小栈顶元素比较,如果比栈顶元素小,则最小元素入最小栈,否则,栈顶元素入最小栈。
2.出栈时,栈一和栈二同时出栈。
则相应的算法如下。
注意的是:本算法中并没有对minStack做进一步的封装。因而这里的都是使用两个栈进行操作。如要符合题目的要求,应该在外层做进一步的封装。将minStack和元素栈作为最终栈的元素。类似
struct{
SelemType *top;
SelemType *base;
elemStack s;
minStack min;
int stackSize;
}
这种结构。
算法的优点是思路清晰。缺点是需要一个辅助栈。
#include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <assert.h> //栈的初始最大容量 #define STACK_MAX_SIZE 100 //栈的容量增量 #define INCREAMENT 10 //状态函数 #define ERROR 0 #define OK 1 #define SOVERFLOW -1 #define YES 1 #define NO 0 typedef int Status,SElemType,ElemType; typedef struct{ SElemType *base; SElemType *top; int stackSize;//当前已经分配的空间,不是指栈中元素个数。 }sqStack; Status InitStack(sqStack &S){ //初始化栈空间,栈为空 S.base = (SElemType *)malloc(STACK_MAX_SIZE * sizeof(ElemType)); if(!S.base){ exit(SOVERFLOW); } S.top = S.base; S.stackSize = STACK_MAX_SIZE; return OK; } //如果栈不空,用e传出栈顶元素并返回OK。否则返回错误。 Status GetTop(sqStack S,SElemType &e){ if(S.top == S.base){ return ERROR; } e = *(S.top - 1); return OK; } /* * Push(S,e)向栈S中压入元素e。需要考虑的情况有: * 1.栈已经满,需要增加空间。如果无法继续增加空间,则退出。 * 2.栈未满。先压入元素,然后修改栈顶指针。 **/ Status Push(sqStack &S,SElemType e){ if((S.top - S.base) >= S.stackSize){ S.base = (ElemType*)realloc(S.base,(S.stackSize + INCREAMENT) * sizeof(ElemType)); if(!S.base){ exit(SOVERFLOW); } S.top = S.base + S.stackSize; S.stackSize += INCREAMENT; } //先压入元素,然后修改指针。弹出时相反 *S.top = e; S.top ++; return OK; } /* * 弹出栈顶元素。需要注意的有: * 1.栈不空。则先修改指针,然后弹出元素并传送给e。 * 2.栈为空时,返回错误。 */ Status Pop(sqStack &S,ElemType &e){ if(S.top == S.base){ return ERROR; } //先修改指针,然后弹出元素。 S.top --; e = *S.top; return OK; } Status isEmpty(sqStack S){ if(S.top == S.base){ return YES; } return NO; } //以下几个函数是对入栈,出栈的封装。实际应用中,需要进一步对栈封装。这里没有封装。 //struct{ // elemStack s; // minStack min; //} void PushIn(sqStack &S,sqStack &min,ElemType e){ ElemType tmp; Push(S,e); if(isEmpty(min)){ Push(min,e); }else{ GetTop(min,tmp); if(tmp >= e){ Push(min,e); }else{ Push(min,tmp); } } } Status PopOut(sqStack &S,sqStack &min,ElemType &e){ if(!isEmpty(S) && !isEmpty(min)){ Pop(min,e); Pop(S,e); return OK; }else{ return ERROR; } } Status GetMin(sqStack S,sqStack min,ElemType &result){ if(!isEmpty(S) && !isEmpty(min)){ GetTop(min,result); return OK; }else{ return ERROR; } } main(){ sqStack S,min; InitStack(S); InitStack(min); int rands,rest; printf("入栈:"); for(int i = 0;i < 100;i++){ rands = rand()%1000; PushIn(S,min,rands); GetMin(S,min,rest); printf("%d -- min:%d \n",rands,rest); } printf("\n出栈:"); while(!isEmpty(S)){ PopOut(S,min,rest); printf("%d ",rest); } system("pause"); return 0; }
解法2:如果不设计另外一个辅助栈,那么可以修改栈的元素类型,增加一个min字段用于记录当前已经入栈的元素中的最小元素。
typedef int SelemType;
typedef int Status;
typedef struct{
minElement *base;
minElement *top;
int stackSize;//当前已经分配的空间,不是指栈中元素个数。
}minStack;
typedef struct{
SelemType data;
SelemType min;
}minElement;
操作的时候与一般的栈操作类似,不同的是push的时候需要同时push两个栈,且minStack中始终是当前最小元素在栈顶。
次思路的代码如下:
//代码功能,包含min函数的栈的实现。 #include <stdio.h> #include <stdlib.h> #include <malloc.h> //栈的初始最大容量 #define STACK_MAX_SIZE 100 //栈的容量增量 #define INCREAMENT 10 //状态函数 #define ERROR 0 #define OK 1 #define SOVERFLOW -1 #define YES 1 #define NO 0 typedef int Status,ElemType; typedef struct{ ElemType data; ElemType min; }minElement; typedef struct{ minElement *base; minElement *top; int stackSize;//当前已经分配的空间,不是指栈中元素个数。 }minStack; //typedef minElement SelemType; Status InitStack(minStack &S){ //初始化栈空间,栈为空 S.base = (minElement *)malloc(STACK_MAX_SIZE * sizeof(minElement)); if(!S.base){ exit(SOVERFLOW); } S.top = S.base; S.stackSize = STACK_MAX_SIZE; return OK; } Status GetTop(minStack S,minElement &e){ if(S.top == S.base){ return ERROR; } e = *(S.top - 1); return OK; } Status isEmpty(minStack S){ if(S.top == S.base){ return YES; } return NO; } Status Push(minStack &S,ElemType e){ if((S.top - S.base) >= S.stackSize){ S.base = (minElement*)realloc(S.base,(S.stackSize + INCREAMENT) * sizeof(minElement)); if(!S.base){ exit(SOVERFLOW); } S.top = S.base + S.stackSize; S.stackSize += INCREAMENT; } //先压入元素,然后修改指针。弹出时相反.top指针始终在顶元素的下一个位置 。与pop时候的 操作刚好相反。 //TODO minElement tmp,node; node.data = e; if(isEmpty(S)){ node.min = e; }else{ GetTop(S,tmp); node.min = tmp.min > e?e:tmp.min; } *(S.top) = node; S.top++; return OK; } Status Pop(minStack &S,minElement &e){ if(S.top == S.base){ return ERROR; } //先修改指针,然后弹出元素。top指针始终在顶元素的下一个位置 S.top --; e = *S.top; return OK; } Status getMin(minStack S,ElemType &e){ minElement tmp; if(!isEmpty(S)){ GetTop(S,tmp); e = tmp.min; return OK; }else{ return ERROR; } } main(){ minStack S; InitStack(S); int rands,min; printf("入栈:"); for(int i = 0;i < 100;i++){ rands = rand()%1000; Push(S,rands); getMin(S,min); printf("%d -- min:%d \n",rands,min); } printf("\n出栈:"); minElement minE; while(!isEmpty(S)){ Pop(S,minE); printf("%d --- %d \n",minE.data,minE.min); } system("pause"); return 0; }