The class that was used today is here. Additionally, the tests taken last friday were returned in class. If you didn't get your test go to Kesden's office hours and you can pick it up there.Filtering ... continued
Last class we started going over what filtering was, but we didn't finish writing some code for actual filter methods. Today we'll finish up talking about filter methods by writing code for the two types that we talked about last class, and then discussing and coding up a third version.First Version
The first version of a filter method that we talked about last class was a filter method that started at the begining and moved toward the end of the list. So we have the general idea of this methods, we're just going to have to add some specifics about how exactly this method is going to work. So we already know two things about the method that we're going to write. Its going to walk through the list that we have, position by position, and that its going to start at the begining of the previous list. Now, we just have to decide what the method's doing at each position. In order to do this we have to make a couple more decisions about how we want the filter method to work, namely whether we want the elements that are greater or less then the given element. In this case we'll take the elements that are greater then the given element. Since this is the case we'll check the element at each position and if it's greater then the given element we'll add it to the list. Now its time to code. // remember to talk about time to write start at end/begin
/* This class filters the array holding the names, and returns a new SortedNames holding only names greater then the name passed in */ public SortedNames getGreaterThanForward (String name){ //creates the new SortedNames, which the names //that satisfy the filter will be added to SortedNames bigNames = new SortedNames(name.length); //goes through each position in the array for(int index = 0; index < count index ++){ //if current position passes filter criteria //adds it to the list if(names[index].compareTo(name)>0){ bigNames.insert(names[index]); } } //returns the list of names that was created return bignames; }
While we're thinking about this method, what changes would we have to make to the method above if we decided to filter for the names that were less then the given name, instead of greater then?
Because of the way that our class is set up the only thing that we would have to change is to the if statement inside the for loop. Change "if(names[index].compareTo(name)>0)" to "if(names[index].compareTo(name)<0)" and you'll switch the filter.
Second Version of the Filter
In the second version of a filter method we're going to start at the end of the array and work our way forward. Think of what types of changes we might have to make to the method that we previously wrote, if we make this change. Looking over the method, it turns out that the only change that we'll have to make is in the for loop. So a filter method that starts at the end of the list and works its way forward would look like the method below.
/* This class filters the array holding the names, and returns a new SortedNames holding only names greater then the name passed in */ public SortedNames getGreaterThanReverse (String name){ //creates the new SortedNames, which the names //that satisfy the filter will be added to SortedNames bigNames = new SortedNames(name.length); //goes through each position in the array //!!only change in the method is on the line below!! for(int index = (count -1); index >= 0; index --){ //if current position passes filter criteria //adds it to the list if(names[index].compareTo(name)>0){ bigNames.insert(names[index]); } } //returns the list of names that was created return bignames; }
Now we've done these two types of the method, and they look pretty similar. So when would you want to use one or the other? Well when thinking about this question we want to think about what might speed up our program, and get it to run more efficiently. One of the areas that can give us a quicker program is if we add the elements to the new list already in the correct order. That way we don't have to shuffle the elements around each time we want to add a new one. In order to do this we would want to add the smallest elements to our list first, so this would imply that of these two searches the getGreaterThanForward will probably be the faster seach. Another area that would give us some speed up comes from the fact that the list is ordered. Since it is ordered if we were looking for items only smaller then a given item, and working backwards, or we were looking for items only larger then a certain item and working forwards we could stop looking at the first item that didn't meet the criteria. There are two things to be careful about here though. The first is the most important and it is that the reverse cases, looking for the larger items and starting from the frount, or looking for smaller items and starting from the rear don't work. This is because in those cases the invalid elements come before the valid ones, instead of the other way around. The other thing to be careful of, is that if you're starting from the back, and adding to many elements to the new array you're going to lose more time by shifting elements when adding them then you're going to gain from being able to stop at some point(see the above paragraph).
Third Version of the Filter
The third version of the filter is going to work very differently from the first two versions. This version is going to involve some binary searching. If you need to review binary search look at Lecture 24 where its first introduced.
In this version we're going to deal with the problem of sometimes having to look at a whole bunch of items that we don't want. Instead of doing that we'll write a filter method that uses a binary search like method to find the approximate position of where the elements we want start. That way we can then write our filter method, starting from that position.
What does using the binary search like method to find our starting position get us? Since binary search works a lot more efficiently then just going through the items one by one we'll have to look at a lot fewer of the items that we don't want to add to our list. This in turn will allow our method to run faster then it might have otherwise.
In order to write this method however, we're going tohave to write our binary search like method first. In this case we'll call it getIndexNear.
/* works like a binary search returns a location that is approximately where we want it although it might be one less then where it actually starts */ private int getIndexNear (String name) { int left = 0; //lower index int right = count-1; //upper index int pivot = left + (right-left)/2; while (right>=left) { //finds the value to do the binary search //comparisons on int difference = names[pivot].compareTo(name); //we have found the value equal to the value //passed in, returns the location if (difference == 0) return pivot; //case where new pivot is greater then value //passed in if (difference > 0) { right = pivot-1; //updates upper index } //case where new pivot is less then value //passed in if (difference < 0) { left=pivot+1; //updates lower index } //updates pivot since one of the //indexes have been updated pivot = left + (right-left)/2; } return pivot; //returns the location }
Since we have finished that we can now go on to writing the filter method. Once the binary search like method is done writing the rest of this filter is a lot like writing the two previous filters.
/* Filter method returns a SortedNames that only contains the elements of the origonal list that were greater then the input value Uses binary search to improve its run time */ public Sortednames getGreaterThanBinary (string name){ //creates the new SortedNames, that the names that //satisfy the filter will be added to SortedNames bigNames = new SortedNames(names.length(); //uses the binary search like method to find the index //about where the values that we want start int goodStartingPlace = getIndexNear(name); //iterates through the array adding the values to the new //SortedNames, starting from the position that we just found for(int index = goodStartingPlace; index < count; index++){ //current name satisfies the criteria if(names[index].compareTo(name) > 0 { bigName.insert(names[index]); //adds the name to the list } } return bigNames; }