All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.graphalgo.impl.util.PriorityMap Maven / Gradle / Ivy

There is a newer version: 5.26.1
Show newest version
/*
 * Copyright (c) 2002-2016 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.graphalgo.impl.util;

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

public class PriorityMap
{
    public interface Converter
    {
        T convert( S source );
    }

    public static final class Entry
    {
        private final E entity;
        private final P priority;

        private Entry( E entity, P priority )
        {
            this.entity = entity;
            this.priority = priority;
        }

        Entry( Node node )
        {
            this( node.head.entity, node.head.priority );
        }

        public E getEntity()
        {
            return entity;
        }

        public P getPriority()
        {
            return priority;
        }
    }

    @SuppressWarnings( "rawtypes" )
    private static final Converter SELF_KEY = new Converter()
    {
        @Override
        public Object convert( Object source )
        {
            return source;
        }
    };
    @SuppressWarnings( "unchecked" )
    public static  PriorityMap withSelfKey(
            Comparator

priority ) { return new PriorityMap( SELF_KEY, priority, true ); } private static class NaturalPriority

> implements Comparator

{ private final boolean reversed; NaturalPriority( boolean reversed ) { this.reversed = reversed; } @Override public int compare( P o1, P o2 ) { return reversed ? o2.compareTo( o1 ) : o1.compareTo( o2 ); } } public static > PriorityMap withNaturalOrder( Converter key ) { return PriorityMap.withNaturalOrder( key, false ); } public static > PriorityMap withNaturalOrder( Converter key, boolean reversed ) { return withNaturalOrder( key, reversed, true ); } public static > PriorityMap withNaturalOrder( Converter key, boolean reversed, boolean onlyKeepBestPriorities ) { Comparator

priority = new NaturalPriority

( reversed ); return new PriorityMap( key, priority, onlyKeepBestPriorities ); } public static > PriorityMap withSelfKeyNaturalOrder() { return PriorityMap.withSelfKeyNaturalOrder( false ); } public static > PriorityMap withSelfKeyNaturalOrder( boolean reversed ) { return PriorityMap.withSelfKeyNaturalOrder( reversed, true ); } @SuppressWarnings( "unchecked" ) public static > PriorityMap withSelfKeyNaturalOrder( boolean reversed, boolean onlyKeepBestPriorities ) { Comparator

priority = new NaturalPriority

( reversed ); return new PriorityMap( SELF_KEY, priority, onlyKeepBestPriorities ); } private final Converter keyFunction; private final Comparator

order; private final boolean onlyKeepBestPriorities; public PriorityMap( Converter key, Comparator

priority, boolean onlyKeepBestPriorities ) { this.keyFunction = key; this.order = priority; this.onlyKeepBestPriorities = onlyKeepBestPriorities; } /** * Add an entity to the priority map. If the key for the {@code entity} * was already found in the priority map and the priority is the same * the entity will be added. If the priority is lower the existing entities * for that key will be discarded. * * @param entity the entity to add. * @param priority the priority of the entity. * @return whether or not the entity (with its priority) was added to the * priority map. Will return {@code false} iff the key for the entity * already exist and its priority is better than the given * {@code priority}. */ public boolean put( E entity, P priority ) { K key = keyFunction.convert( entity ); Node node = map.get( key ); boolean result = false; if ( node != null ) { // it already existed if ( onlyKeepBestPriorities ) { if ( order.compare( priority, node.head.priority ) == 0 ) { // ...with same priority => add as a candidate first in chain node.head = new Link( entity, priority, node.head ); result = true; } else if ( order.compare( priority, node.head.priority ) < 0 ) { // ...with lower (better) priority => this new one replaces any existing queue.remove( node ); putNew( entity, priority, key ); result = true; } } else { // put in the appropriate place in the node linked list if ( order.compare( priority, node.head.priority ) < 0 ) { // ...first in chain and re-insert to queue node.head = new Link( entity, priority, node.head ); reinsert( node ); result = true; } else { // we couldn't add it first in chain, go look for the appropriate place Link link = node.head, prev = link; // skip the first one since we already compared head link = link.next; while ( link != null ) { if ( order.compare( priority, link.priority ) <= 0 ) { // here's our place, put it // NODE ==> N ==> N ==> N prev.next = new Link( entity, priority, link ); result = true; break; } prev = link; link = link.next; } if ( !result ) { // not added so append last in the chain prev.next = new Link( entity, priority, null ); result = true; } } } } else { // Didn't exist, just put putNew( entity, priority, key ); result = true; } return result; } private void putNew( E entity, P priority, K key ) { Node node = new Node( new Link( entity, priority, null ) ); map.put( key, node ); queue.add( node ); } private void reinsert( Node node ) { queue.remove( node ); queue.add( node ); } /** * Get the priority for the entity with the specified key. * * @param key the key. * @return the priority for the the entity with the specified key. */ public P get( K key ) { Node node = map.get( key ); return node != null ? node.head.priority : null; } /** * Remove and return the entry with the highest priority. * * @return the entry with the highest priority. */ public Entry pop() { Node node = queue.peek(); Entry result = null; if ( node == null ) { // Queue is empty return null; } else if ( node.head.next == null ) { // There are no more entries attached to this key // Poll from queue and remove from map. node = queue.poll(); map.remove( keyFunction.convert( node.head.entity ) ); result = new Entry( node ); } else { result = new Entry( node ); node.head = node.head.next; if ( order.compare( result.priority, node.head.priority ) == 0 ) { // Can leave at front of queue as priority is the same // Do nothing } else { // node needs to be reinserted into queue reinsert( node ); } } return result; } public Entry peek() { Node node = queue.peek(); if ( node == null ) { return null; } return new Entry( node ); } // Naive implementation private final Map> map = new HashMap>(); private final PriorityQueue> queue = new PriorityQueue>( 11, new Comparator>() { @Override public int compare( Node o1, Node o2 ) { return order.compare( o1.head.priority, o2.head.priority ); } } ); private static class Node { private Link head; Node( Link head ) { this.head = head; } } private static class Link { private final E entity; private final P priority; private Link next; Link( E entity, P priority, Link next ) { this.entity = entity; this.priority = priority; this.next = next; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy