2011-08-30 18 views
6

muszę pojemnik do przechowywania pary, mam dwie operacje:C++ słowniku priorytet

  1. wartość aktualizację kluczy
  2. dostać klucz do maksymalnej wartości.

Dla pierwszej operacji mapa jest dobrą strukturą. Dla drugiej operacji kolejka priorytetowa wygląda na dobrą. Jak byś to zrobił? Czy mimo to obie operacje są wykonywane bez pętli O (n)? Dzięki.

Odpowiedz

7

asymptotycznie wydajne rozwiązanie to byłoby użyć kombinacji tabeli mieszania i sterty Fibonacciego. Za pomocą tabeli mieszania można uzyskać dostęp do wartości skojarzonej z dowolnym kluczem w czasie O (1) i użyć sterty Fibonacci, aby szybko wyszukać parę klucz/wartość o najniższej wartości (wykonując tę ​​operację w O (1)).

Jeśli chcesz zmienić wartość skojarzoną z kluczem, jeśli zwiększasz wartość, możesz to zrobić w (zamortyzowanym) czasie O (1), używając operacji zwiększania klucza na stadzie Fibonacci, która ma O (1) czas amortyzacji. Jeśli zmniejszasz wartość, upłynie czas O (log n), aby usunąć element ze sterty Fibonacci, a następnie ponownie go wstawić.

W sumie daje to złożoność czasową

  • Włóż nowy element: O (1) dla hash, O (1) dla wkładki do sterty Fibonacciego: O (1) czas.
  • Usuń element: O (1) dla skrótu, O (log n) dla usunięcia z sterty Fibonacciego: Czas O (log n).
  • Znajdź najlepszy element: O (1) do wyszukiwania w kupce Fibonacciego: O (1) czas.
  • Zwiększ wartość: O (1) dla skrótu, O (1) dla klawisza zwiększania: O (1) czas.
  • Zmniejszenie wartości: O (1) dla skrótu, O (log n) dla usunięcia/wstawienia: Czas O (log n).

Mam nadzieję, że to pomoże!

+0

To jest dobre rozwiązanie! Powinieneś również zauważyć wady: utrzymywanie synchronizacji i wykorzystanie pamięci. –

+0

@Mooing Duck - najlepiej byłoby zawinąć to we własnej klasie, aby nie można było zsynchronizować dwóch ze sobą. I tak, jest więcej użycia pamięci, ale to tylko stały czynnik, więcej niż tylko jedna z dwóch struktur. – templatetypedef

+0

@templatetypedef: +1, ale stertę Fibonacciego zamiast sterty binarnej (lub sterty narybku) - naprawdę? Rozumiem, że teoretyczne, amortyzowane granice mogą być lepsze, ale czy tak jest w praktyce? Zobacz na przykład: http://stackoverflow.com/questions/504823/has-anyone-aktually-implemented-a-fibonacci-heap-efektywnie. Ponadto, czy stosy Fibonaaci nie mają w rzeczywistości złej złożoności w przypadku niektórych operacji? –

2

Utwórz heap structure (dla drugiego pocisku) i umieść każdy z jego węzłów na mapie (dla pierwszego punktu).

EDIT: Implementacja min sterty zrobiłem jakiś czas w przeszłości

#ifndef MINHEAP_H 
#define MINHEAP_H 

//////////////////////// MinHeap with Map for Data //////////////////////// 

template <class T, class M = int> class MinHeap { 
    T*   array; 
    unsigned const int arr_max; 
    unsigned int  elements; 
    M   map; 

    void percolate_down(unsigned int i=0) { 
     unsigned int n = elements-1, min; 
     do { 
      unsigned int l = 2*i + 1, r = 2*i + 2; 
      if (l <= n && array[i] > array[l]) min = l; 
      else min = i; 
      if (r <= n && array[i] > array[r] && array[l] > array[r]) min = r; 
      if (i != min) { 
       T temp = array[i]; 
       array[i] = array[min]; 
       array[min] = temp; 
       map.update(array[i], i); 
       map.update(array[min], min); 
       i = min; 
      } else break; 
     } while (i < n); 
    } 
    void percolate_up(unsigned int i) { 
     while (i && array[(i-1)/2] > array[i]) { 
      T temp = array[i]; 
      array[i] = array[(i-1)/2]; 
      array[(i-1)/2] = temp; 
      map.update(array[i], i); 
      map.update(array[(i-1)/2], (i-1)/2); 
      i = (i-1)/2; 
     } 
    } 
public: 
    MinHeap(const int max) : array(new T[max]), arr_max(max), elements(0), map(max) {} 
    ~MinHeap(void) { delete[] array; } 

    bool empty(void) const { return elements == 0; } 
    unsigned int capacity(void) const { return arr_max; } 
    unsigned int size(void) const { return elements; } 
    const M& heapmap(void) const { return map; } 
    const T& peek(unsigned int i=0) const { return array[i]; } 

    bool insert(T& element) { 
     if (arr_max == elements) return false; 

     unsigned int k = elements++; 
     map.update(element, k); 
     array[k] = element; 
     percolate_up(k); 
     return true; 
    } 
    unsigned int mass_insert(T copy[], unsigned int n) { 
     unsigned int i = 0;  
     for(; i < n ; i++) if (!insert(copy[i])) break; 
     return i; 
    } 
    bool delete_min(void) { 
     if (elements == 0) return false; 

     map.update(array[0], arr_max+1); 
     array[0] = array[--elements]; 
     map.update(array[0], 0); 
     percolate_down(); 
     return true; 
    } 
    bool delete_element(unsigned int i) { 
     if (i > elements) return false; 

     map.update(array[i], arr_max+1); 
     T temp = array[i];  
     array[i] = array[--elements]; 
     map.update(array[i], i); 
     if (array[i] > temp) percolate_down(i); 
     else if (temp > array[i]) percolate_up(i); 
     return true; 
    } 
    bool update(unsigned int i, T& element) { 
     if (i > elements) return false; 

     map.update(array[i], arr_max+1); 
     T temp = array[i];  
     array[i] = element; 
     map.update(array[i], i); 
     if (array[i] > temp) percolate_down(i); 
     else if (temp > array[i]) percolate_up(i); 
     return true; 
    } 

// void print() { using namespace std; for (unsigned int i=0 ; i < elements ; i++) cout << array[i] << " | "; cout << endl; } 


    // Iterators 
/* 
    friend class Const_Iterator; 

    class Const_Iterator { 
     MinHeap<T>* heap; 
     unsigned int index; 
     Const_Iterator(MinHeap<T>* h, unsigned int i) : heap(h), index(i) {} 
    public: 
     Const_Iterator(const Const_Iterator& clone) : heap(clone.heap), index(clone.index) {} 

     friend Const_Iterator MinHeap<T>::begin(void); 
    }; 

    Const_Iterator begin(void) { return Const_Iterator(this, 0); } 
*/ 
}; 

