基于最新位置总是获得最旧数组索引的算法

时间:2014-08-29 14:59:01

标签: c# arrays algorithm

这几乎是一个不可能提出的问题,但是对这个算法的任何建议都会非常感激(我会尽我所能解释);

我有一个大小为~4000字节的数组,其中包含字节格式的数据。

对于这个演示,我将简化一些事情;说它的大小为7(表示数据的“块”,而不是单个值!);

 |  0  |  1  |  2  |  3  |  4  |  5  |  6  |

我在位置0添加一个值,数组的重置为'0'

键:N =最新,O =最旧,X =已填充

 |  N  |    |    |    |    |    |    | 

我现在需要添加另一个值。这将在下一个可用位置输入。

 |  O  |  N  |    |    |    |    |    | 

所以现在position [0]现在是数组的'最旧'部分,position [1]是最新的。

这已经(目前)通过一直向前看,没有看到任何值,然后从位置[0]开始直到看到一个值来解决。

让我们添加另一个:

 |  O  |  X  |  N  |    |    |    |    | 

注意,最旧的值没有改变位置,因为它仍然是数组中最旧的部分。

我现在要'清除'数组中最老的部分(在这个例子中它当前是pos [0])。这使得'O'移动到下一个位置。

 |    |  O  |  N  |    |    |    |    | 

让我们添加另一个值。因为它将进入第一个“空”空间,它将进入位置[0];这意味着第一个位置现在位于[0]位置。

 |  N  |  O  |  X  |    |    |    |    | 

我现在要清除另一个;再一次,通过从最新值的右侧看,我看到一个值在第1位。所以我要清除它。

 |    |    |  O/N  |    |    |    |    | 

这意味着位置[2]现在既是最新的也是最旧的值。

添加另一个品牌;

 |  N  |    |  O  |    |    |    |    | 

添加另一个;

 |  X  |  N  |  O  |    |    |    |    | 

并添加另一个;

 |  X  |  X  |  O  |  N  |    |    |    | 

我希望现在删除最旧的值。因此,从“最新”变量的位置看,我看到pos [0]有一个值,所以必须是它。 UH-OH ,这不是最老的值!


正如你所能(希望)告诉我的那样,我无法通过向右看我的下一个价值获得最旧的票 - 这个问题只是经常发生,并且很难找到解决方案。

我只知道添加了最新值的索引,这很难找到解决方案。 (已经尝试了大量的涂鸦和图表,大量的纸屑)。

因此,如果有人对我如何总能找到最旧的价值指数有任何想法,我将非常感激! (我也知道这是一个非常复杂的问题,所以如果有人想要/需要澄清,我会很乐意进一步编辑/解释!)我已经标记了c#,但实际上我只需要一个BASIC算法来保证诚实!!!

=============================================== =====================================

修改

答案建议分配到“最新”位置的右侧; 像:

 |    |    |  O  |  N  |     |     |    | 
 |    |    |  O  |  X  |  N  |     |    | 
 |    |    |  O  |  X  |  X  |  N  |    | 
 |    |    |  O  |  X  |  X  |  X  |  N |
 |  N |    |  O  |  X  |  X  |  X  |  X |  
 |  X |  N |  O  |  X  |  X  |  X  |  X | 

我认为COULD可以工作,但有人知道这是否会失败(例如,我在某个时间删除了某个值/等等?)

3 个答案:

答案 0 :(得分:3)

我猜你被迫使用数组;如果没有,那么您应该考虑切换到适当的数据结构,例如 Queue

如果您确实被迫使用数组,并且只能保留指向最新块的指针,那么我建议始终在最新块的右侧添加新块,并在数组中将索引包回零大小

这使您可以通过查看最新块右侧的块来确定最旧的块是什么,直到找到非空块:这是最旧的块。将它从数组中删除并继续执行:)

让我们来说明一下:

 | N |   |   |   |   |   |   |   // newBlockIndex at 0, adding, newBlockIndex becomes 1
 | X | N |   |   |   |   |   |   // newBlockIndex at 1, adding, newBlockIndex becomes 2
 | X | X | N |   |   |   |   |   // newBlockIndex at 2, adding, newBlockIndex becomes 3
 |   | X | N |   |   |   |   |   // newBlockIndex at 3, removing, no item before index 0, we delete it
 |   | X | X | N |   |   |   |   // newBlockIndex at 3, adding, newBlockIndex becomes 4
