2012-02-10 14 views
9

Postępowałem zgodnie ze wskazówkami podanymi w this question (odpowiedź Jason) w celu napisania mojej PriorityQueue<T> przy użyciu SortedList. Rozumiem, że pole count w tej klasie służy do zapewnienia unikalnych priorytetów i zachowania porządku kolejkowania pośród tego samego priorytetu.Zmiana priorytetu w niestandardowej kolejce priorytetowej

Jednakże, gdy count osiągnie swoją maksymalną wartość, a ja sumuję 1 do niego, ta ostatnia rozpocznie się ponownie od 0, więc priorytet kolejnych elementów będzie wyższy niż priorytet poprzednich pozycji. Stosując to podejście mogłem potrzeba sposobu, aby „bezpiecznie” reset licznika count ... W rzeczywistości, załóżmy mieć następujący stan kolejki (w priorytecie Format | liczyć | przedmiot):

0 | 123 | A
0 | 345 | B
1 | 234 | C
2 | 200 | D

Teraz załóżmy, że limit licznika został osiągnięty, więc muszę zresetować go do 0: w konsekwencji, następny wstawiony element będzie miał licznik 0: na przykład, jeśli wstawię element z priorytetem równym 1, to zostanie błędnie wstawiony przed 1 | 234 | D

0 | 123 | A
0 | 345 | B
1 | 000 | nowy element
1 | 234 | C
2 | 200 | D

Problem priorytetu może być rozwiązany poprzez wdrożenie sterty: Stworzyłem klasę Heap, następnie użyłem Heap<KeyValuePair<TPriority, TElement> i zwyczaj PriorityComparer w celu uporządkowania elementów przez TPriority. Biorąc TPriority jako int i TElement jako string The PriorityComparer jest następujący:

public class MyComparer : IComparer<KeyValuePair<int, string>> 
{ 
    public int Compare(KeyValuePair<int, string> x, KeyValuePair<int, string> y) 
    { 
     return x.Key.CompareTo(y.Key); 
    } 
} 

... 

int capacity = 10; 
Heap<KeyValuePair<int, string>> queue; 
queue = new Heap<KeyValuePair<int, string>>(capacity, new PriorityComparer()); 

... 

UPDATE W ten sposób (przy użyciu PriorityComparer), udało mi się zaimplementować kolejkę priorytetową. Teraz chciałbym dodać wsparcie, aby zmodyfikować jego zachowanie w czasie wykonywania, tzn. Przełączyć z FIFO na sortowanie priorytetowe i na odwrót. Ponieważ moja realizacja priorytetu kolejki ma pole IComparer, myślę, że to wystarczy dodać obiekt Comparer edytować to pole, podobnie jak następuje:

public IComparer 
{ 
    set 
    { 
     this._comparer = value; 
    } 
} 

w międzyczasie pomyślałem, że wezmę innego podejścia: zamiast używać sterówki binarnej do zarządzania priorytetami, mógłbym owijać różne kolejki (każda kolejka odnosi się do danego priorytetu) w następujący sposób.

public class PriorityQueue<T, int> 
{ 
    private Queue<T> _defaultQueue; 
    private bool _priority; 
    private SortedList<int, Queue<T>> _priorityQueues; 

    public PriorityQueue(int capacity) 
    { 
     this._defaultQueue = new Queue<T>(capacity); 
     this._priority = false; 
     this._priorityQueues = new SortedList<int, Queue<T>>(0); 
    } 

    public void PriorityEnable() 
    { 
     this._priority = true; 
    } 

    public void PriorityDisable() 
    { 

     this._priority = false; 
    } 

    public void Enqueue(T item) 
    { 
     if (this._priority) 
     { 
      // enqueue to one of the queues 
      // with associated priority 
      // ... 
     } 
     else this._defaultQueue.Enqueue(item); 
    } 

    public T Dequeue() 
    { 
     if (this._priority) 
     { 
      // dequeue from one of the queues 
      // with associated priority and 
      // return 
      // ... 
     } 
     return this._defaultQueue.Dequeue(); 
    } 
} 
  1. Jak zarządzać przejście od FIFO Tryb do trybie priorytetu gdy wciąż istnieją elementy w domyślnej kolejce? Mogę skopiować je w kolejkach priorytetowych na podstawie priorytetu pozycji ... Inne lepsze rozwiązania?
  2. Jak zarządzać przejściem z trybu priorytetowego na Tryb FIFO? W tym przypadku miałbym kilka kolejek priorytetowych, które mogą zawierać elementy, ale nie muszą już nimi zarządzać zgodnie z priorytetem i nawet nie znają oryginalnej kolejności przyjazdu ...
  3. Jak zarządzać przepustowością różnych kolejki?
  4. Co z wykonaniem powyższych dwóch rozwiązań? Który używa więcej pamięci?
