📜  仅使用一种数据结构实现动态多栈(K 栈)

📅  最后修改于: 2022-05-13 01:57:09.386000             🧑  作者: Mango

仅使用一种数据结构实现动态多栈(K 栈)

在本文中,我们将看到如何创建一个可以处理多个可增长大小的堆栈数据结构。数据结构需要处理三个操作:

例子:

方法:按照下面提到的方法来实现这个想法。

  • 将每个堆栈的大小顶部索引存储在数组sizes[]topIndex[]中。
  • 大小将存储在前缀和数组中(使用前缀数组和将帮助我们在 O(1) 时间内找到堆栈的开始/大小)
  • 如果堆栈的大小达到最大保留容量,则扩大保留大小(乘以2)
  • 如果堆栈的大小下降到保留大小的四分之一,则缩小保留大小(将其除以 2)
  • 每次我们需要扩展/收缩数据结构中的堆栈时,其他堆栈的索引可能会发生变化,因此我们需要注意这一点。这是通过增加/减少 size[] 和 topIndex[] 数组的值来处理的(我们可以在 O(堆栈数)时间内做到这一点)。

下面是实现:

C++
#include 
using namespace std;
 
template 
 
// Class to implement multistack
class MultiStack {
    int numberOfStacks;
    vector values;
    vector sizes, topIndex;
 
public:
    // Constructor to create k stacks
    // (by default 1)
    MultiStack(int k = 1)
        : numberOfStacks(k)
    {
        // reserve 2 elements for each stack first
        values = vector(numberOfStacks << 1);
 
        // For each stack store the index
        // of the element on the top
        // and the size (starting point)
        sizes = vector(numberOfStacks);
        topIndex = vector(numberOfStacks);
 
        // Sizes is a prefix sum vector
        for (int size = 2, i = 0; i < numberOfStacks;
             i++, size += 2)
            sizes[i] = size, topIndex[i] = size - 2;
    }
 
    // Push a value in a stack
    void push(int stackNum, T val)
    {
 
        // Check if the stack is full,
        // if so Expand it
        if (isFull(stackNum))
            Expand(stackNum);
 
        // Add the value to the top of the stack
        // and increment the top index
        values[topIndex[stackNum]++] = val;
    }
 
    // Pop the top value and
    // return it form a stack
    T pop(int stackNum)
    {
 
        // If the stack is empty
        // throw an error
        if (empty(stackNum))
            throw("Empty Stack!");
 
        // Save the top value
        T val = values[topIndex[stackNum] - 1];
 
        // Set top value to default data type
        values[--topIndex[stackNum]] = T();
 
        // Shrink the reserved size if needed
        Shrink(stackNum);
 
        // Return the pop-ed value
        return val;
    }
 
    // Return the top value form a stack
    // Same as pop (but without removal)
    T top(int stackNum)
    {
        if (empty(stackNum))
            throw("Empty Stack!");
        return values[topIndex[stackNum] - 1];
    }
 
    // Return the size of a stack
    // (the number of elements in the stack,
    // not the reserved size)
    int size(int stackNum)
    {
        if (!stackNum)
            return topIndex[0];
        return topIndex[stackNum] - sizes[stackNum - 1];
    }
 
    // Check if a stack is empty or not
    // (has no elements)
    bool empty(int stackNum)
    {
        int offset;
        if (!stackNum)
            offset = 0;
        else
            offset = sizes[stackNum - 1];
        int index = topIndex[stackNum];
        return index == offset;
    }
 
    // Helper function to check
    // if a stack size has reached
    // the reserved size of that stack
    bool isFull(int stackNum)
    {
        int offset = sizes[stackNum];
        int index = topIndex[stackNum];
        return index >= offset;
    }
 
    // Function to expand the reserved size
    // of a stack (multiply by 2)
    void Expand(int stackNum)
    {
 
        // Get the reserved_size of the stack()
        int reserved_size = size(stackNum);
 
        // Update the prefix sums (sizes)
        // and the top index of the next stacks
        for (int i = stackNum + 1; i < numberOfStacks; i++)
            sizes[i] += reserved_size,
                topIndex[i] += reserved_size;
 
        // Update the size of the recent stack
        sizes[stackNum] += reserved_size;
 
        // Double the size of the stack by
        // inserting 'reserved_size' elements
        values.insert(values.begin() + topIndex[stackNum],
                      reserved_size, T());
    }
 
    // Function to shrink the reserved size
    // of a stack (divide by2)
    void Shrink(int stackNum)
    {
 
        // Get the reserved size and the current size
        int reserved_size, current_size;
        if (!stackNum)
            reserved_size = sizes[0],
            current_size = topIndex[0];
        else
            reserved_size
                = sizes[stackNum] - sizes[stackNum - 1],
                current_size
                = topIndex[stackNum] - sizes[stackNum - 1];
 
        // Shrink only if the size is
        // lower than a quarter of the
        // reserved size and avoid shrinking
        // if the reserved size is 2
        if (current_size * 4 > reserved_size
            || reserved_size == 2)
            return;
 
        // Divide the size by 2 and update
        // the prefix sums (sizes) and
        // the top index of the next stacks
        int dif = reserved_size / 2;
        for (int i = stackNum + 1; i < numberOfStacks; i++)
            sizes[i] -= dif, topIndex[i] -= dif;
        sizes[stackNum] -= dif;
 
        // Erase half of the reserved size
        values.erase(values.begin() + topIndex[stackNum],
                     values.begin() + topIndex[stackNum]
                         + dif);
    }
};
 
// Driver code
int main()
{
    // create 3 stacks
    MultiStack MStack(3);
 
    // push elements in stack 0:
    MStack.push(0, 21);
    MStack.push(0, 13);
    MStack.push(0, 14);
 
    // Push one element in stack 1:
    MStack.push(1, 15);
 
    // Push two elements in stack 2:
    MStack.push(2, 1);
    MStack.push(2, 2);
    MStack.push(2, 3);
 
    // Print the top elements of the stacks
    cout << MStack.top(0) << '\n';
    cout << MStack.top(1) << '\n';
    cout << MStack.top(2) << '\n';
 
    return 0;
}


输出
14
15
3

时间复杂度:

  • O(1) 用于top()函数。
  • push()pop()函数的摊销 O(1)。

辅助空间: O(N),其中 N 是堆栈数