【问题标题】:Three dimensional circular buffer三维循环缓冲区
【发布时间】:2016-03-20 10:10:27
【问题描述】:

我正在寻找在 C# .NET 中实现三维循环缓冲区的方法,它允许我提取缓冲区的切片。

我尝试了多维数组,但它不允许我获取缓冲区的特定切片。

我也尝试使用交错数组来实现一个版本,但我发现在理解如何初始化矩阵以及切片提取方面存在一些问题。

感谢您的帮助。

[编辑 1] 缓冲区将用于存储来自 reltime 传感器的数据,宽度高度固定,深度(时间为圆形部分)由用户定义。

我需要的切片将是一个固定大小的矩阵(宽度和高度与给定时间的数据)。

[编辑 2] 我可以实现的唯一实现是有效的。对于锯齿状数组,我仍然停留在声明中(我觉得它很混乱)

public class CircularBufferMatrix<T>
{
    private readonly T[,,] _buffer;

    public CircularBufferMatrix(int width, int height, int depth)
    {
        Width = width;
        Height = height;
        Depth = depth;
        _buffer = new T[width, height, depth];
    }

    public T this[int x, int y, int z]
    {
        set { _buffer[x, y, z%Depth] = value; }
        get { return _buffer[x, y, z%Depth]; }
    }

    #region Getters

    public int Width { get; }

    public int Height { get; }

    public int Depth { get; }

    #endregion
}

【问题讨论】:

  • 嗯,我认为您的要求需要更加精确!例如,您要提取的切片是否始终具有相同的大小并包含相同的数据?
  • @Skizz 嗨,我更新了问题,感谢您的帮助
  • 欢迎来到 SO。有什么代码可以展示吗?
  • 为什么首先将传感器的数据存储在二维数组中,二维数组背后的目的是什么(循环缓冲区很清楚)但为什么不将其存储在其他类型的数据结构中在 CircularBuffer 中。

标签: c# .net


【解决方案1】:

我会将这些分为两个类。您需要类似 CircularBuffer 类的东西来处理读取和写入。另一个可能是您要存储的二维数组的实现。拆分这些的原因是因为您想分别读取/写入帧。

例如:


循环缓冲区实现:

public class CircularBuffer<T>
{
    private T[] _buffer;

    private int IncRollover(int value)
    {
        value++;
        if (value >= _buffer.Length)
            value = 0;

        return value;
    }

    public CircularBuffer(int count)
    {
        _buffer = new T[count];
    }

    public bool Write(T element)
    {
        // if the writeindex (after increasing) equals the readindex, the buffer is full
        var newWriteIndex = IncRollover(WriteIndex);
        if (newWriteIndex == ReadIndex)
            return false;

        _buffer[WriteIndex] = element;

        WriteIndex = newWriteIndex;
        return true;
    }

    public bool TryRead(out T element)
    {
        if (ReadIndex == WriteIndex)
        {
            element = default(T);
            return false;
        }

        element = _buffer[ReadIndex];
        ReadIndex = IncRollover(ReadIndex);

        return true;
    }

    public IEnumerable<T> ReadAll()
    {
        T element;
        while (TryRead(out element))
            yield return element;
    }


    public int ReadIndex { get; private set; }
    public int WriteIndex { get; private set; }
}

这将负责读取和写入单个“帧”/切片。如果你喜欢在 Index 上阅读,你可以扩展这个类。

注意:如果缓冲区已满,写入将返回 false


这可能是存储在循环缓冲区中的二维缓冲区的实现:

public class MyWhateverBuffer<T>
{
    private CircularBuffer<T[,]> _buffer;

    public int Width { get; private set; }
    public int Height { get; private set; }
    public int Depth { get; private set; }

    public MyWhateverBuffer(int width, int height, int depth)
    {
        Width = width;
        Height = height;
        Depth = depth;
        _buffer = new CircularBuffer<T[,]>(depth);
    }

    public T[,] New()
    {
        return new T[Width, Height];
    }

    public bool Add(T[,] buffer)
    {
        return _buffer.Write(buffer);
    }

    public bool TryRead(out T[,] buffer)
    {
        return _buffer.TryRead(out buffer);
    }

    public IEnumerable<T[,]> ReadAll()
    {
        return _buffer.ReadAll();
    }
}

这个类可以这样使用:

MyWhateverBuffer<double> myBuffer = new MyWhateverBuffer<double>(100, 100, 100);

var oneSlice = myBuffer.New();

oneSlice[10, 10] = 3.5;
oneSlice[50, 10] = 23.5;
oneSlice[10, 20] = 43.5;

myBuffer.Add(oneSlice);

var anotherSlice = myBuffer.New();

anotherSlice[10, 10] = 13.5;
anotherSlice[50, 10] = 23.5;
anotherSlice[10, 20] = 43.5;

var result = myBuffer.Add(anotherSlice);

if(!result)
{
    // the buffer was full..
}

// Read the results from the buffer.
foreach(var slice in myBuffer.ReadAll())
{
    Trace.WriteLine(slice[10, 10]);
}

您应该始终检查是否可以添加缓冲区。您不想丢失信息。


旁注:

使用循环缓冲区获得的最大利润是声明元素。就像大数组每次都会被重用。

【讨论】:

    【解决方案2】:

    如果我正确理解您的要求,您需要一个由二维数据数组的项目组成的循环缓冲区,并且一个项目的数据永远不会在其他项目中重复。 C# 没有循环缓冲区类型,但您始终可以自己创建一个:-

    public class CircularBuffer <T> // make it generic
    {
      public class Iterator
      {
        public void MoveForward ();
        public void MoveBackward ();
        public T Item { get { } };
    
        CicrcularBuffer <T> m_container;
        LinkedListNode <T> m_current_item;
      }
    
      public void Add (T item);
      public Iterator GetIterator ();
    
      LinkedList<T> m_data;
    }
    

    然后创建一个类来包含您的数据:-

    public class SensorData
    {
      // contains the two dimension data
    }
    

    并像这样使用它:-

    var buffer = new CircularBuffer <SensorData> ();
    var iterator = buffer.GetIterator ();
    var item = iterator.Item;
    iterator.MoveForward ();
    

    显然,有很多内容需要填写,但应该可以帮助您入门。

    【讨论】:

      猜你喜欢
      • 2019-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-26
      • 2021-09-01
      • 2016-06-11
      相关资源
      最近更新 更多