Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libIverUtiles / src / com / iver / utiles / search / BinarySearchUsingFirstCharacters.java @ 11858

History | View | Annotate | Download (15.4 KB)

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
                                break;
190
                        }
191
                        else {
192
                                if ( sortOrderedItems.get( mIndx ).toString().compareTo( text ) > 0 ) {
193
                                        highIndex = mIndx - 1;
194
                                }
195
                                else {
196
                                        lowIndex = mIndx + 1;
197
                                }
198
                        }
199
                        
200
                        currentIteration ++;
201
                }
202

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

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

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

    
234
                                        Object obj;
235
                                        int j;
236
                                        
237
                                        list = new ArrayList(list.subList(0, list.size()));
238
                                        
239
                                        for (int i = 0; i < list2.size(); i ++) {
240
                                                obj = list2.get(i);
241
                                        
242
                                                // Don't add items which are already in the list
243
                                                if (!list.contains(obj)) {                
244
                                                        // Adds in sort order the new item:
245
                                                        for (j = 0; j < list.size(); j ++) {
246
                                                                if (list.get(j).toString().compareTo(obj.toString()) > 0)
247
                                                                        break;
248
                                                        }
249
                                                        
250
                                                        list.add(j, obj);
251
                                                }
252
                                        }
253
                                        
254
                                        // It's possible that some elements at the end wouldn't be found -> another small search
255
                                        size = list.size();
256
                                        if (size == 0) {
257
                                                j = 0;
258
                                        }
259
                                        else {
260
                                                j = sortOrderedItems.indexOf(list.get(size - 1));
261
                                        }
262
                                        
263
                                        j++;
264
                                        
265
                                        if (j < sortOrderedItems.size()) {
266
                                                do {
267
                                                        obj = sortOrderedItems.get( j );
268
                                                        
269
                                                        if (obj.toString().toLowerCase().startsWith( text.toLowerCase())) {
270
                                                                list.add(size, obj);
271
                                                        }
272
                                                        
273
                                                        j++;
274
                                                }
275
                                                while (j < sortOrderedItems.size());
276
                                        }
277
                                        
278
                                        return list;
279
                                }
280
                        }
281
                        else {
282
                                if ( sortOrderedItems.get( mIndx ).toString().toLowerCase().compareTo( text.toLowerCase() ) > 0 ) {
283
                                        highIndex = mIndx - 1;
284
                                }
285
                                else {
286
                                        lowIndex = mIndx + 1;
287
                                }
288
                        }
289
                        
290
                        currentIteration ++;
291
                }
292
                
293
                return null;
294
        }
295
        
296
//        /** THIS VERSION FAILURES IN SOME PARTICULAR SITUATIONS
297
//         * This method should be used when is wanted distinguish small letters from capital letters during the search, and the comparation of items
298
//         *   done according an algorithm we define.
299
//         *   
300
//         * And it's also necessary that the value returned by the <i>toString()</i> method of each item (supposing 
301
//         *   they inherit from Object) would be the expected value user saw (that would be used to compare the items).
302
//         *   
303
//         * @param text java.lang.String
304
//         * @param sortOrderedItems java.util.Vector
305
//         * @param comp An Comparator object which implements the <i><b>compareTo()</b><i>  method.
306
//         */
307
//        public synchronized static List doSearchConsideringCaseSensitive(String text, Vector sortOrderedItems, Comparator comp) {
308
//                int currentIteration = 0;
309
//                int size = sortOrderedItems.size();
310
//                int maxNumberOfIterations = (int) MathExtension.log2(size);
311
//                int lowIndex = 0;
312
//                int highIndex = sortOrderedItems.size() - 1;
313
//                int mIndx;
314
//
315
//
316
//                while ((lowIndex <= highIndex) && (currentIteration <= maxNumberOfIterations)) {
317
//                        mIndx = ( lowIndex + highIndex ) / 2;
318
//
319
//                        if ( sortOrderedItems.get( mIndx ).toString().startsWith( text ) ) {
320
//                                lowIndex = highIndex = mIndx;
321
//                                highIndex ++;
322
//
323
//                                // Expand the rank to up
324
//                                while ( ( highIndex < size ) && ( sortOrderedItems.get( highIndex ).toString().startsWith( text ) ) ) {
325
//                                        highIndex ++;
326
//                                }
327
//
328
//                                // Expand the rank to down
329
//                                while ( ( (lowIndex - 1) > -1 ) && ( sortOrderedItems.get( (lowIndex - 1) ).toString().startsWith( text ) ) ) {
330
//                                        lowIndex --;
331
//                                }
332
//
333
//                                // It's possible that items with different case, should be between the same case, then this item will be added individually:
334
//                                List list = new Vector(sortOrderedItems.subList(lowIndex, highIndex));
335
//                                
336
//
337
//                                // Expand to down
338
//                                lowIndex --;
339
//                                while ( ( lowIndex > -1 ) && ( sortOrderedItems.get( (lowIndex ) ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
340
//                                        if (sortOrderedItems.get( lowIndex ).toString().startsWith( text )) {
341
//                                                list.add(0, sortOrderedItems.get( lowIndex ));
342
//                                        }
343
//                                        
344
//                                        lowIndex --;
345
//                                }
346
//                                
347
//                                // Expand to up
348
//                                while ( ( highIndex < size ) && ( sortOrderedItems.get( highIndex ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
349
//                                        if (sortOrderedItems.get( highIndex ).toString().startsWith( text )) {                                                
350
//                                                list.add(list.size(), sortOrderedItems.get( highIndex ));
351
//                                        }
352
//                                        
353
//                                        highIndex ++;
354
//                                }
355
//                                
356
//                                // Returns all items in the rank
357
//                                return list; // Breaks the loop
358
//                        }
359
//                        else {
360
//                                if ( comp.compare(sortOrderedItems.get( mIndx ), text ) > 0 ) {
361
//                                        highIndex = mIndx - 1;
362
//                                }
363
//                                else {
364
//                                        lowIndex = mIndx + 1;
365
//                                }
366
//                        }
367
//
368
//                        currentIteration ++;
369
//                }
370
//
371
//                // If no item has been found -> return null
372
//                return null;
373
//        }
374
        