////////////////////////////////////////////////////////////////////////////// 


//////////////////////// MinHeap without Map for Data //////////////////////// 

template <class T> class MinHeap <T, int> { 
    T*   array; 
    unsigned const int arr_max; 
    unsigned int  elements; 

    void percolate_down(unsigned int i=0) { 
     unsigned int n = elements-1, min; 
     do { 
      unsigned int l = 2*i + 1, r = 2*i + 2; 
      if (l <= n && array[i] > array[l]) min = l; 
      else min = i; 
      if (r <= n && array[i] > array[r] && array[l] > array[r]) min = r; 
      if (i != min) { 
       T temp = array[i]; 
       array[i] = array[min]; 
       array[min] = temp; 
       i = min; 
      } else break; 
     } while (i < n); 
    } 
    void percolate_up(unsigned int i) { 
     while (i && array[(i-1)/2] > array[i]) { 
      T temp = array[i]; 
      array[i] = array[(i-1)/2]; 
      array[(i-1)/2] = temp; 
      i = (i-1)/2; 
     } 
    } 
public: 
    MinHeap(const int max) : array(new T[max]), arr_max(max), elements(0) {} 
    ~MinHeap(void) { delete[] array; } 

    bool empty(void) const { return elements == 0; } 
    unsigned int capacity(void) const { return arr_max; } 
    unsigned int size(void) const { return elements; } 
    const T& peek(unsigned int i=0) const { return array[i]; } 

    bool insert(T& element) { 
     if (arr_max == elements) return false; 

     unsigned int k = elements++; 
     array[k] = element; 
     percolate_up(k); 
     return true; 
    } 
    unsigned int mass_insert(T copy[], unsigned int n) { 
     unsigned int i = 0;  
     for(; i < n ; i++) if (!insert(copy[i])) break; 
     return i; 
    } 
    bool delete_min(void) { 
     if (elements == 0) return false; 

     array[0] = array[--elements]; 
     percolate_down(); 
     return true; 
    } 
    bool delete_element(unsigned int i) { 
     if (i > elements) return false; 

     T temp = array[i];  
     array[i] = array[--elements]; 
     if (array[i] > temp) percolate_down(i); 
     else if (temp > array[i]) percolate_up(i); 
     return true; 
    } 
    bool update(unsigned int i, T& element) { 
     if (i > elements) return false; 

     T temp = array[i];  
     array[i] = element; 
     if (array[i] > temp) percolate_down(i); 
     else if (temp > array[i]) percolate_up(i); 
     return true; 
    } 

// void print() { using namespace std; for (unsigned int i=0 ; i < elements ; i++) cout << array[i] << " | "; cout << endl; } 
}; 

////////////////////////////////////////////////////////////////////////////// 

#endif // MINHEAP_H 
+0

Można również użyć 'std :: priority_queue'. – Dawson

+0

@Toolbox Struktura sterty to sposób na implementację priority_queue :) –

+0

Wiem - chodzi mi o to, że nie ma potrzeby ponownego wdrażania tego, co jest już częścią standardowego C++. – Dawson

2

boost :: bimap mógł robić co chcesz, gdzie odwrotna mapa służy do wdrożenia # 2.

+0

Co się stanie, jeśli wiele kluczy ma tę samą wartość? – templatetypedef

+0

@templatetypedef: Twój wybór, możliwe są różne indeksy, takie jak 'bimap >'. –

0

myślę bimap jest najlepsza droga

+0

Co się stanie, jeśli wiele kluczy ma przypisaną tę samą wartość? – templatetypedef

1

Według mojego standardowej C++ 0x, The fundamental property of iterators of associative containers is that they iterate through the containers in the non-descending order of keys where non-descending is defined by the comparison that was used to construct them.

Więc po prostu korzystać z mapy. Wyszukiwanie losowe to O (log (n)), a uzyskanie najwyższego elementu zajmuje czas O (1).

value getHighest(map<key, value>& map) { 
    assert(map.empty() == false); 
    return (--map.end())->second; 
} 
+0

Czy to jest chwyt dla mapy skrótów? wtedy szukanie będzie również O (1) – user875367

+0

Nie, hasze są nieuporządkowane, więc nie możesz znaleźć najwyższego elementu. –