+0

Czy moja odpowiedź stanowi pomoc w rozwiązaniu problemu? – JeremyK

Odpowiedz

1

EDYCJA: Zmieniłeś to, o co prosisz, wprowadzając zmiany. Przeszedłeś od zadawania jednego pytania do zrobienia nowego podejścia i zadawania nowego pytania. Powinien prawdopodobnie otworzyć nowe pytanie dotyczące nowego podejścia, ponieważ obecnie jest ono mylące co do odpowiedzi/odpowiedzi na pytanie/komentarz. Sądzę, że odpowiedziano na twoje pierwotne pytanie dotyczące sortowania równych priorytetów.

Można użyć długo, aby uzyskać więcej wartości. W końcu zawsze dojdziesz do końca, więc będziesz musiał użyć nowego wzorca dla unikalnych wartości lub "zsumować" elementy, gdy osiągniesz maksimum (przeprowadź każdy z nich i zresetuj unikalną wartość licznika).

Może zamiast tego należy użyć identyfikatora GUID dla każdego elementu?

Guid.NewGuid()

EDIT:

Aby dodać po EDIT: Jeśli chcesz nowa 1 należy umieścić po istniejącym, W ręcznym porównania powrót większy niż rezultat (1), gdy wartości są równe. W ten sposób stanie się co następuje:

1 > 0, return greater (1), continue 
1 > 0, return greater (1), continue 
1 == 1, return greater (1), continue 
1 < 2, return less than (-1), insert 

EDIT 2:

Jeśli drugi parametr jest przeznaczona tylko być unikalną wartość, zawsze można użyć ciąg i ustaw wartość jako ciągów liczbowych zamiast. W ten sposób nigdy nie osiągniesz limitu, musisz tylko przeanalizować ciąg znaków. Możesz użyć wiodących wartości alfa, które reprezentują nowy zestaw.

Nie przetestowałem tego kodu, tylko wyobrażenie, co możesz zrobić.

static string leadingStr = ""; 
static char currentChar = 'a'; 
static Int32 currentId = Int32.MinValue; 

static string getNextId() 
{ 
    if (currentId >= Int32.MaxValue) 
    { 
     currentId = Int32.MinValue; 
     if (currentChar >= 'z') 
     { 
      currentChar = 'a'; 
      leadingStr = leadingStr.Insert(0, "X"); 
     } 
     else 
      currentChar++; 
    } 
    else 
     currentId++; 

    return String.Format("{0}{1}-{2}", leadingStr, currentChar, currentId); 
} 

EDIT 3: Reset wartości

static Int64 currentValue = Int64.MinValue; 
static void AddItem(object item) 
{ 
    if (currentValue == Int64.MaxValue) 
     RecountItems(); 

    item.counter = currentValue++; 
    SortedList.Add(item); 
} 

static void RecountItems() 
{ 
    currentValue = 0; 
    foreach (var item in SortedList) 
    { 
     item.counter = currentValue++; 
    } 
} 

Edycja 4: Dla drugiego pytania:

można użyć stosu FIFO, jak zwykle, ale też listę priorytetową, że tylko przechowuje unikalny identyfikator przedmiotów. Jednak będziesz musiał usunąć przedmiot z listy za każdym razem, gdy usuniesz go ze stosu FIFO.

static Object RemoveNextFIFO() 
{ 
    if (fifoList.Count > 0) 
    { 
     var removedItem = fifoList[0]; 
     fifoList.RemoveAt(0); 
     RemoveItemFromPriority(removedItem); 
     return removedItem; 
    } 
} 

static void RemoveItemFromPriority(Object itemToRemove) 
{ 
    foreach (var counter in priorityQueue) 
    { 
     if (counter == itemToRemove.counter) 
     { 
      priorityQueue.remove(item); 
      break; 
     } 
    } 
} 

static Object RemoveFromFIFO(int itemCounter) 
{ 
    foreach (var item in fifoList) 
    { 
     if (item.counter == itemCounter) 
     { 
      fifoList.Remove(item); 
      return item; 
     } 
    } 
} 

