Coda di priorità per priorità parzialmente ordinate con infima


16

Ho alcuni oggetti con priorità di tipo composto ed è solo parzialmente ordinato . Devo selezionare gli oggetti in ordine di questa priorità (ovvero resa minima ogni volta articolo ). Ma piuttosto che completare arbitrariamente l'ordine, preferirei che la coda fosse stabile, nel senso che se c'è più di un elemento minimo, dovrebbe restituire prima il più vecchio.

Esiste una struttura di dati heap che funzionerebbe con l'ordinamento parziale? O una modifica della normale coda di priorità per lavorare con essa? La scelta comune per l'algoritmo di cui ho bisogno è un semplice heap binario o 4-ary, ma non funziona con l'ordinamento parziale.

I valori di priorità supportano:

  1. L'ordinamento parziale mediante l'operazione a b è falso e b a è anche falso. Scrivo un ̸ b in quel caso. . È un ordinamento parziale, quindi è possibile cheabbaa⋚̸b
  2. inf(xi)yyxinO(n)
  3. È possibile definire un'estensione lineare per l'ordinamento parziale. Usarlo per la coda di priorità è la via d'uscita facile in quanto l'algoritmo funziona in questo modo. Ma l'ordine influenza le prestazioni e l'ordine di inserimento sembra che dovrebbe essere il migliore per evitare i casi peggiori.

Inoltre, l'algoritmo in cui desidero utilizzarlo deve conoscere l'influenza di tutte le priorità in coda.

Le priorità hanno un significato nel mondo reale, ma sono soggette a cambiamenti, quindi non sembra fattibile fare affidamento su altre proprietà che potrebbero avere.


Nota: gli heap binari non funzionano con l'ordinamento parziale. Assumere un mucchio binario con , e , dove e e . Sono posizionati in quell'ordine, quindiabcaca⋚̸ba⋚̸c

     a (0)
   /   \
 b (1)   c (2)

ora viene inserito d . La prossima posizione libera è 3, il figlio sinistro di , quindi otteniamob

        a (0)
      /   \
    b (1)   c (2)
  /
d (3)

Se (che implica dalla transitività, ma non dice nulla su e ) e , allora non viene scambiato con , perché non è inferiore. Ma in realtà è meno di , ma non è confrontato con esso, quindi ora l'invariante dell'heap principale non regge; la parte superiore non è minima.dadcdbd⋚̸bdba

Sospetto che una foresta di cumuli in qualche modo nello stile del mucchio binomiale possa funzionare. Fondamentalmente è importante confrontare sempre nuovi valori con root e collegare solo elementi comparabili. Renderebbe gli alberi nella foresta dimensionati casualmente e quindi la complessità dipenderà dal numero di insiemi reciprocamente incomparabili nell'heap. Sospetto in qualche modo che la complessità non possa essere risolta (dobbiamo continuare a confrontare fino a quando non raggiungiamo un elemento comparabile) Potrei aver perso qualcosa, quindi lascio questo aperto.


Nota: l'ordinamento è parziale e mentre ci sono modi per definirne un'estensione lineare, aggiungere un timestamp e usarlo come criterio secondario non è uno di questi. Supponiamo di aver assegnato il timestamp per ogni e definito l'ordinamento come iff o ( et . Quindi supponiamo di avere distinto , , , tale che e . Quindi a t(a)aababbat(a)t(b)abct(a)t(b)t(c)ca e b c , ma c a , quindi la relazione non è transitiva e quindi non è affatto un ordinamento. Questo tipo di estensione funziona solo per ordini deboli, ma non parziali.abbcca


Modifica: mi sono reso conto che non solo è definito un infimo di qualsiasi set, ma in realtà devo essere in grado di ottenere in modo efficiente infimo di elementi attualmente in coda. Quindi sto ora valutando se l'aggiunta di nodi speciali contenenti infima di sottostrutture ad una struttura heap comune sarebbe di aiuto.


Hai considerato una coda di priorità indicizzata?

@hulkmeister: Potresti spiegare come l'indicizzazione della coda faccia funzionare l'ordinamento parziale (no, l'heap binario normale non funziona con l'ordinamento parziale)?