...

编辑添加 关于你的编辑,我认为这个机制非常强大。即使您错误地删除了一个项目(任何项目,甚至是最新的项目),下一个操作也可以成功,因为最新和最新的定义是关于它们对当前索引的位置。最新项目是索引左侧的第一个项目,最右侧是第一项。

即使你没有检查你的数组大小并完全填充它(我不建议这样做),算法会覆盖最新的项目:它可能不太好但是它与队列的概念。当然,如果数组填满,你总是可以决定分配一个更大的数组并将当前数据复制到更大的数组

答案 1 :(得分:1)

您正在寻找的是队列数据结构。

可以使用循环缓冲区方便地实现队列,其中您有头索引和尾索引。

头部和尾部最初都设置为零。

通过将新元素写入Tail指向的位置添加新元素,然后增加Tail。如果递增使其离开数组的末尾,则根据需要换行。

通过递增Head来删除旧元素。再次,如果递增使得它离开数组的末尾,则根据需要进行换行。

头总是指向最古老的元素。 Tail总是指向最新元素的右侧。

答案 2 :(得分:-1)

使用System.Collections.Generic.Queue<T>,其中T是一个字节块。

Queue<byte[]> queue = new Queue<byte[]>();
byte[] block;

queue.Enqueue(new byte[] { 10, 11, 12, 13 });
queue.Enqueue(new byte[] { 20, 21, 22, 23 });
queue.Enqueue(new byte[] { 30, 31, 32, 33 });
block = queue.Dequeue();
queue.Enqueue(new byte[] { 40, 41, 42, 43 });
block = queue.Dequeue();
block = queue.Dequeue();
queue.Enqueue(new byte[] { 50, 51, 52, 53 });
queue.Enqueue(new byte[] { 60, 61, 62, 63 });
queue.Enqueue(new byte[] { 70, 71, 72, 73 });
block = queue.Dequeue();
// ...

Dequeue总是删除最旧的元素!


由于您已在注释中阐明它必须是一个数组,因此这是一个将数组队列封装在一个类中的解决方案。它将连续元素视为定义大小的数据块。它还允许您通过索引和数组本身访问数组元素。这不是典型的队列,但因为你需要数组...

public class ArrayBlocksQueue<T>
{
    private T[] _array;
    private int _in, _out, _count, _length, _blockSize;

    public ArrayBlocksQueue(int maxBlocks, int blockSize)
    {
        _length = maxBlocks * blockSize;
        _blockSize = blockSize;
        _array = new T[_length];
    }

    public void Enqueue(params T[] block)
    {
        if (block == null) {
            throw new ArgumentNullException();
        }
        if (block.Length != _blockSize) {
            throw new ArgumentException("Data does not have required block size.");
        }
        if (_count + _blockSize > _length) {
            throw new ApplicationException("Queue is full");
        }
        block.CopyTo(_array, _in);
        _in = (_in + _blockSize) % _length;
        _count += _blockSize;
    }

    public T[] Dequeue()
    {
        if (_count == 0) {
            throw new ApplicationException("Queue is empty");
        }
        T[] temp = new T[_blockSize];
        System.Array.Copy(_array, _out, temp, 0, _blockSize);
        _out = (_out + _blockSize) % _length;
        _count -= _blockSize;
        return temp;
    }

    public int Count { get { return _count; } }

    public int BlockCount { get { return _count / _blockSize; } }

    public T[] Array { get { return _array; } }

    public T this[int index]
    {
        get
        {
            if (!IsIndexValid(index)) {
                throw new IndexOutOfRangeException();
            }
            return _array[index];
        }
        set
        {
            if (!IsIndexValid(index)) {
                throw new IndexOutOfRangeException();
            }
            _array[index] = value;
        }
    }

    public bool IsIndexValid(int index)
    {
        if (index < 0 || index >= _length) {
            return false;
        }
        if (_count == _length) {
            return true;
        }
        return _out > _in
            ? index < _in || index >= _out
            : index >= _out && index < _in;
    }
}