You can indeed use a Queue<bool>
like already suggested. But it might cause a performance issue in some cases. After the 5 first insertions, every insertion will cost a Dequeue
and an Enqueue
.
Efficiency depends on the implementation of .NET which I am not an expert in, but it could be sub-optimal. Assuming the Queue is at its capacity - Dequeue
can just increment the head index, but then Enqueue
will require a reallocation.
If Dequeue
is not just incrementing the index it might require to copy the whole Queue.
Since Queue
is not limited to a predefined window size, its implementation might be inferior relative to a specific cyclic queue implementation.
Therefore - if efficiency is critical, you can try to use a fixed size array, and manage a cyclic queue on top of it.
BTW - If the number if elements is even (e.g. before we got 5 entries) and we have the same number of true and false, it is not clear what the most common value should be. I arbitrarily chose false.
The implementation:
public class CyclicQueueBool
{
public CyclicQueueBool(int maxSize)
{
int internalSize = maxSize + 1;
m_Queue_ = new bool[internalSize];
m_Head_ = 0;
m_Tail_ = 0;
}
// Get the actual number of elements in the queue (smaller than MaxSize() in case it is not full)
public int NumberOfActualElements()
{
if (m_Head_ >= m_Tail_)
return (int)m_Head_ - (int)m_Tail_;
int maxSize = m_Queue_.Length - 1;
return (int)(maxSize - m_Tail_ + m_Head_ + 1);
}
// Check if the queue is empty or full:
public bool IsEmpty() { return (m_Head_ == m_Tail_); }
public bool IsFull() { return (_Next(m_Head_) == m_Tail_); }
// Push a new element to the queue. If the queue is full the oldest element is discarded to keep the size.
public void Push(bool elem)
{
if (IsFull())
{
m_Tail_ = _Next(m_Tail_);
}
m_Queue_[(int)(m_Head_)] = elem;
m_Head_ = _Next(m_Head_);
}
// Access element by index:
// NOTE: Q[0] is Tail() (i.e. the oldest)
// Q[NumElements-1] is Head() (i.e. the newest)
public bool this[int index]
{
get { return m_Queue_[(int)((index + m_Tail_) % m_Queue_.Length)]; }
set { m_Queue_[(int)((index + m_Tail_) % m_Queue_.Length)] = value; }
}
// Get common value:
public bool GetCommonValue()
{
int numTrue = 0;
int numFalse = 0;
int numElems = this.NumberOfActualElements();
for (int i = 0; i < numElems; ++i)
{
if (this[i])
{
numTrue++;
}
else
{
numFalse++;
}
}
return (numTrue > numFalse);
}
protected int _Next(int i) { return (i + 1) % m_Queue_.Length; }
protected int _Prev(int i) { return (i + m_Queue_.Length - 1) % m_Queue_.Length; }
protected bool[] m_Queue_;
protected int m_Head_;
protected int m_Tail_;
}
class Program
{
static void Main(string[] args)
{
CyclicQueueBool q = new CyclicQueueBool(5);
q.Push(false);
q.Push(true);
q.Push(false);
q.Push(false);
q.Push(true);
Console.WriteLine("GetCommonValue: " + q.GetCommonValue());
}
}
UPDATE: based on @Ben Voigt's comment I replaced List<bool>
in the implementation with bool[]
.