375
        /**
376
         * This method should be used when is wanted distinguish small letters from capital letters during the search, and the comparation of items
377
         *   done according an algorithm we define.
378
         *   
379
         * And it's also necessary that the value returned by the <i>toString()</i> method of each item (supposing 
380
         *   they inherit from Object) would be the expected value user saw (that would be used to compare the items).
381
         *   
382
         * @param text java.lang.String
383
         * @param sortOrderedItems java.util.Vector
384
         * @param comp An Comparator object which implements the <i><b>compareTo()</b><i>  method.
385
         */
386
        public synchronized static List doSearchConsideringCaseSensitive(String text, Vector sortOrderedItems, Comparator comp) {
387
                List results_list = doSearchIgnoringCaseSensitive(text, sortOrderedItems, comp);
388

    
389
                if (results_list == null)
390
                        return null;
391

    
392
                List results = new ArrayList();
393

    
394
                for (int i = 0; i < (results_list.size()); i++) {
395
                        if (results_list.get(i).toString().startsWith(text)) {
396
                                results.add(results_list.get(i));
397
                        }
398
                }
399

    
400
                return results;
401
        }
402
        
403
        /**
404
         * This method should be used when is wanted not to distinguish small letters from capital letters during the search, and the comparation of items
405
         *   done according an algorithm we define.
406
         *   
407
         * And it's also necessary that the value returned by the <i>toString()</i> method of each item (supposing 
408
         *   they inherit from Object) would be the expected value user saw (that would be used to compare the items).
409
         *
410
         * @param text java.lang.String
411
         * @param sortOrderedItems java.util.Vector
412
         * @param comp An Comparator object which implements the <i><b>compareTo()</b><i>  method.
413
         */
414
        public synchronized static List doSearchIgnoringCaseSensitive(String text, Vector sortOrderedItems, Comparator comp) {
415
                int currentIteration = 0;
416
                int size = sortOrderedItems.size();
417
                int maxNumberOfIterations = (int) MathExtension.log2(size);
418
                int lowIndex = 0;
419
                int highIndex = sortOrderedItems.size() - 1;
420
                int mIndx;
421
                
422
                while ((lowIndex <= highIndex) && (currentIteration <= maxNumberOfIterations)) {
423
                        mIndx = ( lowIndex + highIndex ) / 2;
424

    
425
                        if ( sortOrderedItems.get( mIndx ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) {
426
                                lowIndex = highIndex = mIndx;
427
                                highIndex ++;
428
                                
429
                                // Expand the rank to up
430
                                while ( ( highIndex < size ) && ( sortOrderedItems.get( highIndex ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
431
                                        highIndex ++;
432
                                }
433

    
434
                                // Expand the rank to down
435
                                while ( ( (lowIndex - 1) > -1 ) && ( sortOrderedItems.get( (lowIndex - 1) ).toString().toLowerCase().startsWith( text.toLowerCase() ) ) ) {
436
                                        lowIndex --;
437
                                }
438
                                
439
                                // Returns all items in the rank                        
440
                                return Arrays.asList((sortOrderedItems.subList(lowIndex, highIndex)).toArray()); // Breaks the loop
441
                        }
442
                        else {
443
                                if ( comp.compare(sortOrderedItems.get( mIndx ).toString().toLowerCase(), text.toLowerCase() ) > 0 ) {
444
                                        highIndex = mIndx - 1;
445
                                }
446
                                else {
447
                                        lowIndex = mIndx + 1;
448
                                }
449
                        }
450
                        
451
                        currentIteration ++;
452
                }
453
                
454
                return null;
455
        }
456
}