web-dev-qa-db-fra.com

Existe-t-il une "file d'attente" dans MATLAB?

Je veux convertir une fonction récursive en une fonction itérative. Ce que je fais normalement, c’est que j’initialise une file d’attente, mets le premier job en file d’attente. Puis, dans une boucle while, je consomme les travaux de la file d'attente et en ajoute de nouveaux. Si ma fonction récursive s’appelle elle-même plusieurs fois (par exemple, parcourir un arbre comportant de nombreuses branches), plusieurs tâches sont ajoutées. Pseudo code:

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;

Cependant, je ne trouve aucune file d'attente semblable à la structure dans MATLAB. Je peux utiliser vector pour simuler une file d'attente où l'ajout de 3 à cette file d'attente est similaire à:

a = [a 3]

et enlever l'élément est

val = a(1);
a(1) = [];

Si je comprends bien la méthode MATLAB, cette méthode tuera les performances.

Existe-t-il un moyen sain d’utiliser une file d’attente dans MATLAB?

Qu'en est-il des autres structures de données?

20
nimcap

Si vous insistez pour utiliser les structures de données appropriées, vous pouvez utiliser Java à partir de MATLAB:

import Java.util.LinkedList
q = LinkedList();
q.add('item1');
q.add(2);
q.add([3 3 3]);
item = q.remove();
q.add('item4');
32
Amro

Ok, voici une implémentation rapide et peu testée utilisant une classe de descripteurs MATLAB. Si vous ne stockez que des valeurs numériques scalaires, vous pouvez utiliser un tableau double pour les "éléments" plutôt qu'un tableau de cellules. Aucune idée de la performance.

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
9
Edric
  1. Une solution récursive est-elle vraiment si mauvaise? (examinez toujours votre conception en premier).
  2. Echange de fichiers est votre ami. (voler avec fierté!)
  3. Pourquoi s'embêter avec le problème d'une file d'attente ou d'une classe appropriée - feignez un peu. Rester simple:

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;
 

Si la performance souffre d’ajouter trop à la fin - ajoutez par morceaux:

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;

Une classe est certainement plus élégante et réutilisable - mais adaptez l'outil à la tâche.

5
Marc

J'avais aussi besoin d'une file d'attente comme d'une structure de données.

Heureusement, j'avais un nombre limité d'éléments (n).

Ils font tous la queue à un moment donné, mais une fois seulement.

Si votre situation est similaire, vous pouvez adapter l'algorithme simple en utilisant un tableau de taille fixe et 2 index.

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;
1
Antonm

Utilisez ce code, enregistrez-le en tant que fichier m et utilisez les fonctions telles que q.pop (), etc. . Il s’agit du code original, avec quelques modifications:

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

Référence: list, queue, stack Structures dans Matlab

1
moksef

Si vous pouvez utiliser une file d'attente FIFO de taille prédéfinie sans avoir besoin d'un accès direct simple, vous pouvez simplement utiliser l'opérateur modulo et une variable de compteur:

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

Cette approche est très simple, mais présente l’inconvénient de ne pas être aussi facilement accessible que votre file d’attente habituelle. En d’autres termes, l’élément le plus récent sera toujours l’élément k , et non l’élément 1, etc. Pour certaines applications, telles que FIFO stockage de données pour les opérations statistiques, cela ne pose pas nécessairement problème.

1
Tormod Haugene

Dans le cas où vous avez besoin d'une file d'attente uniquement pour stocker des vecteurs (ou des scalaires), il n'est pas difficile d'utiliser une matrice avec la fonction circshift() pour implémenter une file d'attente de base de longueur fixe.

% 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;

Pousser:

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); 

Pop:

result = queue(:,last)
queue(:, last) = NaN;
queue_length = max(1, queue_length - 1);
0
PaulrBear