1
Il mio pensiero era che quando due elementi sono incomparabili, è possibile utilizzare l'indice per tenere traccia dell'ordine di inserimento. Quindi componi la priorità con l'indice e hai chiavi univoche che sono comparabili anche quando la priorità non lo è. Se questo suona come quello che vuoi, posso inserirlo in una risposta completa.

1
@hulkmeister: beh, il problema è molto più profondo di così. Quando viene inserito un nuovo elemento, la coda di priorità normalmente lo confronta con alcuni elementi. Ma se sono incomparabili, semplicemente non sa dove inserirlo. E la disambiguazione con l'indice non funzionerà, perché l'indice cambia e perché probabilmente non darebbe un ordinamento totale coerente con la priorità comunque.

Puoi fare qualche esempio di questo tipo composto e quando è incomparabile? È possibile considerare uguali questi valori "incomparabili"? In tal caso, è possibile memorizzarli nello stesso nodo in ordine di inserimento.

Risposte:


3

Anche se il problema esatto posto nella domanda originale sembra essere difficile (e sarei interessato a una soluzione a quel problema, in particolare la parte di ricerca dell'infima). Volevo solo notare che se l'insieme parzialmente ordinato è effettivamente costituito da vettori che utilizzano un ordine di prodotto e se è sufficiente avere la garanzia che la coda prioritaria restituisca i valori in un ordine "compatibile" con l'ordine parziale ( cioè, gli elementi più piccoli vengono sempre restituiti prima di elementi più grandi), quindi c'è un modo abbastanza semplice per farlo.

L'idea è essenzialmente quella di trovare un ordinamento topologico dell'insieme parzialmente ordinato. Cioè, un ordine totale ' ' tale che abT . Per i vettori che utilizzano un ordine di prodotto, questo è abbastanza semplice: basta usare un ordine lessicografico 'S ', dove il primo "componente" è la somma di tutti i componenti utilizzati per l'ordine del prodotto (il resto dei componenti è essenzialmente arbitrario, quindi potresti anche attenerti a un ordine debole). Possiamo quindi vedere che a < babaTbS e a = b

a<bi(aibi) and i(ai<bi)(iai)<(ibi)aSb
e quindi che ab
a=bi(ai=bi)(iai)=(ibi)aSb,
. Possiamo quindi utilizzare questo ordine con una coda prioritaria ed essere sicuri che gli elementi più piccoli (nell'ordine del prodotto) verranno sempre estratti prima degli elementi più grandi.abaSb

Ci sono molte altre opzioni. Utilizzando almeno uno dei componenti, minimo, massimo, qualsiasi combinazione lineare con coefficienti non negativi. La scelta dell'estensione influisce sulla velocità con cui l'algoritmo di sovrapposizione sarà.
Jan Hudec,

2

Cosa c'è di sbagliato nel completare il tuo ordine parziale?

Ma piuttosto che completare arbitrariamente l'ordine, preferirei che la coda fosse stabile, nel senso che se c'è più di un elemento minimo, dovrebbe restituire prima il più vecchio.

Se preferisci "prima i più vecchi", il tuo ordine sarà effettivamente completato; gli articoli "incomparabili" sono comparabili per età.

Aggiungi un timestamp (o qualsiasi altro numero intero in crescita monotona) a ciascun elemento e usalo se il confronto "reale" è impossibile.


3
Sarebbe bello se si potesse fare un'estensione lineare dell'ordine parziale. Ma non lo è. Diamo 3 valori distinti, inseriti in ordine a , b , c , tali che c ≤ a e b è incomparabile con entrambi. L'estensione con riempimenti timestamp in una 'b ≤ e b ≤' c , così da transitività ora una dovrebbe essere inferiore a C , ma che contraddice l'ordinamento effettivo.

Forse l'hai confuso con un ordine debole. In ordine debole gli elementi incomparabili formano classi di equivalenza, quindi puoi aggiungere criteri aggiuntivi arbitrari. Per ordini parziali non è possibile.

1

EDIT: questo sembra essere un problema interessante, e ho avuto una piccola ricerca al riguardo. Ti suggerisco di leggere quanto segue:

  1. Darell Raymond. Database di ordini parziali, tesi di dottorato, Università di Waterloo.

Ti suggerisco di leggere questo documento: Daskalakis, Constantinos, et al. "Ordinamento e selezione in poset." SIAM Journal on Computing 40.3 (2011): 597-622.

Gli autori presentano qui una struttura di dati chiamata ChainMerge che accetta un poset e una scomposizione a catena del poset in chain. La dimensione della struttura dei dati è O ( n q ) . Gli autori presentano un algoritmo per trovare le minimas che gira in O ( w n ) dove w è un limite superiore della larghezza del poset. .. Ho pensato che forse questo è interessante.qO(nq)O(wn)w

Nota: ho eliminato una precedente risposta ingenua. Fai clic su Modifica per vederlo.


0

Il mio uso della terminologia potrebbe essere errato. Modifica direttamente la mia risposta per risolvere eventuali problemi riscontrati.


Innanzitutto, dagli input devono essere rilevati insiemi reciprocamente incomparabili.

Ad esempio, potrebbero esserci 5 oggetti a, b, c, d, e, ma il loro ordinamento parziale forma due grafici disconnessi:

  • a ≤ b ≤ c
  • d ≤ e
  • ma nessuno dei {a, b, c}è incomparabile con nessuno dei {d, e}.

Questi insiemi reciprocamente incomparabili devono essere rilevati per primi, prima che gli oggetti possano essere archiviati in una struttura dati appropriata. Questo può essere fatto con un algoritmo di ricerca di Union


Per efficienza, l'inserimento di un nuovo oggetto deve avere un modo efficiente di trovare "l'elenco di oggetti esistenti che sono comparabili con questo nuovo oggetto".


Ora, all'interno di ciascun sottoinsieme (rispettivamente {a, b, c}e {d, e}), i minimi dovrebbero essere ben definiti. (Per ogni sottoinsieme possono esserci uno o più minimi, a causa di un ordinamento parziale.)

Vedo questo come un grafico aciclico diretto . Cercare di inserirlo in un mucchio sembra disastroso.


Per estrarre i minimi da questa struttura di dati compositi, il passo successivo è quello di ottenere l'elenco di tutti i minimi da tutti i sottoinsiemi, selezionare quello con il timestamp più antico e rimuovere e restituire questo oggetto.


Purtroppo non vedo il modo di trovare in modo efficiente l'elenco di oggetti comparabili.

Un set parzialmente ordinato può infatti essere visto come grafico aciclico diretto. Ma uno dato dalla tabella di adiacenza (funzione, in realtà) piuttosto che dall'elenco di adiacenza. Trovare i minimi di poset forniti dall'elenco di adiacenza è facile, ma per la tabella di adiacenza è un problema.

I minima sono ben definiti anche nel set originale. Non vedo come trovare i componenti collegati possa aiutare, dal momento che non sono grafici completi.

1
Sembrate supporre che il diagramma di Hasse sia una foresta di alberi unari (equivalentemente grafici di percorso), ma la domanda afferma già che si tratta di un ordine di prodotto, quindi di un reticolo multidimensionale.
Peter Taylor,

0

Un progetto a cui sto lavorando comporta un problema simile (per inciso utilizzo anche l'ordine parziale dei vettori). Avevamo già un algoritmo quadratico per l'ordinamento di un elenco ordinato in modo casuale e ho sviluppato un algoritmo di inserimento osservandone il comportamento quando un solo oggetto era fuori servizio. Non sappiamo se questa sia l'implementazione più veloce possibile.

Ecco alcuni pseudocodici.

class PartialOrderPriorityQueue
   q <- empty list
   method insert (n):
     for i <- 0 to (q.length - 1):
       if q[i] <= n:
         t <- q[i]
         q[i] <- n
         n <- t
     q.append(n)

   method pop():
     return q.remove(0)

-1

Il normale comportamento dell'heap consiste nell'aggiungere il nuovo valore nella parte posteriore e quindi setacciare mentre confronta più grande del suo genitore.

Se si scrive un confronto che restituisce lo stesso per genitore e figlio non è un caso comparabile in quanto per genitore è maggiore di figlio , il setacciamento dovrebbe comunque terminare al punto giusto.

Conta come un ordine sufficientemente stabile per i tuoi scopi?


Per chiarire, prendi l'esempio dal tuo commento: a> b , e c non è paragonabile a a o b :

  • a quindi b quindi c => a, b, c ... questo è già in ordine heap e nulla si sposta mai nel setaccio
  • b, a, c => a, b, c ... a è setacciato nella posizione corretta, e di nuovo siamo nell'ordine di heap corretto
  • a, c, b => a, c, b ... b non può setacciare perché non è paragonabile a c, ma questo li lascia nell'ordine FIFO come hai chiesto
  • c, b, a => c, a, b ... a e b sono nell'ordine relativo corretto, ma nessuno dei due può superare c perché non può essere confrontato con esso

quindi, il risultato dipende dall'ordine di inserimento - questo sembra corrispondere a quello che chiedi, ma non sono sicuro che sia davvero quello che vuoi. In caso contrario, potresti mostrare il risultato che speravi di vedere?


OK, quindi dal tuo commento (e dalla modifica alla tua domanda), vuoi elementi "comparabili" per scavalcare quelli "non comparabili" e trovare il posto giusto sotto l'ordinamento, se ce n'è uno. Ho chiesto questo perché non ero sicuro di come interpretare

se alcuni elementi sono incomparabili, li restituisce nell'ordine in cui sono stati inseriti

(d e b sono incomparabili in coppia nella tua modifica, ma non li vuoi nell'ordine in cui sono stati inseriti).

La mia prossima domanda sarebbe stata sulla relazione tra gli elementi "comparabili" e "non comparabili", ma vedo che hai rivelato ora che sono vettori nell'ordine del prodotto (non era chiaro se alcuni elementi fossero accoppiati- incomparabile con tutto , come NaN, o cosa).

Quindi, se prendo il tuo nuovo esempio e assegno valori vettoriali, è corretto che questo sia un esempio in cui b non è paragonabile a nient'altro:

        a (1,1)
      /      \
    b (0,4)   c (3,3)
  /
d (2,2)

e dovrebbe ordinare in questo modo:

        a (1,1)
      /      \
    d (2,2)   c (3,3)
  /
b (0,4)

?


Ho detto esplicitamente nella domanda che non funzionerà, perché pensavo di avere un contro-esempio, ma non ne sono così sicuro ora. Puoi provare che tale coda sarebbe valida (per la cancellazione, inserire e aggiornare anche)? E ricorda, è possibile che a ≤ b , ma c non sia paragonabile (e quindi confronterebbe "uguale" con la regola sopra) con nessuno dei due.

Bene, questa non è ancora una prova. Non preoccuparti ancora dell'ordine e prova che tale heap ha sempre un elemento minimo nella parte superiore (nota: (più) convenzione comune e la necessità effettiva dell'algoritmo è minima nella parte superiore, quindi se a> b , b viene prima di tutto ).

In realtà sospetto che ci sia un contro-esempio. Supponiamo che a , b e c siano nell'heap, a ≤ b e a ≤ c , a è in alto, b è figlio a sinistra, c è figlio a destra. Ora d arriva che d ≤ c e incomparabile con a e b . È inserito come figlio di b , non è inferiore e rimane lì. Ora arriva e che è c ≤ e (quindi anche a ≤ e ) e incomparabile a b . Quindi e entra come figlio giusto di be rimane. Ora estrae un (OK, a è minimo), e viene scambiato al suo posto e setacciato verso il basso. È incomparabile b , ma inferiore a c , quindi scambia con c . Ora estrarre c , SBAGLIATO , d ≤ c .

Se trovi un errore nel commento precedente (che dovrebbe avere una forma di disuguaglianza che deve reggere a causa della transitività e l'ho perso), avresti ancora una possibilità. Altrimenti non funzionerà.

1
Ok, contro-esempio ancora più semplice. Supponiamo che a , b e c siano nell'heap, a ≤ c , b è incomparabile con nessuno dei due. a è in alto, b è figlio a sinistra, c è figlio a destra. d entra in modo che d ≤ a (quindi d ≤ c ) e incomparabile con b . Il prossimo slot libero è come il figlio sinistro di b e d è incomparabile, quindi rimane lì. Ora estrae a , SBAGLIATO , d ≤ a . Si noti che se ≤ co no, non importa, la situazione è la stessa se fossero incomparabili.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.