再帰関数を反復関数に変換したい。通常は、キューを初期化し、最初のjobをキューに入れます。次に、whileループでキューからジョブを消費し、新しいジョブをキューに追加します。再帰的な関数がそれ自体を複数回呼び出す場合(たとえば、多くの分岐を持つツリーを歩く)、複数のジョブが追加されます。疑似コード:
queue = new Queue();
queue.put(param);
result = 0;
while (!queue.isEmpty()) {
param = queue.remove();
// process param and obtain new param(s)
// change result
queue.add(param1);
queue.add(param2);
}
return result;
しかし、MATLABで構造のようなキューを見つけることができません。ベクトルを使用して、キューに3を追加するようなキューをシミュレートできます。
a = [a 3]
要素の削除は
val = a(1);
a(1) = [];
私がMATLABのやり方を正しく理解していれば、このメソッドはパフォーマンスキラーになります。
MATLABでキューを使用する正しい方法はありますか?
他のデータ構造はどうですか?
適切なデータ構造の使用を主張する場合は、MATLAB内からJavaを使用できます。
import Java.util.LinkedList
q = LinkedList();
q.add('item1');
q.add(2);
q.add([3 3 3]);
item = q.remove();
q.add('item4');
OK、MATLABハンドルクラスを使用した、ほとんどテストされていない、ほとんどテストされていない実装です。スカラー数値のみを格納する場合は、セル配列ではなく「要素」にdouble配列を使用できます。パフォーマンスについてはわかりません。
classdef Queue < handle
properties ( Access = private )
elements
nextInsert
nextRemove
end
properties ( Dependent = true )
NumElements
end
methods
function obj = Queue
obj.elements = cell(1, 10);
obj.nextInsert = 1;
obj.nextRemove = 1;
end
function add( obj, el )
if obj.nextInsert == length( obj.elements )
obj.elements = [ obj.elements, cell( 1, length( obj.elements ) ) ];
end
obj.elements{obj.nextInsert} = el;
obj.nextInsert = obj.nextInsert + 1;
end
function el = remove( obj )
if obj.isEmpty()
error( 'Queue is empty' );
end
el = obj.elements{ obj.nextRemove };
obj.elements{ obj.nextRemove } = [];
obj.nextRemove = obj.nextRemove + 1;
% Trim "elements"
if obj.nextRemove > ( length( obj.elements ) / 2 )
ntrim = fix( length( obj.elements ) / 2 );
obj.elements = obj.elements( (ntrim+1):end );
obj.nextInsert = obj.nextInsert - ntrim;
obj.nextRemove = obj.nextRemove - ntrim;
end
end
function tf = isEmpty( obj )
tf = ( obj.nextRemove >= obj.nextInsert );
end
function n = get.NumElements( obj )
n = obj.nextInsert - obj.nextRemove;
end
end
end
q = {};
head = 1;
q{head} = param;
result = 0;
while (head<=numel(q))
%process param{head} and obtain new param(s)
head = head + 1;
%change result
q{end+1} = param1;
q{end+1} = param2;
end %loop over q
return result;
最後に追加しすぎるとパフォーマンスが低下する場合は、チャンクを追加します。
chunkSize = 100;
chunk = cell(1, chunkSize);
q = chunk;
head = 1;
nextLoc = 2;
q{head} = param;
result = 0;
while (head<endLoc)
%process param{head} and obtain new param(s)
head = head + 1;
%change result
if nextLoc > numel(q);
q = [q chunk];
end
q{nextLoc} = param1;
nextLoc = nextLoc + 1;
q{end+1} = param2;
nextLoc = nextLoc + 1;
end %loop over q
return result;
クラスは確かによりエレガントで再利用可能ですが、ツールをタスクに適合させます。
データ構造のようなキューも必要でした。
幸い、私は要素の数に制限がありました(n)。
それらはすべてある時点でキューに入れられますが、一度だけです。
状況が似ている場合は、固定サイズの配列と2つのインデックスを使用して単純なアルゴリズムを適応させることができます。
queue = zeros( n, 1 );
firstq = 1;
lastq = 1;
while( lastq >= firstq && firstq <= n )
i = queue( firstq ); % pull first element from the queue
% you do not physically remove it from an array,
% thus saving time on memory access
firstq = firstq + 1;
% % % % % % % % % % % % % WORKER PART HERE
% do stuff
%
% % % % % % % % % % % % % % % % % % % % %
queue( lastq ) = j; % Push element to the end of the queue
lastq = lastq + 1; % increment index
end;
このコードを使用して、コードをmファイルとして保存し、q.pop()などの関数を使用します。これは、いくつかの変更を加えた元のコードです。
properties (Access = private)
buffer % a cell, to maintain the data
beg % the start position of the queue
rear % the end position of the queue
% the actually data is buffer(beg:rear-1)
end
properties (Access = public)
capacity % ص»µؤبفء؟£¬µ±بفء؟²»¹»ت±£¬بفء؟ہ©³نخھ2±¶،£
end
methods
function obj = CQueue(c) % ³ُت¼»¯
if nargin >= 1 && iscell(c)
obj.buffer = [c(:); cell(numel(c), 1)];
obj.beg = 1;
obj.rear = numel(c) + 1;
obj.capacity = 2*numel(c);
elseif nargin >= 1
obj.buffer = cell(100, 1);
obj.buffer{1} = c;
obj.beg = 1;
obj.rear = 2;
obj.capacity = 100;
else
obj.buffer = cell(100, 1);
obj.capacity = 100;
obj.beg = 1;
obj.rear = 1;
end
end
function s = size(obj) % ¶سءذ³¤¶ب
if obj.rear >= obj.beg
s = obj.rear - obj.beg;
else
s = obj.rear - obj.beg + obj.capacity;
end
end
function b = isempty(obj) % return true when the queue is empty
b = ~logical(obj.size());
end
function s = empty(obj) % clear all the data in the queue
s = obj.size();
obj.beg = 1;
obj.rear = 1;
end
function Push(obj, el) % ر¹بëذآشھثطµ½¶سخ²
if obj.size >= obj.capacity - 1
sz = obj.size();
if obj.rear >= obj.beg
obj.buffer(1:sz) = obj.buffer(obj.beg:obj.rear-1);
else
obj.buffer(1:sz) = obj.buffer([obj.beg:obj.capacity 1:obj.rear-1]);
end
obj.buffer(sz+1:obj.capacity*2) = cell(obj.capacity*2-sz, 1);
obj.capacity = numel(obj.buffer);
obj.beg = 1;
obj.rear = sz+1;
end
obj.buffer{obj.rear} = el;
obj.rear = mod(obj.rear, obj.capacity) + 1;
end
function el = front(obj) % ·µ»ط¶ست×شھثط
if obj.rear ~= obj.beg
el = obj.buffer{obj.beg};
else
el = [];
warning('CQueue:NO_DATA', 'try to get data from an empty queue');
end
end
function el = back(obj) % ·µ»ط¶سخ²شھثط
if obj.rear == obj.beg
el = [];
warning('CQueue:NO_DATA', 'try to get data from an empty queue');
else
if obj.rear == 1
el = obj.buffer{obj.capacity};
else
el = obj.buffer{obj.rear - 1};
end
end
end
function el = pop(obj) % µ¯³ِ¶ست×شھثط
if obj.rear == obj.beg
error('CQueue:NO_Data', 'Trying to pop an empty queue');
else
el = obj.buffer{obj.beg};
obj.beg = obj.beg + 1;
if obj.beg > obj.capacity, obj.beg = 1; end
end
end
function remove(obj) % اه؟ص¶سءذ
obj.beg = 1;
obj.rear = 1;
end
function display(obj) % دشت¾¶سءذ
if obj.size()
if obj.beg <= obj.rear
for i = obj.beg : obj.rear-1
disp([num2str(i - obj.beg + 1) '-th element of the stack:']);
disp(obj.buffer{i});
end
else
for i = obj.beg : obj.capacity
disp([num2str(i - obj.beg + 1) '-th element of the stack:']);
disp(obj.buffer{i});
end
for i = 1 : obj.rear-1
disp([num2str(i + obj.capacity - obj.beg + 1) '-th element of the stack:']);
disp(obj.buffer{i});
end
end
else
disp('The queue is empty');
end
end
function c = content(obj) % ب،³ِ¶سءذشھثط
if obj.rear >= obj.beg
c = obj.buffer(obj.beg:obj.rear-1);
else
c = obj.buffer([obj.beg:obj.capacity 1:obj.rear-1]);
end
end
end end
リファレンス: リスト、キュー、Matlabのスタック構造
FIFO事前定義されたサイズのキューで単純な直接アクセスを必要とせずに実行できる場合、単純にmodulo演算子といくつかのカウンター変数を使用できます:
myQueueSize = 25; % Define queue size
myQueue = zeros(1,myQueueSize); % Initialize queue
k = 1 % Counter variable
while 1
% Do something, and then
% Store some number into the queue in a FIFO manner
myQueue(mod(k, myQueueSize)+1) = someNumberToQueue;
k= k+1; % Iterate counter
end
このアプローチは非常に単純ですが、通常のキューほど簡単にアクセスできないという欠点があります。つまり、最新の要素は常に要素1でなく、要素kになります。FIFO統計演算のデータストレージなどの一部のアプリケーションでは、これは必ずしも問題ではありません。
ベクトル(またはスカラー)を格納するためだけにキューが必要な場合、circshift()
関数と共に行列を使用して、固定長の基本的なキューを実装することは難しくありません。
% Set the parameters of our queue
n = 4; % length of each vector in queue
max_length = 5;
% Initialize a queue of length of nx1 vectors
queue = NaN*zeros(n, max_length);
queue_length = 0;
プッシュする:
queue = circshift(queue, 1, 2); % Move each column to the right
queue(:,1) = Rand(n, 1); % Add new vector to queue
queue_length = min(max_length, queue_length + 1);
ポップするには:
result = queue(:,last)
queue(:, last) = NaN;
queue_length = max(1, queue_length - 1);