static Object RemoveNextPriority() 
{ 
    if (priorityQueue.Count > 0) 
    { 
     var counter = priorityQueue.Pop(); 
     return RemoveFromFIFO(counter); 
    } 
} 
+0

Cóż, 'SortedList' automatycznie sortuje elementy za pomocą' IComparer': już utworzyłem ten _comparer_ i działa sortowanie według priorytetu i licznika (pozycje o tym samym priorytecie są sortowane porównując ich liczniki). Problem polega na tym, że w pewnym momencie licznik osiąga swoją maksymalną wartość i zaczyna ponownie od 0: wszelkie elementy dodane przed zresetowaniem licznik miałby większy licznik, a więc wyglądałyby tak, jakby zostały wstawione po ostatnich. 'Guid' nie rozwiązuje problemu, ponieważ jest losowy, więc może zniekształcić kolejność wstawiania. – enzom83

+0

Czy możliwe jest dołączenie dodatkowego parametru do danych? Oznacza to, że jeśli masz identyfikator od 0 do 255 (tylko przykład), możesz mieć idSecond od 0 do 255, gdzie najpierw sprawdzasz id, a następnie idSekond? Czyli masz wszystko od 0,0 do 0,1 do ... 255,255, które wyrównałoby twoje dozwolone liczby? Używanie DWA longs z pewnością przekroczyłoby twoje wymagania, prawda? - Od programisty praktykanta. – BlackVegetable

+1

@BlackVegetable: _Gdy będzie możliwe dołączenie dodatkowego parametru do danych? _ Jeśli nie ma alternatywy, myślę, że jedyne prawo to dodać kolejny parametr, być może długość zawierającą bieżącą datę i godzinę. – enzom83

1

Można „oszukiwać” i używać BigInteger więc nigdy nie „zabraknie numerów”. To oczywiście prowadzi do stopniowego pogorszenia wydajności w czasie, ale prawdopodobnie nie jest wystarczająco znaczące, aby mieć znaczenie.

Połączyć to z kolejką priorytetową opartą na heap i gotowe!


Nie próbuj „przełącznika z FIFO do priorytetu sortowania i vice-versa” - wystarczy umieścić elementy w zarówno struktur danych właściwych dla zadania (Queue i priorytetu kolejki).

+0

Po prostu muszę "przełączyć się z FIFO na sortowanie priorytetowe i na odwrót". W ten sposób, gdy kolejka wypełnia więcej niż określony limit, przechodzi do kolejki priorytetowej. Następnie, gdy poziom napełnienia zostanie obniżony poniżej pewnego progu, nastąpi przejście do FIFO. – enzom83

+0

@ enzom83 Dlaczego? Co próbujesz osiągnąć? –

+0

Potrzebuję kontrolować przepływ wychodzących wiadomości do połączenia, więc używam kolejki dla każdego połączenia: jeśli w kolejce jest zbyt wiele wiadomości, prawdopodobnie połączenie jest wolne, wtedy mogę zastosować priorytet do wychodzących wiadomości. – enzom83

1

Używanie obu Queue i jest tym, co bym zrobił.
Ale jeśli musisz ...

Zamiast jednego klucza użyj 2 klawiszy dla elementu.
Pierwszy klucz priority będzie priorytetem.
Drugi klucz time będzie licznikiem, który będzie podobny do znacznika czasu.

Aby zachować normalne zachowanie, należy użyć klawisza priority.

Po wypełnieniu sterty, HEAPIFY, za pomocą klucza time.
Następnie usuń potrzebne elementy z n.
Teraz HEAPIFY ponownie z kluczem priority, aby powrócić do normalnego zachowania.

+0

Kiedy sterty są pełne, może powinienem je zrekompensować za pomocą klucza _priority_ (nie według czasu) ... – enzom83

+0

To jest bardziej zabawny pomysł, Kolejka + Priorytet Kolejka jest drogą do zrobienia. –

+0

Myślę, że użyję sterty: wystarczy, że każdy element będzie zawierał priorytet, ponieważ duplikaty nie stanowią problemu dla sterty (przedmioty, które mają tę samą wartość są umieszczone w kolejności przybycia, nie ma potrzeby dodawania więcej pola). Jak tylko niektóre elementy ("N" elementy) zostaną usunięte z kolejki, ponownie zestsamizuję się z nowymi priorytetami równymi sobie nawzajem. – enzom83

Powiązane problemy