一 题目:设计栈的数据结构,操作有入栈push,出栈pop,求栈中最小元素min,要求这三个操作的时间复杂度都是O(1)
二 求解思路:此题关键是设计min操作,使得时间复杂度是O(1),为此在设计好的堆栈数据结构中引入辅助栈,为节省空间开销,辅助栈中存放“最小元素”地址序列
比如:有一组数据4,3,10,2,8那么
当4入栈时
4 0
栈 辅助栈
当3入栈时
3 1
4 0
栈 辅助栈
当10入栈时
10
3 1
4 0
栈 辅助栈
当2入栈时
2
10 3
3 1
4 0
栈 辅助栈
当8入栈时
8
2
10 3
3 1
4 0
栈 辅助栈
当8出栈时
2
10 3
3 1
4 0
栈 辅助栈
当2出栈时
10
3 1
4 0
栈 辅助栈
当10出栈时
3 1
4 0
栈 辅助栈
当3出栈时
4 0
栈 辅助栈
当4出栈时
栈 辅助栈
也就是说当某个元素入栈时,比较它是不是小于辅助栈栈顶元素(指针)指向的元素, 如果小于,那么将这个元素的地址压入辅助栈
当弹出元素时,比较这个元素的地址是不是和辅助栈栈顶元素相同,如果相同,那么将辅助栈栈顶元素弹出
三 代码
/*
This is a free Program, You can modify or redistribute it under the terms of GNU
*Description:以空间换时间,谷歌一道关于堆栈操作的面试题
*Language: C++
*Development Environment: VC6.0
*Author: Wangzhicheng
*E-mail: 2363702560@qq.com
*Date: 2012/11/14
*/
/*
*某个元素入栈时,比较它是不是小于辅助栈栈顶元素(指针)指向的元素,
*如果小于,那么将这个元素的地址压入辅助栈
*当弹出元素时,比较这个元素的地址是不是和辅助栈栈顶元素相同,如果相同,那么将辅助栈栈顶元素弹出
*/
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <stack>
#include <ctime>
using namespace std;
/*
*向前引用
*/
template<class Type>
class LinkedStack;
/*
*链表结点类
*/
template<class Type>
class LinkNode {
private:
Type data;
LinkNode<Type> *next;
public:
friend class LinkedStack<Type>;
LinkNode<Type>() {
data=NULL;
next=0;
}
LinkNode<Type>(const Type &e,LinkNode<Type> *link=0) {
data=e;
next=link;
}
LinkNode<Type>(const LinkNode<Type> &Node) {
data=Node.getData();
next=Node.getNext();
}
LinkNode<Type> & operator=(const LinkNode<Type> &Node) {
data=Node.getData();
next=Node.getNext();
return *this;
}
bool operator<(const LinkNode<Type> &Node) {
return data<Node.getData();
}
const Type& getData() {
return data;
}
void setData(const Type &e) {
data=e;
}
LinkNode<Type> * getNext() const {
return next;
}
void setNext(LinkNode<Type> *p) {
next=p;
}
};
/*
*链栈类
*@top:栈顶指针
*@assistant:辅助栈,辅助栈中存放着链栈中"最小元素"地址序列
*/
template<class Type>
class LinkedStack {
private:
LinkNode<Type>*top;
stack<LinkNode<Type>*>assistant;
public:
LinkedStack() { //构造函数
top=new LinkNode<Type>;
}
~LinkedStack() { //析构函数,将栈清空
while(!empty()) {
pop();
}
delete top;
top=0;
}
void push(const Type &e) { //入栈函数
LinkNode<Type> *p=new LinkNode<Type>(e);
if(!p) {
cerr<<"内存分配失败,程序退出!"<<endl;
exit(1);
}
p->next=top->next;
top->next=p;
/*
*此时入栈之前栈为空,将链栈当前元素的指针压入辅助栈
*/
if(top->next->next==0) {
assistant.push(top->next);
}
/*
*此时链栈至少有两个元素
*比较当前的链栈顶元素和辅助栈的栈顶元素指向的值
*如果当前栈顶元素小于辅助栈的栈顶元素指向的值,将将链栈当前元素的指针压入辅助栈
*/
else {
if(peek()<assistant.top()->getData()) {
assistant.push(top->next);
}
}
}
const Type & peek() const { //返回栈顶元素
if(empty()==true) {
return NULL;
}
return top->next->data;
}
bool empty() const { //判断栈是否为空
return top->next==0;
}
void pop() { //出栈函数
LinkNode<Type> *pre=top->next; //获取栈顶元素的指针s
if(empty()==true) {
cerr<<"堆栈已空!"<<endl;
return;
}
LinkNode<Type>*p=top->next;
top->next=p->next;
delete p;
/*
*如果被弹出的元素是辅助栈栈顶元素指向的值
*那么将辅助栈栈顶元素弹出
*/
if(assistant.empty()==false && pre==assistant.top()) {
assistant.pop();
}
}
bool min(Type &value) {
if(assistant.empty()==false) {
value=assistant.top()->getData();
return true;
}
else {
cerr<<"栈已空!"<<endl;
return false;
}
}
void show() {
LinkNode<Type> *p=top->next;
int i=0;
while(p) {
cout<<p->getData()<<setw(4)<<" ";
i++;
if(i%10==0) cout<<endl;
p=p->next;
}
cout<<endl;
}
};
void main() {
LinkedStack<int>stack;
srand(unsigned(time(0)));
int i;
int e;
int N=30;
for(i=1;i<=N;i++) { //随机生成N个整数压入栈
e=(rand()%N)+2;
stack.push(e);
}
int min;
cout<<"原始栈中元素是:"<<endl;
stack.show();
cout<<"最小元素是:";
if(stack.min(min)) cout<<min<<endl;
cout<<"---------------------------------"<<endl;
for(i=1;i<=N/2;i++) { //弹出一半元素
stack.pop();
}
cout<<"弹出一半后,栈中元素是:"<<endl;
stack.show();
cout<<"---------------------------------"<<endl;
cout<<"最小元素是:";
if(stack.min(min)) cout<<min<<endl;
}
四 测试
屏幕输出: