📄 heap.java
字号:
/* * Copyright (c) 2001 The Anthill Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 2 as * published by the Free Software Foundation. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */package peersim.edsim;import peersim.core.Node;import peersim.core.CommonState;import peersim.config.Configuration;import peersim.config.IllegalParameterException;/** * The Heap data structure used to maintain events "sorted" by * scheduled time and to obtain the next event to be executed. * * @author Alberto Montresor * @version $Revision: 1.10 $ */public class Heap implements PriorityQ {//--------------------------------------------------------------------------// Constants//--------------------------------------------------------------------------/** * This parameter specifies how many * bits are used to order events that occur at the same time. Defaults * to 8. A value smaller than 8 causes an IllegalParameterException. * Higher values allow for a better discrimination, but reduce * the maximal time steps that can be simulated. * @config */ private static final String PAR_PBITS = "pbits";private static final String PAR_PBITS_LEGACY = "simulation.timebits";/** * Specifies the initial capacity of the heap. Defaults to 65536. * @config */ private static final String PAR_SIZE = "size";//--------------------------------------------------------------------------// Fields//--------------------------------------------------------------------------// The following arrays are four heaps ordered by time. The alternative// approach (i.e. to store event objects) requires much more memory,// and based on some tests that I've done is not really much faster./** Event component of the heap */private Object[] events;/** Time component of the heap */private long[] times;/** Node component of the heap */private Node[] nodes;/** Pid component of the heap */private byte[] pids;/** Number of elements */private int size;/** Singleton event object used to return (event, time, node, pid) tuples */private final Event ev = new Event();/** The number of bits reserved to order event with the same timestamp */private final int pbits;/** The mask to test whether the time value fits into the range we canrepresent */private final long overflowMask;//--------------------------------------------------------------------------// Contructor//--------------------------------------------------------------------------/** * Initializes a new heap using defaults. */public Heap() { this(""); // "" is not a valid prefix for a component}//--------------------------------------------------------------------------/** * Initializes a new heap using the configuration. */public Heap(String prefix) { int size = Configuration.getInt(prefix+"."+PAR_SIZE,65536); // some complex stuff to deal with legacy parameter names... if( !Configuration.contains(PAR_PBITS_LEGACY) ) pbits = Configuration.getInt(prefix+"."+PAR_PBITS,8); else { pbits = Configuration.getInt(PAR_PBITS_LEGACY); if( Configuration.contains(prefix+"."+PAR_PBITS) ) throw new IllegalParameterException(PAR_PBITS_LEGACY, "Your configuration file contains both "+ prefix+"."+PAR_PBITS+ " and "+ PAR_PBITS_LEGACY+"; please remove "+ PAR_PBITS_LEGACY); } if (pbits < 8 || pbits >= 31) { throw new IllegalParameterException(prefix+"."+PAR_PBITS, "This parameter should be >= 8 or < 31"); } overflowMask = ~maxTime(); events = new Object[size]; times = new long[size]; nodes = new Node[size]; pids = new byte[size];}//--------------------------------------------------------------------------// Methods//--------------------------------------------------------------------------/** * Returns the current number of events in the system. */public int size(){ return size;}//--------------------------------------------------------------------------/** * Add a new event, to be scheduled at the specified time. * * @param time the time at which this event should be scheduled * @param event the object describing the event * @param node the node at which the event has to be delivered * @param pid the protocol that handles the event */public void add(long time, Object event, Node node, byte pid) { add(time,event,node,pid,CommonState.r.nextInt(1 << pbits));}//--------------------------------------------------------------------------/** * Add a new event, to be scheduled at the specified time. * * @param time the time at which this event should be scheduled * @param event the object describing the event * @param node the node at which the event has to be delivered * @param pid the protocol that handles the event */public void add(long time, Object event, Node node, byte pid, long priority) { if( (time&overflowMask) != 0 ) throw new IllegalArgumentException("Time overflow: time="+time);//XXX should we test priority overflow? How much does it cost? time = (time << pbits) | priority; size++; int pos = size; put(pos, time, event, node, pid); while (pos > 1 && getTime(pos / 2) > time) { swap(pos, pos / 2); pos = pos / 2; }}//--------------------------------------------------------------------------/** * Removes the first event in the heap and returns it. * Note that, to avoid garbage collection, a singleton instance of * the Event class is used. This means that data contained in the * returned event are overwritten when a new invocation of this * method is performed. * @return first event or null if size is zero */public Event removeFirst() { if(size==0) return null; ev.time = times[0] >> pbits; ev.event = events[0]; ev.node = nodes[0]; ev.pid = pids[0]; swap(1, size); size--; minHeapify(1); return ev;}//--------------------------------------------------------------------------public long maxTime() { return Long.MAX_VALUE >> pbits; }//--------------------------------------------------------------------------public long maxPriority() { return (1L << pbits)-1; }//--------------------------------------------------------------------------/** * Prints the time values contained in the heap. */public String toString(){ StringBuffer buffer = new StringBuffer(); buffer.append("[Size: " + size + " Times: "); for (int i=1; i <= size; i++) { buffer.append(getTime(i)+","); } buffer.append("]"); return buffer.toString();}//--------------------------------------------------------------------------// Private methods//--------------------------------------------------------------------------/** * */private void minHeapify(int index) { // The time to be placed of the current node long time = getTime(index); // Left, right children of the current index int l,r; // Their associated time long lt, rt; // The minimum time between val, lt, rt long mintime; // The index of the mininum time int minindex = index; do { index = minindex; mintime = time; l = index << 1; r = l + 1; if (l <= size && (lt = getTime(l)) < mintime) { minindex = l; mintime = lt; } if (r <= size && (rt = getTime(r)) < mintime) { minindex = r; mintime = rt; } if (minindex != index) { swap(minindex, index); } } while (minindex != index);}//--------------------------------------------------------------------------/** * */private void swap(int i1, int i2) { i1--; i2--; Object te = events[i1]; events[i1] = events[i2]; events[i2] = te; long tt = times[i1]; times[i1] = times[i2]; times[i2] = tt; Node tn = nodes[i1]; nodes[i1] = nodes[i2]; nodes[i2] = tn; byte tp = pids[i1]; pids[i1] = pids[i2]; pids[i2] = tp;}//--------------------------------------------------------------------------/** * */private long getTime(int index) { /* Compute first and second index, and return the value */ index--; return times[index];}//--------------------------------------------------------------------------/** * */private void put(int index, long time, Object event, Node node, byte pid) { index--; if (index >= events.length) { doubleCapacity(); } events[index] = event; times[index] = time; nodes[index] = node; pids[index] = pid;}//--------------------------------------------------------------------------/** * */private void doubleCapacity() { int oldsize = events.length; int newsize = oldsize*2; Object[] te = new Object[newsize]; System.arraycopy(events, 0, te, 0, oldsize); events = te; long[] tt = new long[newsize]; System.arraycopy(times, 0, tt, 0, oldsize); times = tt; Node[] tn = new Node[newsize]; System.arraycopy(nodes, 0, tn, 0, oldsize); nodes = tn; byte[] tp = new byte[newsize]; System.arraycopy(pids, 0, tp, 0, oldsize); pids = tp;}//--------------------------------------------------------------------------// Testing//--------------------------------------------------------------------------/*public static void main(String[] args) { Random random = new Random(); Heap heap = new Heap(); int rep = 1000000; if( args.length > 0 ) rep = Integer.parseInt(args[0]); int[] values1 = new int[rep]; long[] values2 = new long[rep]; for (int i = 0; i < rep; i++) { values1[i] = random.nextInt(1000000000); } long time1 = System.currentTimeMillis(); for (int i = 0; i < rep; i++) { heap.add(values1[i], null, null, (byte) 1); } long time2 = System.currentTimeMillis(); System.out.println("Inserting: " + (time2-time1)); time1 = System.currentTimeMillis(); for (int i = 0; i < rep; i++) { values2[i] = heap.removeFirst().time; } time2 = System.currentTimeMillis(); System.out.println("Removing: " + (time2-time1)); Arrays.sort(values1); for (int i=0; i<rep; i++) { if (values1[i] != values2[i]) System.out.print("+"); }}*/} // END Heap
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -