View Javadoc

1   /*
2    * Copyright (c) 2003-2008 by Cosylab d. d.
3    *
4    * This file is part of Java-Common.
5    *
6    * Java-Common is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * Java-Common is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with Java-Common.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  package com.cosylab.util;
21  
22  /**
23   * Simple heap implementation. This implementation uses <code>Comparable</code>
24   * interface to maintain ascending order. Heap will grow and shrink based on
25   * number of elements. If total number of elements equals internal array size,
26   * this array is expanded by factor of 2. If number of elements is less than
27   * one quarter the array size, array will be shrunk to by half.<br>
28   * Implementation is synchronized and can be considered thread-safe.
29   *
30   * @author <a href="mailto:ales.pucelj@cosylab.com">Ales Pucelj</a>
31   * @version $id$
32   */
33  public class Heap
34  {
35  	/*
36  	 * Internal array of elements.
37  	 */
38  	private Comparable[] elements;
39  
40  	/*
41  	 * Number of elements in heap.
42  	 */
43  	private int size;
44  
45  	/**
46  	 * Default constructor for Heap(). Creates new heap with 16 elements.
47  	 */
48  	public Heap()
49  	{
50  		this(16);
51  	}
52  
53  	/**
54  	 * Alternate constructor for heap that allows specification of initial
55  	 * size.
56  	 *
57  	 * @param initialSize
58  	 */
59  	public Heap(int initialSize)
60  	{
61  		elements = new Comparable[Math.max(8, initialSize)];
62  	}
63  
64  	/**
65  	 * Calculates optimal size.
66  	 *
67  	 * @return optimal size for this heap.
68  	 */
69  	private int getOptimalSize()
70  	{
71  		int n = elements.length;
72  
73  		if (size == n) {
74  			return 2 * n;
75  		}
76  
77  		if (n < 8) {
78  			return size;
79  		}
80  
81  		if (size < n / 4) {
82  			return n / 2;
83  		}
84  
85  		return size;
86  	}
87  
88  	/**
89  	 * Checks the size of the internal array and adjusts it if neccessary.
90  	 */
91  	private void checkSize()
92  	{
93  		int n = getOptimalSize();
94  
95  		if (n == size) {
96  			return;
97  		}
98  
99  		Comparable[] newElements = new Comparable[n];
100 
101 		for (int i = 0; i < size; i++) {
102 			newElements[i] = elements[i];
103 		}
104 
105 		elements = newElements;
106 	}
107 
108 	/**
109 	 * Adds new element to the heap.
110 	 *
111 	 * @param c Element to add.
112 	 */
113 	public synchronized void add(Comparable c)
114 	{
115 		checkSize();
116 
117 		int curr = size;
118 		int parent = (size + 1) / 2 - 1;
119 
120 		while ((parent >= 0) && (elements[parent].compareTo(c) > 0)) {
121 			elements[curr] = elements[parent];
122 			curr = parent;
123 			parent = (parent + 1) / 2 - 1;
124 		}
125 
126 		elements[curr] = c;
127 
128 		size++;
129 	}
130 
131 	/**
132 	 * Helper routine used be remove.
133 	 *
134 	 * @param index Index of the element.
135 	 *
136 	 * @return Largest of the children for the element at index or -1 if
137 	 *         invalid.
138 	 */
139 	private int getChild(int index)
140 	{
141 		int left = 2 * index + 1;
142 		int right = 2 * index + 2;
143 
144 		if (right < size) {
145 			if (elements[left].compareTo(elements[right]) < 0) {
146 				return left;
147 			} else {
148 				return right;
149 			}
150 		}
151 
152 		if (left < size) {
153 			return left;
154 		}
155 
156 		return -1;
157 	}
158 
159 	/**
160 	 * Removes smallest element.
161 	 *
162 	 * @return Element or null if empty.
163 	 */
164 	public synchronized Comparable remove()
165 	{
166 		if (size == 0) {
167 			return null;
168 		}
169 
170 		Comparable result = elements[0];
171 
172 		int curr = 0;
173 		int child = getChild(curr);
174 
175 		Comparable last = elements[size - 1];
176 
177 		while ((child > -1) && (elements[child].compareTo(last) < 0)) {
178 			elements[curr] = elements[child];
179 			curr = child;
180 			child = getChild(curr);
181 		}
182 
183 		elements[curr] = last;
184 		size--;
185 
186 		return result;
187 	}
188 
189 	/**
190 	 * Returns element at index.
191 	 *
192 	 * @param index Index of the element.
193 	 *
194 	 * @return synchronized
195 	 */
196 	public synchronized Comparable get(int index)
197 	{
198 		return elements[index];
199 	}
200 
201 	/**
202 	 * Size of the heap.
203 	 *
204 	 * @return synchronized
205 	 */
206 	public synchronized int size()
207 	{
208 		return size;
209 	}
210 
211 	/**
212 	 * True if heap is empty.
213 	 *
214 	 * @return synchronized
215 	 */
216 	public synchronized boolean isEmpty()
217 	{
218 		return size == 0;
219 	}
220 
221 	/**
222 	 * Returns smallest element or null if empty.
223 	 *
224 	 * @return synchronized
225 	 */
226 	public synchronized Comparable getFirst()
227 	{
228 		if (isEmpty()) {
229 			return null;
230 		}
231 
232 		return elements[0];
233 	}
234 
235 	/**
236 	 * DOCUMENT ME!
237 	 *
238 	 * @return DOCUMENT ME!
239 	 */
240 	public synchronized String toString()
241 	{
242 		StringBuffer sb = new StringBuffer(size() * 5);
243 		sb.append("Heap = { ");
244 
245 		int n = Math.min(size, 30);
246 		boolean first = true;
247 
248 		for (int i = 0; i < n; i++) {
249 			if (first) {
250 				first = false;
251 			} else {
252 				sb.append(", ");
253 			}
254 
255 			sb.append(elements[i]);
256 		}
257 
258 		sb.append(" }");
259 
260 		return sb.toString();
261 	}
262 
263 	/**
264 	 * Run test applet.
265 	 *
266 	 * @param args command line parameters
267 	 */
268 	public static void main(String[] args)
269 	{
270 		Heap h = new Heap();
271 
272 		for (int k = 0; k < 3; k++) {
273 			for (int i = 0; i < 10; i++) {
274 				h.add(new Integer((int)(Math.random() * 100.0)));
275 			}
276 
277 			System.out.println(h.toString());
278 
279 			for (int i = 0; i < 5; i++) {
280 				System.out.print(h.remove() + " ");
281 			}
282 
283 			System.out.println();
284 		}
285 	}
286 }
287 
288 /* __oOo__ */