队列中取最大值操作

假设有这样一个拥有3个操作的队列:

    1.EnQueue(v):将v加入队列
    2.DeQueue:使队列中的队首元素删除并返回元素
    3.MaxElement:返回队列中的最大元素
请设计一种数据结构和算法,让MaxElement操作的时间复杂度尽可能低
 
研究这个问题之前,先研究两个子问题:
    1、设计一个包含min操作的栈
    2、用栈实现队列
 
一、设计一个包含min操作的栈
    考虑给栈增加一个成员变量MinValue,有元素入栈的时候,将入栈元素与MinValue相比,如果小于MinValue,用入栈元素的值,更新MinValue,但是效率低的地方在于,如果出栈元素等于MinValue,则需要重新查找整个栈,找出MinValue。
    解决这个问题的方法是采用一个辅助栈,将一个元素入栈的时候,在辅助栈中相同的位置记录它入栈之前栈中最小元素的位置。出栈的时候,若出栈元素等于MinValue,则查找这个辅助栈对应项的元素,直接按位置取出最小值。
如图:
    

队列中取最大值操作


最左边的数字代表元素在栈中的位置。当3入栈时,它就是最小元素,因此在辅助栈中与它位置相同的地方,保存它之前的最大位置(-1或0皆可),4入栈的时候,考虑到3和help[0]相等,因此4对应的辅助栈元素是0,2入栈时,考虑到4大于stack[help[1]],因此2对应的辅助栈元素仍然是0,1入栈时,由于2比stack[help[2]]小,因此1对应的辅助栈元素是2的位置,即2.依次类推。

源代码:
template<typename T> class MinStack {

private:

    T *stack;

    T *min;

    size_t top;

    T MinValue;

    size_t MaxElement;

public:

    MinStack();

    ~MinStack();

    void push(T t);

    void pop();

    T GetTop();

    T GetMin();

};

template<typename T> MinStack<T>::MinStack()

{

    MaxElement = 20;

    stack = new T[MaxElement];

    min = new T[MaxElement];

    top = -1;

}

 

template<typename T> MinStack<T>::~MinStack()

{

    delete[] stack;

    delete[] min;

}

 

template<typename T> void MinStack<T>::push(T t)

{

    if(top == MaxElement)

    {

        cout<<"It's full";

        return;

    }

    if(top == -1)

    {

        stack[++top] = t;

        min[top] = 0;

        MinValue = t;

    }

    else

    {

        stack[++top] = t;

        min[top] = stack[top-1]>stack[min[top-1]]?min[top-1]:top-1;

        MinValue = t>stack[min[top]]?stack[min[top]]:t;

    }

}

 

template<typename T> void MinStack<T>::pop()

{

    if(top==-1)

    {

        cout<<"It's empty";

        return;

    }

    if(top == 0)

    {

        --top;

    }

    else

    {

        --top;

        MinValue = stack[min[top+1]];

    }

}

 

template<typename T> T MinStack<T>::GetTop()

{

    if(top==-1)

    {

        cout<<"It's empty stack";

        exit(0);

    }

    return stack[top];

}

 

template<typename T> T MinStack<T>::GetMin()

{

    if(top==-1)

    {

        cout<<"It's empty stack";

        exit(0);

    }

    return MinValue;

}
二、用两个栈实现队列
这个问题的关键是,设置一个栈用来入队,另一个栈用来出队。一开始出栈队为空,当有出队动作的时候,就将入队栈全部出栈,进栈到出队栈,这样顺序就正好反过来了,下一次出队就直接从出队栈取元素,入队则继续入入队栈。总结一下就是:
    入队一直是在入队栈入栈。
    出队的时候,如果出队栈为空,就把入队栈全部出栈入栈到出队栈,再取栈顶元素,移动栈顶指针,如果出队栈不空,直接取元素,移指针。
源代码:
template<typename T> class Stack 

{

public:

    T *s;

    size_t top;

    size_t Max;

    Stack();

    ~Stack();

    void push(T t);

    void pop();

    T GetTop();

};

 

template<typename T> class Queue 

{

private:

    Stack<T> En;

    Stack<T> De;

public:    

    void EnQueue(T t);

    T DeQueue();

};

template<typename T> Stack<T>::Stack()

{

    Max = 20;

    s = new T[Max];

    top = -1;

}

 

template<typename T> Stack<T>::~Stack()

{

    delete[] s;

}

 

template<typename T> void Stack<T>::push(T t)

{

    if(top==Max)

    {

        cout<<"It's full stack";

        return;

    }

    s[++top] = t;

}

 

template<typename T> void Stack<T>::pop()

{

    if(top == -1)

    {

        cout<<"It's empty stack";

        return;

    }

    --top;

}

 

template<typename T> T Stack<T>::GetTop()

{

    return s[top];

}

 

