Risposta breve: non puoi.
Risposta leggermente più lunga:
Avrai bisogno di spazio extra per memorizzare l '"età" della tua voce che ti permetterà di discriminare tra priorità identiche. E avrai bisogno di Ω ( n ) spazio per informazioni che consentano inserimenti e recuperi rapidi. Più il tuo payload (valore e priorità).Ω(n)Ω(n)
E, per ogni carico di memorizzare, sarete in grado di "nascondere" alcune informazioni l'indirizzo (ad esempio, significa Y è più vecchio di X). Ma in quelle informazioni "nascoste", nasconderai le informazioni "età", o le informazioni "recupero rapido". Non entrambi.addr(X)<addr(Y)
Risposta molto lunga con pseudo-matematica traballante inesatta:
Nota: la fine della seconda parte è imprecisa, come detto. Se un ragazzo di matematica potesse fornire una versione migliore, sarei grato.
Pensiamo alla quantità di dati coinvolti in una macchina X-bit (diciamo 32 o 64-bit), con record (valore e priorità) parole macchina larghe.P
Hai un set di potenziali record che è parzialmente ordinato: e ( a , 1 ) = ( a , 1 )(a,1)<(a,2)(a,1)=(a,1) ma non puoi confrontare e ( b , 1 ) .(a,1)(b,1)
Tuttavia, si desidera poter confrontare due valori non confrontabili dal proprio set di record, in base a quando sono stati inseriti. In modo da avere qui un altro insieme di valori: quelli che sono stati inseriti, e si vuole migliorare con un ordine parziale: se e solo se X è stato inserito prima Y .X<YXY
Nel peggiore dei casi, la memoria verrà riempita con i record del modulo (con ? Diverso per ognuno), quindi dovrai fare affidamento interamente sul tempo di inserimento per decidere quale va prima fuori.(?,1)?
- Il tempo di inserimento (rispetto ad altri record ancora nella struttura) richiede bit di informazione (con payload P-byte e 2 X byte di memoria accessibili).X−log2(P)2X
- Il payload (il valore e la priorità del tuo record) richiede parole macchina di informazioni.P
Ciò significa che devi in qualche modo memorizzare extra per ogni record memorizzato. E questo è O ( n ) per n record.X−log2(P)O(n)n
Ora, quante informazioni ci fornisce ogni "cella" di memoria?
- bit di dati ( W è la larghezza della parola macchina).WW
- bit di indirizzo.X
Supponiamo ora (il payload è largo almeno una parola macchina (di solito un ottetto)). Ciò significa che X - lP≥1 , in modo da poter adattare le informazioni sull'ordine di inserimento all'indirizzo della cella. Questo è ciò che accade in uno stack: le celle con l'indirizzo più basso sono entrate per prime nello stack (e usciranno per ultime).X−log2(P)<X
Quindi, per memorizzare tutte le nostre informazioni, abbiamo due possibilità:
- Memorizza l'ordine di inserimento nell'indirizzo e il payload in memoria.
- Conserva entrambi in memoria e lascia l'indirizzo libero per qualche altro utilizzo.
Ovviamente, per evitare sprechi, useremo la prima soluzione.
Ora per le operazioni. Suppongo che desideri avere:
- con O ( lInsert(task,priority) complessità temporale.O(logn)
- con O (StableExtractMin() complessità temporale.O(logn)
Diamo un'occhiata a :StableExtractMin()
L'algoritmo davvero molto generale va così:
- Trova il record con la priorità minima e il "tempo di inserimento" minimo in .O(logn)
- Rimuoverlo dalla struttura in .O(logn)
- Restituirlo.
Ad esempio, nel caso di un heap, sarà organizzato in modo leggermente diverso, ma il lavoro è lo stesso: 1. Trova il record minimo in
2. Rimuovilo dalla struttura in O ( 1 )
3. Correzione tutto in modo che la prossima volta # 1 e # 2 siano ancora O ( 1 ) cioè "ripari l'heap". Questo deve essere fatto in "O (log n)" 4. Restituisce l'elemento.0(1)O(1)O(1)
Tornando all'algoritmo generale, vediamo che per trovare il record nel tempo , abbiamo bisogno di un modo veloce per scegliere quello giusto tra 2 ( X - l o g 2 ( P ) ) candidati (peggio caso, la memoria è piena).O(logn)2(X−log2(P))
Ciò significa che dobbiamo memorizzare bit di informazioni al fine di recuperare quell'elemento (ogni bit taglia in due lo spazio candidato, quindi abbiamo bisezioni O ( l o g n ) , che significa O ( l oX−log2(P)O(logn) complessità temporale).O(logn)
Questi bit di informazioni potrebbero essere memorizzati come l'indirizzo dell'elemento (nell'heap, il min è a un indirizzo fisso) oppure, ad esempio con puntatori (in un albero di ricerca binario (con puntatori), è necessario seguire in media per arrivare al minuto).O(logn)
Ora, quando si elimina quell'elemento, avremo bisogno di aumentare il record minimo successivo in modo che abbia la giusta quantità di informazioni per consentire il recupero di prossima volta, cioè, quindi ha X - l o g 2 ( P ) frammenti di informazioni che la discriminano dagli altri candidati.O(logn)X−log2(P)
Cioè, se non ha già abbastanza informazioni, dovrai aggiungerne alcune. In un albero di ricerca binario (non bilanciato), le informazioni sono già lì: dovresti mettere un puntatore NULL da qualche parte per eliminare l'elemento e senza ulteriori operazioni, il BST è ricercabile in tempo in media.O(logn)
Dopo questo punto, è leggermente abbozzato, non sono sicuro di come formularlo. Ma ho la netta sensazione che ciascuno degli elementi rimanenti nel tuo set avrà bisogno di avere bit di informazioni che aiuteranno a trovare il prossimo min e aumentarlo con abbastanza informazioni in modo che possano essere trovate in O ( l o gX−log2(P) prossima volta.O(logn)
L'algoritmo di inserimento di solito ha solo bisogno di aggiornare parte di queste informazioni, non penso che costerà di più (dal punto di vista della memoria) per farlo funzionare velocemente.
Ciò significa che avremo bisogno di conservare più bit di informazioni per ciascun elemento. Quindi, per ogni elemento, abbiamo:X−log2(P)
- Il tempo di inserimento, bit.X−log2(P)
- Il carico utile parole della macchina P.P
- L'informazione "ricerca veloce", X−log2(P) bit .
Dato che utilizziamo già i contenuti della memoria per memorizzare il payload e l'indirizzo per memorizzare i tempi di inserimento, non ci resta spazio per memorizzare le informazioni di "ricerca rapida". Quindi dovremo allocare un po 'di spazio extra per ogni elemento, e quindi "sprecare" spazio extra.Ω(n)