关闭

编程之美读书笔记-队列中取最大值操作问题

175人阅读 评论(0) 收藏 举报
分类:
题目:
假设有这样一个拥有3个操作的队列:
1. EnQueue(v):将v加入队列中
2. DeQueue():使队列中的队首元素删除并返回此元素
3. MaxElement:返回队列中的最大元素
设计一种数据结构和算法,让MaxElement操作的时间复杂度尽可能地低。
解析:设队列长度为N。利用一个数组或链表来存储队列元素,MaxElement时间复杂度为O(N);利用最大堆来存储队列元素,MaxElement时间复杂度为O(1),EnQueue和DeQueue时间复杂度为O(log2N)。按照最大堆的思路,寻找一种新的保存队列中元素相对大小关系的指针集合,并且使得更新这个指针集合的时间复杂度更低。由于栈是一个和队列及其相似的数据结构,我们不妨先看看栈。对于栈来讲,Push和Pop操作都是在栈顶完成的,所以很容易维护栈中的最大值,它的时间复杂度为O(1)。
#include<iostream>  
using namespace std; 
#define MAXN 1000

class MyStack
{
private:
	int stackTop;
	int maxStackItemIndex;
	//最大元素的位置
	int stackItem[MAXN];
	int link2NextMaxItem[MAXN];
	//link2NextMaxItem[i]表示仅小于i位置元素的元素所在位置
	//如果i位置的元素不是当前栈中最大的,这个值就为-1
public:  
	MyStack()
	{
		stackTop = -1;
		maxStackItemIndex = -1;
	}
	bool isEmpty()
	{
		return stackTop == -1;
	}
	bool isFull()
	{
		return stackTop == MAXN - 1;
	}
	void push(int x) 
	{
		if (this->isFull())
		{
			cout << "the stack is full now." << endl;
			return;
		}
		else
		{
			stackItem[++stackTop] = x; 
			if (x > Max()) 
			{
				link2NextMaxItem[stackTop] = maxStackItemIndex;
				maxStackItemIndex = stackTop;
			}
			else
				link2NextMaxItem[stackTop] = -1;
		}
	}
	int pop() 
	{
		int ret;
		if (this->isEmpty())
		{
			cout << "the stack is empty now." << endl;
			return INT_MIN;
		}
		else 
		{
			ret = stackItem[stackTop];  
			if (stackTop == maxStackItemIndex)
			{
				maxStackItemIndex = link2NextMaxItem[stackTop];
			}
			stackTop--;
		}
		return ret;
	}
	int Max() 
	{
		if (maxStackItemIndex >= 0) return stackItem[maxStackItemIndex];
		else return INT_MIN;
	}
};

int main() 
{
	MyStack mystack;
	mystack.push(3);
	mystack.push(4);
	mystack.push(8);
	mystack.push(1);
	mystack.pop();
	mystack.push(7);
	cout << mystack.Max() << endl;
	return 0;
}

如果能够用栈有效地实现队列,而栈的Max操作又很容易实现,那么队列的Max操作也就能有效地完成了。考虑用两个栈来实现一个队列,设为栈A和栈B。
#include<iostream>  
using namespace std; 
#define MAXN 1000

class MyStack
{
private:
	int stackTop;
	int maxStackItemIndex;
	//最大元素的位置
	int stackItem[MAXN];
	int link2NextMaxItem[MAXN];
	//link2NextMaxItem[i]表示仅小于i位置元素的元素所在位置
	//如果i位置的元素不是当前栈中最大的,这个值就为-1
public:  
	MyStack()
	{
		stackTop = -1;
		maxStackItemIndex = -1;
	}
	bool isEmpty()
	{
		return stackTop == -1;
	}
	bool isFull()
	{
		return stackTop == MAXN - 1;
	}
	void push(int x) 
	{
		if (this->isFull())
		{
			cout << "the stack is full now." << endl;
			return;
		}
		else
		{
			stackItem[++stackTop] = x; 
			if (x > Max()) 
			{
				link2NextMaxItem[stackTop] = maxStackItemIndex;
				maxStackItemIndex = stackTop;
			}
			else
				link2NextMaxItem[stackTop] = -1;
		}
	}
	int pop() 
	{
		int ret;
		if (this->isEmpty())
		{
			cout << "the stack is empty now." << endl;
			return INT_MIN;
		}
		else 
		{
			ret = stackItem[stackTop];  
			if (stackTop == maxStackItemIndex)
			{
				maxStackItemIndex = link2NextMaxItem[stackTop];
			}
			stackTop--;
		}
		return ret;
	}
	int Max() 
	{
		if (maxStackItemIndex >= 0) return stackItem[maxStackItemIndex];
		else return INT_MIN;
	}
};

class MyQueue
{
private:
	MyStack mystackA,mystackB;
public:
	int MaxValue(int x, int y)
	{
		if (x > y) return x;
		else return y;
	}
	int Max()
	{
		return MaxValue(mystackA.Max(), mystackB.Max());
	}
	void EnQueue(int v)
	{
		mystackB.push(v);
	}
	int DeQueue()
	{
		if (mystackA.isEmpty())
		{
			while (!mystackB.isEmpty()) mystackA.push(mystackB.pop());
		}
		return mystackA.pop();
	}
};

int main() 
{
	MyQueue myqueue;
	myqueue.EnQueue(8);
	myqueue.EnQueue(3);
	myqueue.EnQueue(4);
	myqueue.EnQueue(1);
	myqueue.DeQueue();
	myqueue.EnQueue(7);
	cout << myqueue.Max() << endl;
	return 0;
}
上述代码能够用栈来实现一个队列。出队的时候,如果A堆栈为空,那么把B堆栈的数据弹出并压入A堆栈这个操作不是O(1)的,虽然如此,但从每个元素的角度来看,它被移动的次数最多可能有3次。所以这种方法的平均时间复杂度是线性的。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:167030次
    • 积分:2457
    • 等级:
    • 排名:第15086名
    • 原创:87篇
    • 转载:111篇
    • 译文:20篇
    • 评论:29条
    博客专栏
    最新评论