有没有办法做一个循环堆栈?
Is there a way to do a circular stack?
下午好!
我正在尝试制作某种圆形堆栈。它应该像一个普通的后进先出堆栈,但没有明显的限制。与其达到最大容量,不如及时消除或跳过当时引入的第一个元素!
例如:
假设我们有一个包含 3 个元素的堆栈:stack[3]
我们用 "pushing" 内部的 3 个元素填充它:push[a], push[b], push[c]
.
但是接下来我们要添加第 4 个和第 5 个元素:push[d], push[e]
。
标准堆栈会说堆栈已达到极限,无法再添加任何元素。
但我想要一个循环堆栈,它会消除或跳过a
和b
,记住c
、d
和e
并输出e
、d
和 c
;
该项目是在 ESP32 上的 PlatformIO 中完成的,所以我无权访问 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;
};
过去 3 天我一直在修改它,但我就是无法让它按照我想要的方式工作。
它是一个 FIFO 结构,将打印 a
、b
、c
或 c
、d
、e
、
我希望它从上到下打印,在这种情况下从头到尾打印,但我无法弄清楚。
如果我没理解错的话,那么你要找的只是一个固定大小的缓冲区,它有一个指向 "stack" 的 "top" 的指针,即 incremented/decremented 这样它就环绕在缓冲区的末尾。这将自动导致最新的条目总是覆盖最旧的条目,有效地为您提供最后 N 个值的 LIFO 存储,其中 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;
}
请注意,这个简单的实现不是线程安全的……
下午好!
我正在尝试制作某种圆形堆栈。它应该像一个普通的后进先出堆栈,但没有明显的限制。与其达到最大容量,不如及时消除或跳过当时引入的第一个元素!
例如:
假设我们有一个包含 3 个元素的堆栈:stack[3]
我们用 "pushing" 内部的 3 个元素填充它:push[a], push[b], push[c]
.
但是接下来我们要添加第 4 个和第 5 个元素:push[d], push[e]
。
标准堆栈会说堆栈已达到极限,无法再添加任何元素。
但我想要一个循环堆栈,它会消除或跳过a
和b
,记住c
、d
和e
并输出e
、d
和 c
;
该项目是在 ESP32 上的 PlatformIO 中完成的,所以我无权访问 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;
};
过去 3 天我一直在修改它,但我就是无法让它按照我想要的方式工作。
它是一个 FIFO 结构,将打印 a
、b
、c
或 c
、d
、e
、
我希望它从上到下打印,在这种情况下从头到尾打印,但我无法弄清楚。
如果我没理解错的话,那么你要找的只是一个固定大小的缓冲区,它有一个指向 "stack" 的 "top" 的指针,即 incremented/decremented 这样它就环绕在缓冲区的末尾。这将自动导致最新的条目总是覆盖最旧的条目,有效地为您提供最后 N 个值的 LIFO 存储,其中 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;
}
请注意,这个简单的实现不是线程安全的……