如何在单个数组中有效地实现 k 个堆栈?
我们已经讨论了在单个数组中实现 2 个堆栈的空间效率。在这篇文章中,讨论了 k 个堆栈的一般解决方案。以下是详细的问题陈述。创建一个表示 k 个堆栈的数据结构 kStacks。 kStacks 的实现应该只使用一个数组,即k 个堆栈应该使用同一个数组来存储元素。 kStacks 必须支持以下功能。 push(int x, int sn) –> 将 x 推送到栈号 'sn',其中 sn 是从 0 到 k-1 pop(int sn) -> 从栈号 'sn' 中弹出一个元素,其中 sn 是从 0 到 k -1方法1(将数组划分为n/k大小的槽)实现k栈的一种简单方法是将数组划分为k个大小为n/k的槽,每个槽固定为不同的栈,即使用arr [0] 到 arr[n/k-1] 用于第一个堆栈,arr[n/k] 到 arr[2n/k-1] 用于 stack2 其中 arr[] 是用于实现两个堆栈和大小的数组数组为 n。这种方法的问题是对数组空间的使用效率低下。即使 arr[] 中有可用空间,堆栈推送操作也可能导致堆栈溢出。例如,假设 k 为 2,数组大小 (n) 为 6,我们将 3 个元素推送到第一个堆栈,并且不将任何内容推送到第二个堆栈。当我们将第 4 个元素推到第一个时,即使数组中还有 3 个元素的空间,也会出现溢出。方法 2(一种节省空间的实现)这个想法是使用两个额外的数组来有效地实现一个数组中的 k 个堆栈。这对于整数堆栈可能没有多大意义,但堆栈项目可能很大,例如员工、学生等的堆栈,其中每个项目都有数百个字节。对于如此大的堆栈,使用的额外空间相对较少,因为我们使用两个整数数组作为额外空间。以下是使用的两个额外数组: 1) top[]: 这是大小 k 并存储所有堆栈中顶部元素的索引。 2) next[]:大小为 n,存储数组 arr[] 中项的下一项的索引。这里 arr[] 是存储 k 个堆栈的实际数组。与 k 个堆栈一起,还维护了 arr[] 中的一个空闲槽堆栈。此堆栈的顶部存储在变量“free”中。 top[] 中的所有条目都初始化为 -1 以指示所有堆栈都是空的。所有条目 next[i] 都初始化为 i+1,因为所有插槽最初都是空闲的并指向下一个插槽。空闲栈顶,'free'被初始化为0。下面是上述思想的实现。
C++
// A C++ program to demonstrate implementation of k stacks in a single
// array in time and space efficient way
#include
using namespace std;
// A C++ class to represent k stacks in a single array of size n
class kStacks
{
int *arr; // Array of size n to store actual content to be stored in stacks
int *top; // Array of size k to store indexes of top elements of stacks
int *next; // Array of size n to store next entry in all stacks
// and free list
int n, k;
int free; // To store beginning index of free list
public:
//constructor to create k stacks in an array of size n
kStacks(int k, int n);
// A utility function to check if there is space available
bool isFull() { return (free == -1); }
// To push an item in stack number 'sn' where sn is from 0 to k-1
void push(int item, int sn);
// To pop an from stack number 'sn' where sn is from 0 to k-1
int pop(int sn);
// To check whether stack number 'sn' is empty or not
bool isEmpty(int sn) { return (top[sn] == -1); }
};
//constructor to create k stacks in an array of size n
kStacks::kStacks(int k1, int n1)
{
// Initialize n and k, and allocate memory for all arrays
k = k1, n = n1;
arr = new int[n];
top = new int[k];
next = new int[n];
// Initialize all stacks as empty
for (int i = 0; i < k; i++)
top[i] = -1;
// Initialize all spaces as free
free = 0;
for (int i=0; i
Java
// Java program to demonstrate implementation of k stacks in a single
// array in time and space efficient way
public class GFG
{
// A Java class to represent k stacks in a single array of size n
static class KStack
{
int arr[]; // Array of size n to store actual content to be stored in stacks
int top[]; // Array of size k to store indexes of top elements of stacks
int next[]; // Array of size n to store next entry in all stacks
// and free list
int n, k;
int free; // To store beginning index of free list
//constructor to create k stacks in an array of size n
KStack(int k1, int n1)
{
// Initialize n and k, and allocate memory for all arrays
k = k1;
n = n1;
arr = new int[n];
top = new int[k];
next = new int[n];
// Initialize all stacks as empty
for (int i = 0; i < k; i++)
top[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; // -1 is used to indicate end of free list
}
// A utility function to check if there is space available
boolean isFull()
{
return (free == -1);
}
// To push an item in stack number 'sn' where sn is from 0 to k-1
void push(int item, int sn)
{
// Overflow check
if (isFull())
{
System.out.println("Stack Overflow");
return;
}
int i = free; // Store index of first free slot
// Update index of free slot to index of next slot in free list
free = next[i];
// Update next of top and then top for stack number 'sn'
next[i] = top[sn];
top[sn] = i;
// Put the item in array
arr[i] = item;
}
// To pop an from stack number 'sn' where sn is from 0 to k-1
int pop(int sn)
{
// Underflow check
if (isEmpty(sn))
{
System.out.println("Stack Underflow");
return Integer.MAX_VALUE;
}
// Find index of top item in stack number 'sn'
int i = top[sn];
top[sn] = next[i]; // Change top to store next of previous top
// Attach the previous top to the beginning of free list
next[i] = free;
free = i;
// Return the previous top item
return arr[i];
}
// To check whether stack number 'sn' is empty or not
boolean isEmpty(int sn)
{
return (top[sn] == -1);
}
}
// Driver program
public static void main(String[] args)
{
// Let us create 3 stacks in an array of size 10
int k = 3, n = 10;
KStack ks = new KStack(k, n);
ks.push(15, 2);
ks.push(45, 2);
// Let us put some items in stack number 1
ks.push(17, 1);
ks.push(49, 1);
ks.push(39, 1);
// Let us put some items in stack number 0
ks.push(11, 0);
ks.push(9, 0);
ks.push(7, 0);
System.out.println("Popped element from stack 2 is " + ks.pop(2));
System.out.println("Popped element from stack 1 is " + ks.pop(1));
System.out.println("Popped element from stack 0 is " + ks.pop(0));
}
}
// This code is Contributed by Sumit Ghosh
Python3
# Python 3 program to demonstrate implementation
# of k stacks in a single array in time and space
# efficient way
class KStacks:
def __init__(self, k, n):
self.k = k # Number of stacks.
self.n = n # Total size of array holding
# all the 'k' stacks.
# Array which holds 'k' stacks.
self.arr = [0] * self.n
# All stacks are empty to begin with
# (-1 denotes stack is empty).
self.top = [-1] * self.k
# Top of the free stack.
self.free = 0
# Points to the next element in either
# 1. One of the 'k' stacks or,
# 2. The 'free' stack.
self.next = [i + 1 for i in range(self.n)]
self.next[self.n - 1] = -1
# Check whether given stack is empty.
def isEmpty(self, sn):
return self.top[sn] == -1
# Check whether there is space left for
# pushing new elements or not.
def isFull(self):
return self.free == -1
# Push 'item' onto given stack number 'sn'.
def push(self, item, sn):
if self.isFull():
print("Stack Overflow")
return
# Get the first free position
# to insert at.
insert_at = self.free
# Adjust the free position.
self.free = self.next[self.free]
# Insert the item at the free
# position we obtained above.
self.arr[insert_at] = item
# Adjust next to point to the old
# top of stack element.
self.next[insert_at] = self.top[sn]
# Set the new top of the stack.
self.top[sn] = insert_at
# Pop item from given stack number 'sn'.
def pop(self, sn):
if self.isEmpty(sn):
return None
# Get the item at the top of the stack.
top_of_stack = self.top[sn]
# Set new top of stack.
self.top[sn] = self.next[self.top[sn]]
# Push the old top_of_stack to
# the 'free' stack.
self.next[top_of_stack] = self.free
self.free = top_of_stack
return self.arr[top_of_stack]
def printstack(self, sn):
top_index = self.top[sn]
while (top_index != -1):
print(self.arr[top_index])
top_index = self.next[top_index]
# Driver Code
if __name__ == "__main__":
# Create 3 stacks using an
# array of size 10.
kstacks = KStacks(3, 10)
# Push some items onto stack number 2.
kstacks.push(15, 2)
kstacks.push(45, 2)
# Push some items onto stack number 1.
kstacks.push(17, 1)
kstacks.push(49, 1)
kstacks.push(39, 1)
# Push some items onto stack number 0.
kstacks.push(11, 0)
kstacks.push(9, 0)
kstacks.push(7, 0)
print("Popped element from stack 2 is " +
str(kstacks.pop(2)))
print("Popped element from stack 1 is " +
str(kstacks.pop(1)))
print("Popped element from stack 0 is " +
str(kstacks.pop(0)))
kstacks.printstack(0)
# This code is contributed by Varun Patil
C#
using System;
// C# program to demonstrate implementation of k stacks in a single
// array in time and space efficient way
public class GFG
{
// A c# class to represent k stacks in a single array of size n
public class KStack
{
public int[] arr; // Array of size n to store actual content to be stored in stacks
public int[] top; // Array of size k to store indexes of top elements of stacks
public int[] next; // Array of size n to store next entry in all stacks
// and free list
public int n, k;
public int free; // To store beginning index of free list
//constructor to create k stacks in an array of size n
public KStack(int k1, int n1)
{
// Initialize n and k, and allocate memory for all arrays
k = k1;
n = n1;
arr = new int[n];
top = new int[k];
next = new int[n];
// Initialize all stacks as empty
for (int i = 0; i < k; i++)
{
top[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; // -1 is used to indicate end of free list
}
// A utility function to check if there is space available
public virtual bool Full
{
get
{
return (free == -1);
}
}
// To push an item in stack number 'sn' where sn is from 0 to k-1
public virtual void push(int item, int sn)
{
// Overflow check
if (Full)
{
Console.WriteLine("Stack Overflow");
return;
}
int i = free; // Store index of first free slot
// Update index of free slot to index of next slot in free list
free = next[i];
// Update next of top and then top for stack number 'sn'
next[i] = top[sn];
top[sn] = i;
// Put the item in array
arr[i] = item;
}
// To pop an from stack number 'sn' where sn is from 0 to k-1
public virtual int pop(int sn)
{
// Underflow check
if (isEmpty(sn))
{
Console.WriteLine("Stack Underflow");
return int.MaxValue;
}
// Find index of top item in stack number 'sn'
int i = top[sn];
top[sn] = next[i]; // Change top to store next of previous top
// Attach the previous top to the beginning of free list
next[i] = free;
free = i;
// Return the previous top item
return arr[i];
}
// To check whether stack number 'sn' is empty or not
public virtual bool isEmpty(int sn)
{
return (top[sn] == -1);
}
}
// Driver program
public static void Main(string[] args)
{
// Let us create 3 stacks in an array of size 10
int k = 3, n = 10;
KStack ks = new KStack(k, n);
ks.push(15, 2);
ks.push(45, 2);
// Let us put some items in stack number 1
ks.push(17, 1);
ks.push(49, 1);
ks.push(39, 1);
// Let us put some items in stack number 0
ks.push(11, 0);
ks.push(9, 0);
ks.push(7, 0);
Console.WriteLine("Popped element from stack 2 is " + ks.pop(2));
Console.WriteLine("Popped element from stack 1 is " + ks.pop(1));
Console.WriteLine("Popped element from stack 0 is " + ks.pop(0));
}
}
// This code is contributed by Shrikant13
Javascript
输出:
Popped element from stack 2 is 45
Popped element from stack 1 is 39
Popped element from stack 0 is 7
push() 和 pop() 操作的时间复杂度为 O(1)。上述实现的最佳部分是,如果堆栈中有可用的插槽,则可以将项目推入任何堆栈,即不会浪费空间。