如何在阵列中实现K堆栈,具有最佳存储空间(堆栈应该是动态的)?
答案 0 :(得分:0)
答案1: 在开始时存储K堆栈指针。现在将第一个地址标记为地址0(使生活更简单) 一个偶数K堆栈(stack_0,stack_2,......)应该向上增长;奇数K堆栈(stack_1,..)应该向下增长 初始化时将数组分段为K / 2个部分(假设K为简单起见)。 stack0从地址0开始 stack1从(arraySize /(k / 2))开始并向下增长 stack3从(arraySize /(k / 2))开始并向上增长
当将数据推入某个堆栈时,我们应该确保它没有溢出到相邻堆栈,否则抛出异常。
数组应该如下所示: [[stack pointers] [stack_0] [stack_1] ... [stack_k]]其中stack [0]和stack [1]都共享相同的区域,这样他们就可以充分利用它们可用的空间。
可以通过将每个大堆栈与一个小堆栈配对来完成进一步的优化(这可以通过检查堆栈随时间的行为来完成)。此外,将快速变化的阵列与缓慢变化的阵列组合在一起可能有所帮助
答案2: 在这方面考虑更多,我看到我的第一个解决方案只保证使用array_size /(k / 2)(因为如果我们只有一个大小为array_size /(k / 2)的数组,我们将得到堆栈溢出)。 以下(完全不切实际)的解决方案可以满足要求: 我们为k堆栈指针分配数组的开头,并从现在开始忽略该区域。 在数组的其余部分,我们将每个单元格视为struct [data,previous,next]。
push(stack_i,data) - >从堆栈指针区域获取sp_i。然后转到该地址,填入“next”指针指向数组中的下一个空单元格(我们可以将所有空白空间链接在另一个堆栈中,这样就是o(1))。在“下一个”单元格中存储我们的数据,并填写“prev”指针。更新sp_i
pop(stack_i) - >得到sp_i。从该单元格中获取“数据”。来自该单元格的“prev”是我们的新sp_i。将旧的(现在为空)单元格推送到空列表。
答案 1 :(得分:0)
好吧,如果您只担心空间使用情况,并且不关心堆栈操作可以采用O(N)
,那么您可以使用数组的前几个单元来管理堆栈:
Array[0]
- 堆栈0的结尾
Array[1]
- 堆栈1的结尾
...
Array[K-1]
=堆栈结束K
堆栈n
从Array[n-1]
开始,到Array[n]
(exclusive - [Array[n-1], Array[n]) )
结束。堆栈空If Array[n-1]==Array[n]
。第一个堆栈从K开始,因此首先是Array[0]..Array[K-1] = K
当你进入一个堆栈时,只需移动它下面的堆栈中的所有元素,并分别调整指针。
它将为您提供所需的内存限制。
答案 2 :(得分:0)
哦,哦,如果K也是动态的,你只需要让K元素数组动态化。使其变大只是意味着压下所有堆栈。所以如果你不介意O(N)推和弹操作,K不应该是常数。
我想知道我是否得到了这份工作。
答案 3 :(得分:0)
我将使用包含所有空闲插槽的队列,并在添加或弹出数据时更新该队列。这样,空间复杂度为N
,其中pop
是数组的大小。 add
和O(1)
操作是C++
。
例如:您有一个大小为S和K的堆栈数组。您有一个队列,其中包含从0到S-1的所有空闲插槽。您添加的第一个值将在第一个空闲插槽(索引0)中。然后,从队列中弹出索引0。向哪个堆栈添加或弹出数据都没有关系。如果弹出一个值,则会排队从中删除节点的插槽的索引,并相应地设置指针或索引。
这是// TYPE: type of the stacks, SIZE: size of the array, STACKS: number of stacks
template <typename TYPE, size_t SIZE, size_t STACKS>
class KStacksInOneArray
{
// A node holds the data and a pointer or index to the next value
private:
struct Node
{
TYPE data;
int next = -1; // -1 is equivalent to nullptr:
// there is no next element
};
public:
KStacksInOneArray()
{
// initialize the free slots from 0 to SIZE - 1
for (size_t idx = 0; idx < SIZE; ++idx)
_freeSlots.push(idx);
// initialize the heads, all to -1
std::fill(_heads.begin(), _heads.end(), -1);
}
void pop(size_t stack)
{
// don't trust the user
if (stack >= STACKS) throw std::out_of_range("there are only " + std::to_string(STACKS) + " stacks");
if (isEmpty(stack)) throw std::out_of_range("cannot pop from an empty stack");
// before destroying the node, get the new head
auto newHead = _arr[_heads[stack]].next;
_arr[_heads[stack]] = Node{};
// push the free slot on the queue and adjust the head
_freeSlots.push(_heads[stack]);
_heads[stack] = newHead;
}
const TYPE& top(size_t stack) const
{
if (stack >= STACKS) throw std::out_of_range("there are only 3 stacks");
return _arr[_heads[stack]];
}
void add(size_t stack, TYPE data)
{
if (stack >= STACKS) throw std::out_of_range("there are only " + std::to_string(STACKS) + " stacks");
if (_freeSlots.empty()) throw std::bad_alloc();
// set the new node in the first free slot and
_arr[_freeSlots.front()] = {std::move(data), _heads[stack] != -1 ? _heads[stack] : -1};
// update the head and remove the free slot from the queue
_heads[stack] = _freeSlots.front();
_freeSlots.pop();
}
bool isEmpty(size_t stack) const
{
if (stack >= STACKS) throw std::out_of_range("there are only " + std::to_string(STACKS) + " stacks");
if (_heads[stack] == -1) return true;
return false;
}
private:
std::vector<Node> _arr = std::vector<Node>(SIZE);
std::array<int, STACKS> _heads;
std::queue<int> _freeSlots;
};
中的实现。我已经使用索引指向下一个节点(毕竟,我们正在使用数组),但是您可以使用指针或迭代器,没关系。
{{1}}