Revision 11451

View differences:

trunk/libraries/libIverUtiles/src/com/iver/utiles/search/BinarySearchUsingFirstCharacters.java
1
package com.iver.utiles.search;
2

  
3
import java.util.ArrayList;
4
import java.util.Arrays;
5
import java.util.Comparator;
6
import java.util.List;
7
import java.util.Vector;
8

  
9
import com.iver.utiles.MathExtension;
10

  
11
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
12
 *
13
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
14
 *
15
 * This program is free software; you can redistribute it and/or
16
 * modify it under the terms of the GNU General Public License
17
 * as published by the Free Software Foundation; either version 2
18
 * of the License, or (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU General Public License
26
 * along with this program; if not, write to the Free Software
27
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
28
 *
29
 * For more information, contact:
30
 *
31
 *  Generalitat Valenciana
32
 *   Conselleria d'Infraestructures i Transport
33
 *   Av. Blasco Ib??ez, 50
34
 *   46010 VALENCIA
35
 *   SPAIN
36
 *
37
 *      +34 963862235
38
 *   gvsig@gva.es
39
 *      www.gvsig.gva.es
40
 *
41
 *    or
42
 *
43
 *   IVER T.I. S.A
44
 *   Salamanca 50
45
 *   46005 Valencia
46
 *   Spain
47
 *
48
 *   +34 963163400
49
 *   dac@iver.es
50
 */
51

  
52
/**
53
 * This class has static methods that return items that their beginning text value matches with a text pattern. <br>
54
 * It's necessary that items of the parameter array (Vector) were sort ordered according to their text value. <br>
55
 * Supports Vectors with and without repeated items.
56
 * 
57
 * There are four methods, that are a modification of a binary search algorithm of search, getting a rank of items:
58
 * <ul>
59
 * <li>Considering case sensitive in the search.</li>
60
 * <li>Ignoring case sensitive in the search.</li>
61
 * <li>Considering case sensitive in the search and an object which implements the Comparable interface</li>
62
 * <li>Ignoring case sensitive in the search, but yes an objecth which implements the Comparable interface</li>
63
 * </ul>
64
 * 
65
 * @author Pablo Piqueras Bartolom? (p_queras@hotmail.com)
66
 */
67
public class BinarySearchUsingFirstCharacters {
68
	/**
69
	 * This method should be used when is wanted to distinguish small letters from capital letters during the search.
70
	 *   
71
	 * It's necessary that all items of the array implement the {@link Comparable} interface.<br>
72
	 * And it's also necessary that the value returned by the <i>toString()</i> method of each item (supposing 
73
	 *   they inherit from Object) would be the expected value user saw (that would be used to compare the items).
74
	 *   
75
	 * @param text java.lang.String
76
	 * @param sortOrderedItems java.util.Vector
77
	 */
78
	public synchronized static List doSearchConsideringCaseSensitive(String text, Vector sortOrderedItems) {
79
		int currentIteration = 0;
80
		int size = sortOrderedItems.size();
81
		int maxNumberOfIterations = (int) MathExtension.log2(size);
82
		int lowIndex = 0;
83
		int highIndex = sortOrderedItems.size() - 1;
84
		int mIndx;
85
		
86
		while ((lowIndex <= highIndex) && (currentIteration <= maxNumberOfIterations)) {
87
			mIndx = ( lowIndex + highIndex ) / 2;
88
			
89
			if ( sortOrderedItems.get( mIndx ).toString().startsWith( text ) ) {
90
				lowIndex = highIndex = mIndx;
91
				highIndex ++;
92
				
93
				// Expand the rank to up
94
				while ( ( highIndex < size ) && ( sortOrderedItems.get( highIndex ).toString().startsWith( text ) ) ) {
95
					highIndex ++;
96
				}
97

  
98
				// Expand the rank to down
99
				while ( ( (lowIndex - 1) > -1 ) && ( sortOrderedItems.get( (lowIndex - 1) ).toString().startsWith( text ) ) ) {
100
					lowIndex --;
101
				}
102

  
103
				// It's possible that items with different case, should be between the same case, then this item will be added individually:
104
				List list = new Vector(sortOrderedItems.subList(lowIndex, highIndex));
105
				
106
				// Expand to down
107
				lowIndex --;
108
				while ( ( lowIndex > -1 ) && ( sortOrderedItems.get( (lowIndex ) ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
109
					if (sortOrderedItems.get( lowIndex ).toString().startsWith( text )) {
110
						list.add(0, sortOrderedItems.get( lowIndex ));
111
					}
112
					
113
					lowIndex --;
114
				}
115
				
116
				// Expand to up
117
				while ( ( highIndex < size ) && ( sortOrderedItems.get( highIndex ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
118
					if (sortOrderedItems.get( highIndex ).toString().startsWith( text )) {						
119
						list.add(list.size(), sortOrderedItems.get( highIndex ));
120
					}
121
					
122
					highIndex ++;
123
				}
124
				
125
				// Returns all items in the rank
126
				return list; // Breaks the loop
127
			}
128
			else {
129
				if ( sortOrderedItems.get( mIndx ).toString().compareTo( text ) > 0 ) {
130
					highIndex = mIndx - 1;
131
				}
132
				else {
133
					lowIndex = mIndx + 1;
134
				}
135
			}
136
			
137
			currentIteration ++;
138
		}
139
		
140
		// If no item has been found -> return null
141
		return null;
142
	}
143
	
144
	/**
145
	 * This method should be used when is wanted not to distinguish small letters from capital letters during the search.
146
	 *   
147
	 * It's necessary that all items of the array implement the {@link Comparable} interface.<br>
148
	 * And it's also necessary that the value returned by the <i>toString()</i> method of each item (supposing 
149
	 *   they inherit from Object) would be the expected value user saw (that would be used to compare the items).
150
	 *
151
	 * In this particular situation, it's supposed that the vector is sort ordered according the default algorithm of Java; this has the problem that
152
	 *   it doesn't consideres the special characters and the orthographic rules of languages that aren't English, and then, for a particular
153
	 *   <i>text</i> search, an incorrect result could be obtained. The solution decided for this problem has been to modify the algorithm, for seach
154
	 *   into two ranks.
155
	 *
156
	 * @param text java.lang.String
157
	 * @param sortOrderedItems java.util.Vector
158
	 */
159
	public synchronized static List doSearchIgnoringCaseSensitive(String text, Vector sortOrderedItems) {
160
		int currentIteration = 0;
161
		int size = sortOrderedItems.size();
162
		int maxNumberOfIterations = (int) MathExtension.log2(size);
163
		int lowIndex = 0;
164
		int highIndex = sortOrderedItems.size() - 1;
165
		int mIndx;
166
		List list = null;
167
		List list2 = null;
168

  
169
		// FIRST RANK
170
		while ((lowIndex <= highIndex) && (currentIteration <= maxNumberOfIterations)) {
171
			mIndx = ( lowIndex + highIndex ) / 2;
172
			
173
			if ( sortOrderedItems.get( mIndx ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) {
174
				lowIndex = highIndex = mIndx;
175
				highIndex ++;
176
				
177
				// Expand the rank to up
178
				while ( ( highIndex < size ) && ( sortOrderedItems.get( highIndex ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
179
					highIndex ++;
180
				}
181

  
182
				// Expand the rank to down
183
				while ( ( (lowIndex - 1) > -1 ) && ( sortOrderedItems.get( (lowIndex - 1) ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
184
					lowIndex --;
185
				}
186
				
187
				// Returns all items in the rank
188
				list = Arrays.asList((sortOrderedItems.subList(lowIndex, highIndex)).toArray());
189
				
190
//				list = new ArrayList(Arrays.asList((sortOrderedItems.subList(lowIndex, highIndex)).toArray())); // Breaks the loop
191
//				break;
192
			}
193
			else {
194
				if ( sortOrderedItems.get( mIndx ).toString().compareTo( text ) > 0 ) {
195
					highIndex = mIndx - 1;
196
				}
197
				else {
198
					lowIndex = mIndx + 1;
199
				}
200
			}
201
			
202
			currentIteration ++;
203
		}
204

  
205
		// SECOND RANK
206
		currentIteration = 0;
207
		lowIndex = 0;
208
		highIndex = sortOrderedItems.size() - 1;
209

  
210
		while ((lowIndex <= highIndex) && (currentIteration <= maxNumberOfIterations)) {
211
			mIndx = ( lowIndex + highIndex ) / 2;
212
			
213
			if ( sortOrderedItems.get( mIndx ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) {
214
				lowIndex = highIndex = mIndx;
215
				highIndex ++;
216
				
217
				// Expand the rank to up
218
				while ( ( highIndex < size ) && ( sortOrderedItems.get( highIndex ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
219
					highIndex ++;
220
				}
221

  
222
				// Expand the rank to down
223
				while ( ( (lowIndex - 1) > -1 ) && ( sortOrderedItems.get( (lowIndex - 1) ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
224
					lowIndex --;
225
				}
226
				
227
				// Returns all items in the rank			
228
				list2 = Arrays.asList((sortOrderedItems.subList(lowIndex, highIndex)).toArray()); // Breaks the loop
229
				
230
				if (list == null)
231
					return list2;
232
				else {
233
					if (list2 == null)
234
						return null;
235

  
236
					Object obj;
237
					int j;
238
					
239
					list = new ArrayList(list.subList(0, list.size()));
240
					
241
					for (int i = 0; i < list2.size(); i ++) {
242
						obj = list2.get(i);
243
					
244
						// Don't add items which are already in the list
245
						if (!list.contains(obj)) {
246
							// Adds in sort order the new item:
247
							for (j = 0; j < list.size(); j ++) {
248
								if (list.get(j).toString().compareTo(obj.toString()) > 0)
249
									break;
250
							}
251
							
252
							list.add(j, obj);
253
							System.out.println("A?ade: " + obj);
254
						}
255
					}
256
					
257
					return list;
258
				}
259
			}
260
			else {
261
				if ( sortOrderedItems.get( mIndx ).toString().toLowerCase().compareTo( text.toLowerCase() ) > 0 ) {
262
					highIndex = mIndx - 1;
263
				}
264
				else {
265
					lowIndex = mIndx + 1;
266
				}
267
			}
268
			
269
			currentIteration ++;
270
		}
271
		
272
		return null;
273
	}
274
	
275
	/**
276
	 * This method should be used when is wanted distinguish small letters from capital letters during the search, and the comparation of items
277
	 *   done according an algorithm we define.
278
	 *   
279
	 * And it's also necessary that the value returned by the <i>toString()</i> method of each item (supposing 
280
	 *   they inherit from Object) would be the expected value user saw (that would be used to compare the items).
281
	 *   
282
	 * @param text java.lang.String
283
	 * @param sortOrderedItems java.util.Vector
284
	 * @param comp An Comparator object which implements the <i><b>compareTo()</b><i>  method.
285
	 */
286
	public synchronized static List doSearchConsideringCaseSensitive(String text, Vector sortOrderedItems, Comparator comp) {
287
		int currentIteration = 0;
288
		int size = sortOrderedItems.size();
289
		int maxNumberOfIterations = (int) MathExtension.log2(size);
290
		int lowIndex = 0;
291
		int highIndex = sortOrderedItems.size() - 1;
292
		int mIndx;
293

  
294

  
295
		while ((lowIndex <= highIndex) && (currentIteration <= maxNumberOfIterations)) {
296
			mIndx = ( lowIndex + highIndex ) / 2;
297

  
298
			if ( sortOrderedItems.get( mIndx ).toString().startsWith( text ) ) {
299
				lowIndex = highIndex = mIndx;
300
				highIndex ++;
301

  
302
				// Expand the rank to up
303
				while ( ( highIndex < size ) && ( sortOrderedItems.get( highIndex ).toString().startsWith( text ) ) ) {
304
					highIndex ++;
305
				}
306

  
307
				// Expand the rank to down
308
				while ( ( (lowIndex - 1) > -1 ) && ( sortOrderedItems.get( (lowIndex - 1) ).toString().startsWith( text ) ) ) {
309
					lowIndex --;
310
				}
311

  
312
				// It's possible that items with different case, should be between the same case, then this item will be added individually:
313
				List list = new Vector(sortOrderedItems.subList(lowIndex, highIndex));
314
				
315

  
316
				// Expand to down
317
				lowIndex --;
318
				while ( ( lowIndex > -1 ) && ( sortOrderedItems.get( (lowIndex ) ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
319
					if (sortOrderedItems.get( lowIndex ).toString().startsWith( text )) {
320
						list.add(0, sortOrderedItems.get( lowIndex ));
321
					}
322
					
323
					lowIndex --;
324
				}
325
				
326
				// Expand to up
327
				while ( ( highIndex < size ) && ( sortOrderedItems.get( highIndex ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
328
					if (sortOrderedItems.get( highIndex ).toString().startsWith( text )) {						
329
						list.add(list.size(), sortOrderedItems.get( highIndex ));
330
					}
331
					
332
					highIndex ++;
333
				}
334
				
335
				// Returns all items in the rank
336
				return list; // Breaks the loop
337
			}
338
			else {
339
				if ( comp.compare(sortOrderedItems.get( mIndx ), text ) > 0 ) {
340
					highIndex = mIndx - 1;
341
				}
342
				else {
343
					lowIndex = mIndx + 1;
344
				}
345
			}
346

  
347
			currentIteration ++;
348
		}
349

  
350
		// If no item has been found -> return null
351
		return null;
352
	}
353
	
354
	/**
355
	 * This method should be used when is wanted not to distinguish small letters from capital letters during the search, and the comparation of items
356
	 *   done according an algorithm we define.
357
	 *   
358
	 * And it's also necessary that the value returned by the <i>toString()</i> method of each item (supposing 
359
	 *   they inherit from Object) would be the expected value user saw (that would be used to compare the items).
360
	 *
361
	 * @param text java.lang.String
362
	 * @param sortOrderedItems java.util.Vector
363
	 * @param comp An Comparator object which implements the <i><b>compareTo()</b><i>  method.
364
	 */
365
	public synchronized static List doSearchIgnoringCaseSensitive(String text, Vector sortOrderedItems, Comparator comp) {
366
		int currentIteration = 0;
367
		int size = sortOrderedItems.size();
368
		int maxNumberOfIterations = (int) MathExtension.log2(size);
369
		int lowIndex = 0;
370
		int highIndex = sortOrderedItems.size() - 1;
371
		int mIndx;
372
		
373
		while ((lowIndex <= highIndex) && (currentIteration <= maxNumberOfIterations)) {
374
			mIndx = ( lowIndex + highIndex ) / 2;
375
			
376
			if ( sortOrderedItems.get( mIndx ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) {
377
				lowIndex = highIndex = mIndx;
378
				highIndex ++;
379
				
380
				// Expand the rank to up
381
				while ( ( highIndex < size ) && ( sortOrderedItems.get( highIndex ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
382
					highIndex ++;
383
				}
384

  
385
				// Expand the rank to down
386
				while ( ( (lowIndex - 1) > -1 ) && ( sortOrderedItems.get( (lowIndex - 1) ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
387
					lowIndex --;
388
				}
389
				
390
				// Returns all items in the rank			
391
				return Arrays.asList((sortOrderedItems.subList(lowIndex, highIndex)).toArray()); // Breaks the loop
392
			}
393
			else {
394
				if ( comp.compare(sortOrderedItems.get( mIndx ).toString().toLowerCase(), text.toLowerCase() ) > 0 ) {
395
					highIndex = mIndx - 1;
396
				}
397
				else {
398
					lowIndex = mIndx + 1;
399
				}
400
			}
401
			
402
			currentIteration ++;
403
		}
404
		
405
		return null;
406
	}
407
}
0 408

  

Also available in: Unified diff