如何实现可以获取最小值的栈? 这个问题是很久之前在微信公众号上看见的一个问题,突然想起来就来操作一下。 开发环境 : sublime+MinGW 先附上我自己实现的栈的结构
typedef struct StackNode { int data; struct StackNode *next; }StackNode,*LinkStackPtr; typedef struct LinkStack { LinkStackPtr top; int count; }LinkStack; LinkStack *init(){ LinkStack *stack=(LinkStack*)malloc(sizeof(LinkStack)); if (stack==NULL) { printf("动态开辟空间失败" ); }else stack->top=NULL; stack->count=0 ; return stack; } LinkStackPtr creatNode () { LinkStackPtr stack; stack =(LinkStackPtr)malloc(sizeof(StackNode)); if (stack==NULL){ printf("动态开辟空间失败" ); } scanf("%d" ,&(stack->data)); stack->next=NULL; return stack; } void push (LinkStack * s) { LinkStackPtr newStack= creatNode(); LinkStackPtr currentTopStack=s->top; s->top=newStack; newStack->next=currentTopStack; s->count++; } void pop (LinkStack *s) { LinkStackPtr topStack=s->top; s->top=topStack->next; s->count--; free(topStack); }
Solution 1 :在进栈的时候用一个变量保存当前的最小值每次进栈就会和最小值比较如果比最小值要小就会更新这个变量的值,出栈的时候比较麻烦,如果最小值被弹出去了就需要遍历整个栈来获取最小值。
typedef struct StackNode { int data; struct StackNode *next; }StackNode,*LinkStackPtr; typedef struct LinkStack { LinkStackPtr top; int count; int min; }LinkStack; void push (LinkStack * s) { LinkStackPtr newStack= creatNode(); if (s->count==0 ){ s->min=newStack->data; }else if (s->min>newStack->data){ s->min=newStack->data; } LinkStackPtr currentTopStack=s->top; s->top=newStack; newStack->next=currentTopStack; s->count++; } void pop (LinkStack *s) { LinkStackPtr topStack=s->top; LinkStackPtr stackNode=topStack->next; int min=topStack->data; s->top=topStack->next; s->count--; free(topStack); if (min==s->min){ min=stackNode->data; do { if (min>stackNode->data){ min=stackNode->data; } stackNode=stackNode->next; }while (stackNode!=NULL); } s->min=min; }
这种方法进栈时间复杂度为 O(1), 但是出栈时间复杂度为 O(n). 显然不是很优雅。
Solution 2 :空间换时间利用一个辅助栈,辅助栈里面存放最小值,辅助栈进栈时判断进栈的元素和当前栈顶的元素大小跟小就可以进栈。所以最小值就是辅助栈的栈顶元素,出栈时如果出栈的元素是最小值节点那辅助栈也同时弹栈 再取栈顶元素。
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct StackNode { int data; struct StackNode *next; }StackNode,*LinkStackPtr; typedef struct LinkStack { LinkStackPtr top; int count; struct LinkStack *mins; }LinkStack; LinkStack *init(){ LinkStack *stack=(LinkStack*)malloc(sizeof(LinkStack)); if (stack==NULL) { printf("动态开辟空间失败" ); }else stack->top=NULL; stack->count=0 ; return stack; } LinkStackPtr creatNode () { LinkStackPtr stack; stack =(LinkStackPtr)malloc(sizeof(StackNode)); if (stack==NULL){ printf("动态开辟空间失败" ); } scanf("%d" ,&(stack->data)); stack->next=NULL; return stack; } void push (LinkStack * s) { LinkStackPtr newStack= creatNode(); LinkStackPtr currentTopStack=s->top; LinkStackPtr minStackNode = (LinkStackPtr)malloc(sizeof(StackNode)); if (minStackNode==NULL){ printf("动态开辟空间失败" ); } minStackNode->data=newStack->data; minStackNode->next=NULL; s->top=newStack; LinkStack *mins=s->mins; LinkStackPtr currentMinsTop=mins->top; if (s->count==0 ){ mins->top=newStack; newStack->next=NULL; }else if (newStack->data<=mins->top->data){ mins->top=minStackNode; mins->top->next=currentMinsTop; mins->count++; } s->top->next=currentTopStack; s->count++; } void pop (LinkStack *s) { LinkStackPtr topStack=s->top; LinkStack * mins=s->mins; LinkStackPtr minsTopStack=mins->top; s->top=topStack->next; s->count--; if (topStack->data==mins->top->data) { mins->top=minsTopStack->next; mins->count--; free(minsTopStack); } free(topStack); } void printStack (LinkStack *stack) { LinkStackPtr stackNode=stack->top; do { printf("%d\n" ,stackNode->data); stackNode=stackNode->next; }while (stackNode!=NULL); } int main (int argc, char const *argv[]) { LinkStack *stack=init(); stack->mins=init(); push(stack); printf("*******进栈******\n" ); printStack(stack); printf("*********辅助栈*******\n" ); printStack(stack->mins); printf("*******最小值******\n" ); printf("%d\n" , stack->mins->top->data); pop(stack); printf("*******出栈******\n" ); printStack(stack); printf("*******最小值******\n" ); printf("%d\n" , stack->mins->top->data); printf("*********辅助栈*******\n" ); printStack(stack->mins); return 0 ; }
明显这个方法进栈出栈时间复杂度都是 O(1),空间复杂度相对会高一点,其实空间复杂度还可以优化,可以在辅助栈里面存索引,这样进栈时会避免存入相同的最小值,如 2 1 1 1 1 1 存到辅助栈就是 2 1 1 1 1 1 后面的 1 都是重复的,如果存索引就是 0 1 进栈时跟之前一样,出栈时判断索引是否和辅助栈存的索引一致,不一致就不动。这里因为这个是个链栈 , 要根据索引取值并不方便所以就不实现了。
这里我把代码全部贴上来了,C 语言确实学的不怎么样,所以里面会有一些奇怪的操作,这个算法本身很简单但是用 C 语言一实现就会有一堆问题,昨天进栈的时候一个指针把辅助栈和主栈搞混了一直有 bug, 今天早上上课才想起来,毕竟 C 语言写的少 hahahaha, 所以后面我打算以后会同时用 C 语言和 Java 都实现一遍。
赞赏
感谢鼓励