JavaScript中的循环缓冲区

36 javascript circular-buffer data-structures

有人已经在JavaScript中实现了循环缓冲区吗?没有指针你会怎么做?

bob*_*nce 31

奇怪的共同发生,我今天刚刚写了一篇!我不知道你的要求究竟是什么,但这可能是有用的.

它呈现的界面就像一个无限长度的数组,但"忘记"旧项:

// Circular buffer storage. Externally-apparent 'length' increases indefinitely
// while any items with indexes below length-n will be forgotten (undefined
// will be returned if you try to get them, trying to set is an exception).
// n represents the initial length of the array, not a maximum
function CircularBuffer(n) {
    this._array= new Array(n);
    this.length= 0;
}
CircularBuffer.prototype.toString= function() {
    return '[object CircularBuffer('+this._array.length+') length '+this.length+']';
};
CircularBuffer.prototype.get= function(i) {
    if (i<0 || i<this.length-this._array.length)
        return undefined;
    return this._array[i%this._array.length];
};
CircularBuffer.prototype.set= function(i, v) {
    if (i<0 || i<this.length-this._array.length)
        throw CircularBuffer.IndexError;
    while (i>this.length) {
        this._array[this.length%this._array.length]= undefined;
        this.length++;
    }
    this._array[i%this._array.length]= v;
    if (i==this.length)
        this.length++;
};
CircularBuffer.IndexError= {};
Run Code Online (Sandbox Code Playgroud)

  • "不确定",如[1.7976931348623157e + 308](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_VALUE#Description),这反过来意味着**一些**'无限`.+1 (2认同)
  • 它最多只能工作到“Number_MAX_SAFE_INTEGER”或“2^53 - 1”。这是因为“Number_MAX_SAFE_INTEGER + 1”等于“Number_MAX_SAFE_INTEGER + 2”。仍然是一个非常大的数字,几乎有十亿亿!来源:[MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER) (2认同)

Tor*_*ker 20

var createRingBuffer = function(length){

  var pointer = 0, buffer = []; 

  return {
    get  : function(key){return buffer[key];},
    push : function(item){
      buffer[pointer] = item;
      pointer = (length + pointer +1) % length;
    }
  };
};
Run Code Online (Sandbox Code Playgroud)

更新:如果你只用数字填充缓冲区,这里有一些衬里插件:

min  : function(){return Math.min.apply(Math, buffer);},
sum  : function(){return buffer.reduce(function(a, b){ return a + b; }, 0);},
Run Code Online (Sandbox Code Playgroud)

  • 为什么你有`pointer =(length + pointer +1)%length`而不仅仅是`pointer =(pointer + 1)%length`? (3认同)

Two*_*ist 6

像许多其他人一样,我喜欢noiv的解决方案,但我想要一个更好的API:

var createRingBuffer = function(length){
  /* https://stackoverflow.com/a/4774081 */
  var pointer = 0, buffer = []; 

  return {
    get  : function(key){
        if (key < 0){
            return buffer[pointer+key];
        } else if (key === false){
            return buffer[pointer - 1];
        } else{
            return buffer[key];
        }
    },
    push : function(item){
      buffer[pointer] = item;
      pointer = (pointer + 1) % length;
      return item;
    },
    prev : function(){
        var tmp_pointer = (pointer - 1) % length;
        if (buffer[tmp_pointer]){
            pointer = tmp_pointer;
            return buffer[pointer];
        }
    },
    next : function(){
        if (buffer[pointer]){
            pointer = (pointer + 1) % length;
            return buffer[pointer];
        }
    }
  };
};
Run Code Online (Sandbox Code Playgroud)

原始改进:

  • get 支持默认参数(返回最后一项推送到缓冲区)
  • get 支持负索引(从右计算)
  • prev 将缓冲区移回一个并返回那里的内容(如弹出而不删除)
  • next 撤消prev(向前移动缓冲区并返回它)

我用它来存储一个命令历史记录,然后我可以使用它prevnext方法在应用程序中翻转,当它们无处可去时很好地返回undefined.


Iva*_*tov 5

差不多 10 年后,一个使用 JavaScript ES6 的答案:

    class CircularBuffer {
      constructor(bufferLength) {
        this.buffer = [];
        this.pointer = 0;
        this.bufferLength = bufferLength;
      }
      
      push(element) {
        if(this.buffer.length === this.bufferLength) {
           this.buffer[this.pointer] = element;
        } else {
           this.buffer.push(element);
        }
        this.pointer = (this.pointer + 1) % this.bufferLength;
      }
    
      get(i) {
        return this.buffer[i];
      }
      
      //Gets the ith element before last one 
      getLast(i) {
        return this.buffer[this.pointer+this.bufferLength-1-i];
      }
    
    }

//To use it:

let circularBuffer = new CircularBuffer(3);
circularBuffer.push('a');
circularBuffer.push('b');
circularBuffer.push('c');
// should print a,b,c
console.log(`0 element: ${circularBuffer.get(0)}; 1 element: ${circularBuffer.get(1)}; 2 element: ${circularBuffer.get(2)};`);

console.log('Last element: '+circularBuffer.getLast(0)); // should print 'c'

circularBuffer.push('d');

// should print d,b,c
console.log(`0 element: ${circularBuffer.get(0)}; 1 element: ${circularBuffer.get(1)}; 2 element: ${circularBuffer.get(2)};`);
Run Code Online (Sandbox Code Playgroud)