Algorithm 实现一个队列,其中push_rear()、pop_front()和get_min()都是常量时间操作
我遇到了一个问题: 实现一个队列,其中push_rear()、pop_front()和get_min()都是固定时间操作。 我最初考虑使用min heap数据结构,对于get_min(),它的复杂性为O(1)。但是push_rear()和pop_front()将是O(log(n)) 有人知道实现这样一个包含O(1)push()、pop()和min()的队列的最佳方法是什么吗 我在谷歌上搜索了一下,想指出这一点。但是,对于push()、pop()和min()这三种方法,似乎没有一种解决方案遵循固定时间规则Algorithm 实现一个队列,其中push_rear()、pop_front()和get_min()都是常量时间操作,algorithm,data-structures,queue,big-o,Algorithm,Data Structures,Queue,Big O,我遇到了一个问题: 实现一个队列,其中push_rear()、pop_front()和get_min()都是固定时间操作。 我最初考虑使用min heap数据结构,对于get_min(),它的复杂性为O(1)。但是push_rear()和pop_front()将是O(log(n)) 有人知道实现这样一个包含O(1)push()、pop()和min()的队列的最佳方法是什么吗 我在谷歌上搜索了一下,想指出这一点。但是,对于push()、pop()和min()这三种方法,似乎没有一种解决方案遵循固定
谢谢您的建议。如果您不介意存储一些额外的数据,那么存储最小值应该很简单。如果新的或删除的元素是最小值,Push和pop可以更新该值,返回最小值与获取变量值一样简单 这是假设get_min()不会更改数据;如果您希望使用类似于pop_min()的内容(即删除最小元素),则只需存储一个指向实际元素及其前面的元素(如果有)的指针,并相应地使用push_rear()和pop_front()更新它们 评论后编辑:
很明显,如果这些操作的最小更改不严格满足要求,这会导致O(n)推送和弹出。如果您不介意存储一些额外的数据,存储最小值应该很简单。如果新的或删除的元素是最小值,Push和pop可以更新该值,返回最小值与获取变量值一样简单 这是假设get_min()不会更改数据;如果您希望使用类似于pop_min()的内容(即删除最小元素),则只需存储一个指向实际元素及其前面的元素(如果有)的指针,并相应地使用push_rear()和pop_front()更新它们 评论后编辑:
显然,如果这些操作的最小值发生变化,那么这会导致O(n)push和pop,因此不能严格满足要求。您可以使用O(1)pop()、push()和get_min()实现堆栈:只需将当前最小值与每个元素一起存储。因此,例如,堆栈
[4,2,5,1]
(1在顶部)变成[(4,4)、(2,2)、(5,2)、(1,1)]
那你就可以了。推到一个堆栈,从另一个堆栈弹出;如果第二个堆栈在弹出期间为空,请将所有元素从第一个堆栈移动到第二个堆栈
例如,对于一个pop
请求,移动第一个堆栈中的所有元素[(4,4)、(2,2)、(5,2)、(1,1)]
,第二个堆栈将是[(1,1)、(5,1)、(2,1)、(4,1)]
。现在从第二个堆栈返回顶部元素
要找到队列的最小元素,请查看各个最小堆栈中最小的两个元素,然后取这两个值中的最小值。(当然,在一个堆栈为空的情况下,这里有一些额外的逻辑,但这并不难解决)
它将有O(1)
get_min()
和push()
和摊销O(1)pop()
可以使用O(1)pop()、push()和get_min()实现堆栈:只需将当前最小值与每个元素一起存储。因此,例如,堆栈[4,2,5,1]
(1在顶部)变成[(4,4)、(2,2)、(5,2)、(1,1)]
那你就可以了。推到一个堆栈,从另一个堆栈弹出;如果第二个堆栈在弹出期间为空,请将所有元素从第一个堆栈移动到第二个堆栈
例如,对于一个pop
请求,移动第一个堆栈中的所有元素[(4,4)、(2,2)、(5,2)、(1,1)]
,第二个堆栈将是[(1,1)、(5,1)、(2,1)、(4,1)]
。现在从第二个堆栈返回顶部元素
要找到队列的最小元素,请查看各个最小堆栈中最小的两个元素,然后取这两个值中的最小值。(当然,在一个堆栈为空的情况下,这里有一些额外的逻辑,但这并不难解决)
它将有O(1)
get_min()
和push()
和摊销O(1)pop()
好的-我想我有一个答案,它给出了摊销O(1)中的所有操作,这意味着任何一个操作都可能占用O(n),但任何n个操作的顺序每次操作都需要O(1)时间
这样做的目的是将数据存储为数据库。这是一个二叉树,遵循min heap属性(每个节点不大于其子节点),其排序方式使节点的无序遍历以添加节点的相同顺序返回节点。例如,下面是序列2 1 4 3 5
的笛卡尔树:
1
/ \
2 3
/ \
4 5
可以使用以下步骤在O(1)摊销时间内将元素插入笛卡尔树。看看树的右脊柱(从根部到最右边的叶子的路径,由一直向右行走形成)。从最右边的节点开始,沿此路径向上扫描,直到找到比要插入的节点小的第一个节点。更改该节点,使其右子节点成为新节点,然后使该节点的前右子节点成为刚才添加的节点的左子节点。例如,假设我们想在上面的树中插入2的另一个副本。我们沿着右侧脊柱走,经过5和3,但在1下方停下来,因为1<2。然后,我们将树更改为如下所示:
1
/ \
2 2
/
3
/ \
4 5
请注意,按顺序遍历会得到2 1 4 3 5 2,这是我们添加值的顺序
这在摊销O(1)中运行,因为我们可以创建一个势函数,该函数等于树右侧脊椎中的节点数。插入节点所需的实时时间为1加上sp中的节点数
class MyQueue//Our data structure
{
deque D;//We need 2 deque objects
deque Min;
push(element)//pushing element to MyQueue
{
D.push_back(element);
while(Min.is_not_empty() and Min.back()>element)
Min.pop_back();
Min.push_back(element);
}
pop()//poping MyQueue
{
if(Min.front()==D.front() )
Min.pop_front();
D.pop_front();
}
min()
{
return Min.front();
}
}
D [12]
Min[12]
D[12,5]
Min[5] //5>12 so 12 removed
D[12,5,10]
Min[5,10]
D[12,5,10,7]
Min[5,7]
D[12,5,10,7,11]
Min[5,7,11]
D[12,5,10,7,11,19]
Min[5,7,11,19]
D[5,10,7,11,19]
Min[5,7,11,19]
D[10,7,11,19]
Min[7,11,19]
Queue q, minq1, minq2;
isMinq1Current=true;
void push(int a)
{
q.push(a);
if(isMinq1Current)
{
if(minq1.empty) minq1.push(a);
else
{
while(!minq1.empty && minq1.top < =a) minq2.push(minq1.pop());
minq2.push(a);
while(!minq1.empty) minq1.pop();
isMinq1Current=false;
}
}
else
{
//mirror if(isMinq1Current) branch.
}
}
int pop()
{
int a = q.pop();
if(isMinq1Current)
{
if(a==minq1.top) minq1.pop();
}
else
{
//mirror if(isMinq1Current) branch.
}
return a;
}
class LinkedListElement
{
LinkedListElement next;
int currentMin;
}
from collections import deque
class MinQueue(deque):
def __init__(self):
deque.__init__(self)
self.minq = deque()
def push_rear(self, x):
self.append(x)
while len(self.minq) > 0 and self.minq[-1] > x:
self.minq.pop()
self.minq.append(x)
def pop_front(self):
x = self.popleft()
if self.minq[0] == x:
self.minq.popleft()
return(x)
def get_min(self):
return(self.minq[0])
#include <iostream>
#include <queue>
#include <deque>
using namespace std;
queue<int> main_queue;
deque<int> min_queue;
void clearQueue(deque<int> &q)
{
while(q.empty() == false) q.pop_front();
}
void PushRear(int elem)
{
main_queue.push(elem);
if(min_queue.empty() == false && elem < min_queue.front())
{
clearQueue(min_queue);
}
while(min_queue.empty() == false && elem < min_queue.back())
{
min_queue.pop_back();
}
min_queue.push_back(elem);
}
void PopFront()
{
int elem = main_queue.front();
main_queue.pop();
if (elem == min_queue.front())
{
min_queue.pop_front();
}
}
int GetMin()
{
return min_queue.front();
}
int main()
{
PushRear(1);
PushRear(-1);
PushRear(2);
cout<<GetMin()<<endl;
PopFront();
PopFront();
cout<<GetMin()<<endl;
return 0;
}
import numbers
class EmptyQueueException(Exception):
pass
class BaseQ():
def __init__(self):
self.l = list()
def enqueue(self, x):
assert isinstance(x, numbers.Number)
self.l.append(x)
def dequeue(self):
return self.l.pop(0)
def peek_first(self):
return self.l[0]
def peek_last(self):
return self.l[len(self.l)-1]
def empty(self):
return self.l==None or len(self.l)==0
def clear(self):
self.l=[]
class MainQ(BaseQ):
def __init__(self, min_q):
super().__init__()
self.min_q = min_q
def enqueue(self, x):
super().enqueue(x)
if self.min_q.empty():
self.min_q.enqueue(x)
elif x > self.min_q.peek_last():
self.min_q.enqueue(x)
else: # x <= self.min_q.peek_last():
self.min_q.clear()
self.min_q.enqueue(x)
def dequeue(self):
if self.empty():
raise EmptyQueueException("Queue is empty")
x = super().dequeue()
if x == self.min_q.peek_first():
self.min_q.dequeue()
return x
def get_min(self):
if self.empty():
raise EmptyQueueException("Queue is empty, NO minimum")
return self.min_q.peek_first()
INPUT_NUMS = (("+", 5), ("+", 10), ("+", 3), ("+", 6), ("+", 1), ("+", 2), ("+", 4), ("+", -4), ("+", 100), ("+", -40),
("-",None), ("-",None), ("-",None), ("+",-400), ("+",90), ("-",None),
("-",None), ("-",None), ("-",None), ("-",None), ("-",None), ("-",None), ("-",None), ("-",None))
if __name__ == '__main__':
min_q = BaseQ()
main_q = MainQ(min_q)
try:
for operator, i in INPUT_NUMS:
if operator=="+":
main_q.enqueue(i)
print("Added {} ; Min is: {}".format(i,main_q.get_min()))
print("main_q = {}".format(main_q.l))
print("min_q = {}".format(main_q.min_q.l))
print("==========")
else:
x = main_q.dequeue()
print("Removed {} ; Min is: {}".format(x,main_q.get_min()))
print("main_q = {}".format(main_q.l))
print("min_q = {}".format(main_q.min_q.l))
print("==========")
except Exception as e:
print("exception: {}".format(e))
"C:\Program Files\Python35\python.exe" C:/dev/python/py3_pocs/proj1/priority_queue.py
Added 5 ; Min is: 5
main_q = [5]
min_q = [5]
==========
Added 10 ; Min is: 5
main_q = [5, 10]
min_q = [5, 10]
==========
Added 3 ; Min is: 3
main_q = [5, 10, 3]
min_q = [3]
==========
Added 6 ; Min is: 3
main_q = [5, 10, 3, 6]
min_q = [3, 6]
==========
Added 1 ; Min is: 1
main_q = [5, 10, 3, 6, 1]
min_q = [1]
==========
Added 2 ; Min is: 1
main_q = [5, 10, 3, 6, 1, 2]
min_q = [1, 2]
==========
Added 4 ; Min is: 1
main_q = [5, 10, 3, 6, 1, 2, 4]
min_q = [1, 2, 4]
==========
Added -4 ; Min is: -4
main_q = [5, 10, 3, 6, 1, 2, 4, -4]
min_q = [-4]
==========
Added 100 ; Min is: -4
main_q = [5, 10, 3, 6, 1, 2, 4, -4, 100]
min_q = [-4, 100]
==========
Added -40 ; Min is: -40
main_q = [5, 10, 3, 6, 1, 2, 4, -4, 100, -40]
min_q = [-40]
==========
Removed 5 ; Min is: -40
main_q = [10, 3, 6, 1, 2, 4, -4, 100, -40]
min_q = [-40]
==========
Removed 10 ; Min is: -40
main_q = [3, 6, 1, 2, 4, -4, 100, -40]
min_q = [-40]
==========
Removed 3 ; Min is: -40
main_q = [6, 1, 2, 4, -4, 100, -40]
min_q = [-40]
==========
Added -400 ; Min is: -400
main_q = [6, 1, 2, 4, -4, 100, -40, -400]
min_q = [-400]
==========
Added 90 ; Min is: -400
main_q = [6, 1, 2, 4, -4, 100, -40, -400, 90]
min_q = [-400, 90]
==========
Removed 6 ; Min is: -400
main_q = [1, 2, 4, -4, 100, -40, -400, 90]
min_q = [-400, 90]
==========
Removed 1 ; Min is: -400
main_q = [2, 4, -4, 100, -40, -400, 90]
min_q = [-400, 90]
==========
Removed 2 ; Min is: -400
main_q = [4, -4, 100, -40, -400, 90]
min_q = [-400, 90]
==========
Removed 4 ; Min is: -400
main_q = [-4, 100, -40, -400, 90]
min_q = [-400, 90]
==========
Removed -4 ; Min is: -400
main_q = [100, -40, -400, 90]
min_q = [-400, 90]
==========
Removed 100 ; Min is: -400
main_q = [-40, -400, 90]
min_q = [-400, 90]
==========
Removed -40 ; Min is: -400
main_q = [-400, 90]
min_q = [-400, 90]
==========
Removed -400 ; Min is: 90
main_q = [90]
min_q = [90]
==========
exception: Queue is empty, NO minimum
Process finished with exit code 0
import java.io.*;
import java.util.*;
public class queueMin {
static class stack {
private Node<Integer> head;
public void push(int data) {
Node<Integer> newNode = new Node<Integer>(data);
if(null == head) {
head = newNode;
} else {
Node<Integer> prev = head;
head = newNode;
head.setNext(prev);
}
}
public int pop() {
int data = -1;
if(null == head){
System.out.println("Error Nothing to pop");
} else {
data = head.getData();
head = head.getNext();
}
return data;
}
public int peek(){
if(null == head){
System.out.println("Error Nothing to pop");
return -1;
} else {
return head.getData();
}
}
public boolean isEmpty(){
return null == head;
}
}
static class stackMin extends stack {
private stack s2;
public stackMin(){
s2 = new stack();
}
public void push(int data){
if(data <= getMin()){
s2.push(data);
}
super.push(data);
}
public int pop(){
int value = super.pop();
if(value == getMin()) {
s2.pop();
}
return value;
}
public int getMin(){
if(s2.isEmpty()) {
return Integer.MAX_VALUE;
}
return s2.peek();
}
}
static class Queue {
private stackMin s1, s2;
public Queue(){
s1 = new stackMin();
s2 = new stackMin();
}
public void enQueue(int data) {
s1.push(data);
}
public int deQueue() {
if(s2.isEmpty()) {
while(!s1.isEmpty()) {
s2.push(s1.pop());
}
}
return s2.pop();
}
public int getMin(){
return Math.min(s1.isEmpty() ? Integer.MAX_VALUE : s1.getMin(), s2.isEmpty() ? Integer.MAX_VALUE : s2.getMin());
}
}
static class Node<T> {
private T data;
private T min;
private Node<T> next;
public Node(T data){
this.data = data;
this.next = null;
}
public void setNext(Node<T> next){
this.next = next;
}
public T getData(){
return this.data;
}
public Node<T> getNext(){
return this.next;
}
public void setMin(T min){
this.min = min;
}
public T getMin(){
return this.min;
}
}
public static void main(String args[]){
try {
FastScanner in = newInput();
PrintWriter out = newOutput();
// System.out.println(out);
Queue q = new Queue();
int t = in.nextInt();
while(t-- > 0) {
String[] inp = in.nextLine().split(" ");
switch (inp[0]) {
case "+":
q.enQueue(Integer.parseInt(inp[1]));
break;
case "-":
q.deQueue();
break;
case "?":
out.println(q.getMin());
default:
break;
}
}
out.flush();
out.close();
} catch(IOException e){
e.printStackTrace();
}
}
static class FastScanner {
static BufferedReader br;
static StringTokenizer st;
FastScanner(File f) {
try {
br = new BufferedReader(new FileReader(f));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public FastScanner(InputStream f) {
br = new BufferedReader(new InputStreamReader(f));
}
String next() {
while (st == null || !st.hasMoreTokens()) {
try {
st = new StringTokenizer(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
String nextLine(){
String str = "";
try {
str = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong() {
return Long.parseLong(next());
}
double nextDoulbe() {
return Double.parseDouble(next());
}
}
static FastScanner newInput() throws IOException {
if (System.getProperty("JUDGE") != null) {
return new FastScanner(new File("input.txt"));
} else {
return new FastScanner(System.in);
}
}
static PrintWriter newOutput() throws IOException {
if (System.getProperty("JUDGE") != null) {
return new PrintWriter("output.txt");
} else {
return new PrintWriter(System.out);
}
}
}
const m = new MaxQueue();
m.enqueue(6);
/*
the dqStack now looks like:
[6, 6] - [value, max]
*/
m.enqueue(7);
m.enqueue(8);
/*
dqStack: eqStack: 8
[6, 6] 7 - just the value
*/
/*
dqStack: eqStack: 8
[6, 8] 7
*/
m.dequeue();
> 6
// equivalent to:
/*
const tuple = m.dqStack.pop() // [6, 8]
tuple[0];
> 6
*/
// if we build a MaxQueue
const maxQ = new MaxQueue(3, 5, 2, 4, 1);
/*
the stacks will look like:
dqStack: eqStack: 1
4
2
[3, 5] 5
*/
maxQ.dequeue(); // pops from dqStack (now empty), so move all from eqStack to dqStack
> 3
// as dequeue moves one value over, it checks if it's greater than the ***previous max*** and stores the max at tuple[1], i.e., [data, max]:
/*
dqStack: [5, 5] => 5 > 4 - update eqStack:
[2, 4] => 2 < 4 - no update
[4, 4] => 4 > 1 - update
[1, 1] => 1st value moved over so max is itself empty
*/
maxQ.getMax();
> 5
// equivalent to calling peek on the dqStack and pulling out the maximum value:
/*
const peekedTuple = maxQ.dqStack.peek(); // [5, 5]
peekedTuple[1];
> 5
*/