C++ 有没有办法做一个循环堆栈?
下午好 我正试着做一些圆形的堆叠。它应该像一个正常的后进先出堆栈,但没有明显的限制。与其达到最大容量,还不如消除或跳过当时引入的第一个元素 例如:C++ 有没有办法做一个循环堆栈?,c++,stack,circular-buffer,lifo,C++,Stack,Circular Buffer,Lifo,下午好 我正试着做一些圆形的堆叠。它应该像一个正常的后进先出堆栈,但没有明显的限制。与其达到最大容量,还不如消除或跳过当时引入的第一个元素 例如: #include <cstddef> #include <memory> #include <iostream> template <typename T> class ForgetfulStack { std::unique_ptr<T[]> buffer; std::s
#include <cstddef>
#include <memory>
#include <iostream>
template <typename T>
class ForgetfulStack
{
std::unique_ptr<T[]> buffer;
std::size_t head = 0;
std::size_t size = 0;
public:
ForgetfulStack(std::size_t size)
: buffer(std::make_unique<T[]>(size)), size(size)
{
}
void push(const T& value)
{
buffer[head] = value;
head = (head + 1) % size;
}
T pop()
{
head = (head - 1 + size) % size;
return buffer[head];
}
};
int main()
{
ForgetfulStack<int> blub(3);
blub.push(1);
blub.push(2);
blub.push(3);
blub.push(4);
blub.push(5);
std::cout << blub.pop() << ' ' << blub.pop() << ' ' << blub.pop() << std::endl;
}
假设我们有一个包含3个元素的堆栈:stack[3]
我们通过将3个元素推入其中来填充它:push[a]、push[b]、push[c]
但是我们需要添加第四个和第五个元素:push[d],push[e]
标准堆栈将表示堆栈已达到其极限,无法添加更多元素
但我想要一个循环堆栈,它将消除或跳过a和b,记住c、d和e,并输出e、d和c
该项目是在PlatformIO上进行的,它是一个ESP32,所以我不能访问C++ STL,即使我有,我认为编译这样一个大的库只需要1个栈是毫无意义的。
即使曾经有一段时间我认为我应该编译一个类似的库,让我可以访问stack或deque,但这段时间已经过去了,因为现在我觉得自己像一个不会解决数学问题的白痴。这已经困扰我一个多星期了
我在网上找到的只是以下FIFO循环缓冲区:
class circular_buffer {
public:
explicit circular_buffer(size_t size) :
buf_(std::unique_ptr<T[]>(new T[size])),
max_size_(size)
{
}
void put(T item)
{
std::lock_guard<std::mutex> lock(mutex_);
buf_[head_] = item;
if(full_) {
tail_ = (tail_ + 1) % max_size_;
}
head_ = (head_ + 1) % max_size_;
full_ = head_ == tail_;
}
T get()
{
std::lock_guard<std::mutex> lock(mutex_);
if(empty())
{
return T();
}
//Read data and advance the tail (we now have a free space)
auto val = buf_[tail_];
full_ = false;
tail_ = (tail_ + 1) % max_size_;
return val;
}
void reset()
{
std::lock_guard<std::mutex> lock(mutex_);
head_ = tail_;
full_ = false;
}
bool empty() const
{
//if head and tail are equal, we are empty
return (!full_ && (head_ == tail_));
}
bool full() const
{
//If tail is ahead the head by 1, we are full
return full_;
}
size_t capacity() const
{
return max_size_;
}
size_t size() const
{
size_t size = max_size_;
if(!full_)
{
if(head_ >= tail_)
{
size = head_ - tail_;
}
else
{
size = max_size_ + head_ - tail_;
}
}
return size;
}
private:
std::mutex mutex_;
std::unique_ptr<T[]> buf_;
size_t head_ = 0;
size_t tail_ = 0;
const size_t max_size_;
bool full_ = 0;
};
在过去的三天里,我一直在修补它,但我就是不能让它按照我想要的方式工作。
它是FIFO结构,将打印a、b、c或c、d、e
在这种情况下,我希望它从上到下,从头到尾打印,但我无法理解 如果我理解正确,那么您所要寻找的就是一个具有固定大小的缓冲区,该缓冲区有一个指向堆栈顶部的指针,该指针递增/递减,以使其环绕缓冲区的末尾。这将自动导致最新条目总是覆盖最旧条目,有效地为最后N个值提供后进先出存储,其中N是缓冲区大小。例如:
#include <cstddef>
#include <memory>
#include <iostream>
template <typename T>
class ForgetfulStack
{
std::unique_ptr<T[]> buffer;
std::size_t head = 0;
std::size_t size = 0;
public:
ForgetfulStack(std::size_t size)
: buffer(std::make_unique<T[]>(size)), size(size)
{
}
void push(const T& value)
{
buffer[head] = value;
head = (head + 1) % size;
}
T pop()
{
head = (head - 1 + size) % size;
return buffer[head];
}
};
int main()
{
ForgetfulStack<int> blub(3);
blub.push(1);
blub.push(2);
blub.push(3);
blub.push(4);
blub.push(5);
std::cout << blub.pop() << ' ' << blub.pop() << ' ' << blub.pop() << std::endl;
}
请注意,这个简单的实现不是线程安全的…如果我理解正确,那么您所要寻找的就是一个具有固定大小的缓冲区,它有一个指向堆栈顶部的指针,该指针是递增/递减的,因此它环绕缓冲区的末尾。这将自动导致最新条目总是覆盖最旧条目,有效地为最后N个值提供后进先出存储,其中N是缓冲区大小。例如:
#include <cstddef>
#include <memory>
#include <iostream>
template <typename T>
class ForgetfulStack
{
std::unique_ptr<T[]> buffer;
std::size_t head = 0;
std::size_t size = 0;
public:
ForgetfulStack(std::size_t size)
: buffer(std::make_unique<T[]>(size)), size(size)
{
}
void push(const T& value)
{
buffer[head] = value;
head = (head + 1) % size;
}
T pop()
{
head = (head - 1 + size) % size;
return buffer[head];
}
};
int main()
{
ForgetfulStack<int> blub(3);
blub.push(1);
blub.push(2);
blub.push(3);
blub.push(4);
blub.push(5);
std::cout << blub.pop() << ' ' << blub.pop() << ' ' << blub.pop() << std::endl;
}
请注意,这个简单的实现不是线程安全的…从技术上讲,循环堆栈不再是堆栈,而是循环缓冲区或环形缓冲区。从技术上讲,循环堆栈不再是堆栈,而是循环缓冲区或环形缓冲区。我觉得如果head==0,head-1+大小将下溢,并且应该重写为head+size-1。@无用,std::size\u t是无符号的,因此不会下溢。至少根据我对无符号整数算术的理解,这里执行加法和减法的顺序应该无关紧要!?当然,我可能错了……它确实是无符号的,并且会下溢——但这实际上是对无符号整数类型的完美定义。你仍然会得到正确的结果0u-1+size==UINT\u MAX+size==size-1,只是看到潜在的下溢让我觉得有点痒。@没用啊,我想我们只是误解了这里的术语。我假设你的意思是下溢,即有符号整数超出范围,导致未定义的行为。如果你只是说它将在0处环绕,那么当然,它会这样做。但正如你所说,结果最终还是正确的。将其更改为head+size-1只需将0处的潜在环绕换成最大值处的潜在环绕…可以说,后者是,当然,这种情况不会经常发生……如果堆栈为空或应该为空时我不断弹出值,您的示例将返回以前存储在堆栈中的随机值。如果head==0,我觉得head-1+size将下溢,并且应该重写为head+size-1。@无用,std::size\t未签名,因此不会下溢。至少根据我对无符号整数算术的理解,这里执行加法和减法的顺序应该无关紧要!?当然,我可能错了……它确实是无符号的,并且会下溢——但这实际上是对无符号整数类型的完美定义。你仍然会得到正确的结果0u-1+size==UINT\u MAX+size==size-1,只是看到潜在的下溢让我觉得有点痒。@没用啊,我想我们只是误解了这里的术语。我假设你的意思是下溢,即有符号整数超出范围,导致未定义的行为。如果你只是说它将在0处环绕,那么当然,它会这样做。但正如你所说,结果最终还是正确的。将其更改为head+size-1只需交换潜在的包裹ar
如果我在堆栈为空或应该为空时不断弹出值,则返回以前存储在堆栈中的随机值。