如何在单个数组中有效地实现 k 个队列?
我们已经讨论了数组中 k 堆栈的有效实现。在这篇文章中,同样讨论了队列。以下是详细的问题说明。
创建一个表示 k 个队列的数据结构 kQueues。 kQueues 的实现应该只使用一个数组,即 k 个队列应该使用相同的数组来存储元素。 kQueues 必须支持以下功能。
enqueue(int x, int qn) –> 将 x 添加到队列号 'qn' 中,其中 qn 是从 0 到 k-1
dequeue(int qn) –> 从队列号 'qn' 中删除一个元素,其中 qn 是从 0 到 k-1
方法 1(将数组划分为大小为 n/k 的插槽)
实现k个队列的一个简单方法是将数组分成k个大小为n/k的槽,固定不同队列的槽,即第一个队列使用arr[0]到arr[n/k-1] , arr[n/k] 到 arr[2n/k-1] 用于 queue2,其中 arr[] 是用于实现两个队列的数组,数组大小为 n。
这种方法的问题是数组空间的使用效率低下。即使 arr[] 中有可用空间,入队操作也可能导致溢出。例如,考虑 k 为 2,数组大小 n 为 6。让我们将 3 个元素排入第一个队列,而不将任何元素排入第二个队列。当我们将第 4 个元素排入第一个队列时,即使数组中还有 3 个元素的空间,也会发生溢出。
方法 2(空间高效的实现)
思路类似于stack post,这里我们需要使用三个额外的数组。在 stack post 中,我们需要两个额外的数组,因为在队列中,enqueue() 和 dequeue() 操作是在不同的端完成的,所以还需要一个数组。
以下是使用的三个额外数组:
1) front[] :它的大小为 k 并存储所有队列中前元素的索引。
2)后[] :这是大小k并存储所有队列中后元素的索引。
2) next[] :它的大小为 n 并存储数组 arr[] 中所有项目的下一个项目的索引。
这里 arr[] 是实际存储 k 个堆栈的数组。
与 k 个队列一起,还维护了 arr[] 中的空闲槽栈。此堆栈的顶部存储在变量“free”中。
front[] 中的所有条目都初始化为 -1 以指示所有队列都为空。所有条目 next[i] 都初始化为 i+1,因为所有插槽最初都是空闲的并指向下一个插槽。空闲堆栈的顶部,'free' 被初始化为 0。
以下是上述想法的 C++ 实现。
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。
C++
// A C++ program to demonstrate implementation of k queues in a single
// array in time and space efficient way
#include
#include
using namespace std;
// A C++ class to represent k queues in a single array of size n
class kQueues
{
// Array of size n to store actual content to be stored in queue
int *arr;
// Array of size k to store indexes of front elements of the queue
int *front;
// Array of size k to store indexes of rear elements of queue
int *rear;
// Array of size n to store next entry in all queues
int *next;
int n, k;
int free; // To store the beginning index of the free list
public:
//constructor to create k queue in an array of size n
kQueues(int k, int n);
// A utility function to check if there is space available
bool isFull() { return (free == -1); }
// To enqueue an item in queue number 'qn' where qn is from 0 to k-1
void enqueue(int item, int qn);
// To dequeue an from queue number 'qn' where qn is from 0 to k-1
int dequeue(int qn);
// To check whether queue number 'qn' is empty or not
bool isEmpty(int qn) { return (front[qn] == -1); }
};
// Constructor to create k queues in an array of size n
kQueues::kQueues(int k1, int n1)
{
// Initialize n and k, and allocate memory for all arrays
k = k1, n = n1;
arr = new int[n];
front = new int[k];
rear = new int[k];
next = new int[n];
// Initialize all queues as empty
for (int i = 0; i < k; i++)
front[i] = -1;
// Initialize all spaces as free
free = 0;
for (int i=0; i
Java
// A Java program to demonstrate implementation of k queues in a single
// array in time and space efficient way
public class KQueues {
int k;
int n;
int[] arr;
int[] front;
int[] rear;
int[] next;
int free;
KQueues(int k, int n){
// Initialize n and k, and allocate memory for all arrays
this.k = k;
this.n = n;
this.arr = new int[n];
this.front = new int[k];
this.rear = new int[k];
this.next = new int[n];
// Initialize all queues as empty
for(int i= 0; i< k; i++) {
front[i] = rear[i] = -1;
}
// Initialize all spaces as free
free = 0;
for(int i= 0; i< n-1; i++) {
next[i] = i+1;
}
next[n-1] = -1;
}
public static void main(String[] args)
{
// Let us create 3 queue in an array of size 10
int k = 3, n = 10;
KQueues ks= new KQueues(k, n);
// Let us put some items in queue number 2
ks.enqueue(15, 2);
ks.enqueue(45, 2);
// Let us put some items in queue number 1
ks.enqueue(17, 1);
ks.enqueue(49, 1);
ks.enqueue(39, 1);
// Let us put some items in queue number 0
ks.enqueue(11, 0);
ks.enqueue(9, 0);
ks.enqueue(7, 0);
System.out.println("Dequeued element from queue 2 is " +
ks.dequeue(2));
System.out.println("Dequeued element from queue 1 is " +
ks.dequeue(1));
System.out.println("Dequeued element from queue 0 is " +
ks.dequeue(0) );
}
// To check whether queue number 'i' is empty or not
private boolean isEmpty(int i) {
return front[i] == -1;
}
// To dequeue an from queue number 'i' where i is from 0 to k-1
private boolean isFull(int i) {
return free == -1;
}
// To enqueue an item in queue number 'j' where j is from 0 to k-1
private void enqueue(int item, int j) {
if(isFull(j)) {
System.out.println("queue overflow");
return;
}
int nextFree = next[free];
if(isEmpty(j)) {
rear[j] = front[j] = free;
}else {
// Update next of rear and then rear for queue number 'j'
next[rear[j]] = free;
rear[j] = free;
}
next[free] = -1;
// Put the item in array
arr[free] = item;
// Update index of free slot to index of next slot in free list
free = nextFree;
}
// To dequeue an from queue number 'i' where i is from 0 to k-1
private int dequeue(int i) {
// Underflow checkSAS
if(isEmpty(i)) {
System.out.println("Stack underflow");
return Integer.MIN_VALUE;
}
// Find index of front item in queue number 'i'
int frontIndex = front[i];
// Change top to store next of previous top
front[i] = next[frontIndex];
// Attach the previous front to the beginning of free list
next[frontIndex] = free;
free = frontIndex;
return arr[frontIndex];
}
}
Python
# A Python program to demonstrate implementation of k queues in a single
# array in time and space efficient way
class KQueues:
def __init__(self, number_of_queues, array_length):
self.number_of_queues = number_of_queues
self.array_length = array_length
self.array = [-1] * array_length
self.front = [-1] * number_of_queues
self.rear = [-1] * number_of_queues
self.next_array = list(range(1, array_length))
self.next_array.append(-1)
self.free = 0
# To check whether the current queue_number is empty or not
def is_empty(self, queue_number):
return True if self.front[queue_number] == -1 else False
# To check whether the current queue_number is full or not
def is_full(self, queue_number):
return True if self.free == -1 else False
# To enqueue the given item in the given queue_number where
# queue_number is from 0 to number_of_queues-1
def enqueue(self, item, queue_number):
if self.is_full(queue_number):
print("Queue FULL")
return
next_free = self.next_array[self.free]
if self.is_empty(queue_number):
self.front[queue_number] = self.rear[queue_number] = self.free
else:
self.next_array[self.rear[queue_number]] = self.free
self.rear[queue_number] = self.free
self.next_array[self.free] = -1
self.array[self.free] = item
self.free = next_free
# To dequeue an item from the given queue_number where
# queue_number is from 0 to number_of_queues-1
def dequeue(self, queue_number):
if self.is_empty(queue_number):
print("Queue EMPTY")
return
front_index = self.front[queue_number]
self.front[queue_number] = self.next_array[front_index]
self.next_array[front_index] = self.free
self.free = front_index
return self.array[front_index]
if __name__ == "__main__":
# Let us create 3 queue in an array of size 10
ks = KQueues(3, 10)
# Let us put some items in queue number 2
ks.enqueue(15, 2)
ks.enqueue(45, 2)
# Let us put some items in queue number 1
ks.enqueue(17, 1);
ks.enqueue(49, 1);
ks.enqueue(39, 1);
# Let us put some items in queue number 0
ks.enqueue(11, 0);
ks.enqueue(9, 0);
ks.enqueue(7, 0);
print("Dequeued element from queue 2 is {}".format(ks.dequeue(2)))
print("Dequeued element from queue 1 is {}".format(ks.dequeue(1)))
print("Dequeued element from queue 0 is {}".format(ks.dequeue(0)))
C#
// A C# program to demonstrate implementation of k queues in a single
// array in time and space efficient way
using System;
public class KQueues
{
int k;
int n;
int[] arr;
int[] front;
int[] rear;
int[] next;
int free;
KQueues(int k, int n)
{
// Initialize n and k, and
// allocate memory for all arrays
this.k = k;
this.n = n;
this.arr = new int[n];
this.front = new int[k];
this.rear = new int[k];
this.next = new int[n];
// Initialize all queues as empty
for(int i = 0; i < k; i++)
{
front[i] = rear[i] = -1;
}
// Initialize all spaces as free
free = 0;
for(int i = 0; i < n - 1; i++)
{
next[i] = i + 1;
}
next[n - 1] = -1;
}
public static void Main(String[] args)
{
// Let us create 3 queue in an array of size 10
int k = 3, n = 10;
KQueues ks = new KQueues(k, n);
// Let us put some items in queue number 2
ks.enqueue(15, 2);
ks.enqueue(45, 2);
// Let us put some items in queue number 1
ks.enqueue(17, 1);
ks.enqueue(49, 1);
ks.enqueue(39, 1);
// Let us put some items in queue number 0
ks.enqueue(11, 0);
ks.enqueue(9, 0);
ks.enqueue(7, 0);
Console.WriteLine("Dequeued element from queue 2 is " +
ks.dequeue(2));
Console.WriteLine("Dequeued element from queue 1 is " +
ks.dequeue(1));
Console.WriteLine("Dequeued element from queue 0 is " +
ks.dequeue(0) );
}
// To check whether queue number 'i' is empty or not
private bool isEmpty(int i)
{
return front[i] == -1;
}
// To dequeue an from queue
// number 'i' where i is from 0 to k-1
private bool isFull(int i)
{
return free == -1;
}
// To enqueue an item in queue
// number 'j' where j is from 0 to k-1
private void enqueue(int item, int j)
{
if(isFull(j))
{
Console.WriteLine("queue overflow");
return;
}
int nextFree = next[free];
if(isEmpty(j))
{
rear[j] = front[j] = free;
}
else
{
// Update next of rear and then
// rear for queue number 'j'
next[rear[j]] = free;
rear[j] = free;
}
next[free] = -1;
// Put the item in array
arr[free] = item;
// Update index of free slot to
// index of next slot in free list
free = nextFree;
}
// To dequeue an from queue
// number 'i' where i is from 0 to k-1
private int dequeue(int i)
{
// Underflow checkSAS
if(isEmpty(i))
{
Console.WriteLine("Stack underflow");
return int.MinValue;
}
// Find index of front item in queue number 'i'
int frontIndex = front[i];
// Change top to store next of previous top
front[i] = next[frontIndex];
// Attach the previous front to the beginning of free list
next[frontIndex] = free;
free = frontIndex;
return arr[frontIndex];
}
}
// This code is contributed by aashish1995
Javascript
输出:
Dequeued element from queue 2 is 15
Dequeued element from queue 1 is 17
Dequeued element from queue 0 is 11