template<typename T> void Queue<T>::EnQueue(T t)

{

    En.push(t);

}

 

template<typename T> T Queue<T>::DeQueue()

{

    if(De.top==-1)

    {

        while(En.top+1>0)

        {

            De.push(En.GetTop());

            En.pop();

        }

    }

    if(De.top==-1)

    {

        cout<<"It's empty queue";

    }

    T temp = De.GetTop();

    De.pop();

    return temp;

}
解决了这两个子问题之后,队列中取最大值操作便迎刃而解。
修改Queue的定义,用MinStack代替Stack,并加入一个MinValue()函数。
template<typename T> class Queue 

{

private:

    MinStack<T> En;

    MinStack<T> De;

public:

    void EnQueue(T t);

    T DeQueue();

    T MinValue();

};

 

template<typename T> T Queue<T>::MinValue()

{

    if(De.top==-1&&En.top==-1)

    {

        cout<<"It's a empty queue";

        exit(0);

    }

    else if(De.top == -1)

    {

        return En.MinValue;

    }

    else if(En.top == -1)

    {

        return De.MinValue;

    }

    else

    {

        return En.MinValue<De.MinValue?En.MinValue:De.MinValue;

    }

}
如果不用模板,直接用int或者float,则可以将MinStack中的MinValue值初始化为INT_MAX,并且如果队空就将MinValue置为INT_MIN,这样可以省略En空,De不空或者En不空De空的讨论。
 
 
//问题:设计一个队列能够在O(1)时间内取得队列的最大值



#include <stdio.h>

#include <queue>

#include <stack>



//O(1)的速度取出栈中的最大值

template<typename T>

class MaxStack 

{

public:

	//入栈

	void Push(const T& value) 

	{

		data_.push(value);

		if (max_element_.empty()) 

		{

			max_element_.push(value);

		} 

		else if (value >= max_element_.top())

		{

			max_element_.push(value);

		}

    }

	//返回栈顶元素

    T Top() 

    {

	    return data_.top();

    }

	//出栈

    void Pop() 

    {

		if (data_.top() == max_element_.top()) 

	    {

			max_element_.pop();

        }

        data_.pop();    

     }

	//判断是否为空

     bool Empty() 

	 {

		 return data_.empty();

     }

	 //取出最大值

     T Max() 

	 {

		 if (!max_element_.empty()) 

		 { 

			 return max_element_.top();

         }

     }

private:

	std::stack<T> data_;

    std::stack<T> max_element_;

};



//O(1)的速度取出队列中的最大值

template<typename T>

class MaxQueue 

{

public:

	

	//入队操作!!!!

	void Push(const T& value)

	{

		push_stack_.Push(value);

    }



	//取队首元素

	T Front()

	{

		if (pop_stack_.empty()) 

		{

			while (!push_stack_.Empty()) 

			{

				pop_stack_.Push(push_stack_.Top());

				push_stack_.Pop();

			}

		}

		return pop_stack_.Top();

	}



	//出队操作!!!!

	void Pop() 

	{

		if (pop_stack_.Empty()) 

		{

			while (!push_stack_.Empty()) 

			{

				pop_stack_.Push(push_stack_.Top());

				push_stack_.Pop();

			}

		}

		pop_stack_.Pop();

	}



	//判空操作!!!!!

	bool IsEmpty() 

	{

		return push_stack_.Empty() && pop_stack_.Empty();

	}



	//取出最大值

	T Max() 

	{

		if (!push_stack_.Empty() && !pop_stack_.Empty()) 

		{

			return push_stack_.Max() > pop_stack_.Max() ? push_stack_.Max() : pop_stack_.Max();

		} 

		else if (push_stack_.Empty() && !pop_stack_.Empty()) 

		{

			return pop_stack_.Max();

		} 

		else if (!push_stack_.Empty() && pop_stack_.Empty()) 

		{

			return push_stack_.Max();

		} 

		else	

		{

		      throw RUNTIME_ERROR;

		}

	}

private:

	MaxStack<T> push_stack_;

	MaxStack<T> pop_stack_;

};

//测试用例

int main(int argc, char** argv) 

{

	MaxQueue<int> max_queue;

	max_queue.Push(1);

	max_queue.Push(2);

	max_queue.Push(6);

	max_queue.Push(4);

	max_queue.Push(5);

	max_queue.Push(2);

	printf("max %d\n", max_queue.Max());

	max_queue.Pop();

	printf("max %d\n", max_queue.Max());

	max_queue.Pop();

	printf("max %d\n", max_queue.Max());

	max_queue.Pop();

	printf("max %d\n", max_queue.Max());

	max_queue.Pop();

	printf("max %d\n", max_queue.Max());

	max_queue.Pop();

	printf("max %d\n", max_queue.Max());

}

  

你可能感兴趣的:(队列)