






Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
Material Type: Assignment; Class: ALGORITHM IMPLEMENTATION; Subject: Computer Science; University: University of Pittsburgh; Term: Fall 2006;
Typology: Assignments
1 / 10
This page cannot be seen from the preview
Don't miss anything!







Assignment 1 (Boggle) Report Implemented Optimizations Most of the optimizations in my program focused on the dictionary implemented as a PATRICIA tree. Obviously, these trees are highly optimized and efficient; however it was some of the minute details that I used to generate slightly better runtimes than other methods. These were primarily in the “GetBitAtPosition” and “GetFirstDifferentBit” functions. In my function to get the bit at a particular position I create a bit mask of 0x (10000000 in binary), and logical shift right x times (where x is the position of the bit you're requesting). For example, the mask is 10000000 but if you want the 3rd left bit, (position 2, since it's zero based) it would be shifted 2 times, resulting in 00100000. Then you "bitwise and" the number passed in with the created mask which will zero out any numbers in the result where there was a zero in the mask. This leaves you with just the bit at the given position set to on (1). This is then put in an integer so it will be either 0 (if off) or the number represented by a 1 at that position in the binary string (i.e. if the result was equal to 4, then the “and” result had a 1 in the fours place (00000100). Compare the result to 0, and return false if equal (since 0 is off), or true otherwise. To do the “GetBitAtPosition” for a string, I simply divided the position by 8, set the position equal to itself modulus 8 (to get the position for the individual character), and then called the function as normal. For my “GetFirstDifferent” bit function, I had to do another interesting trick. First I just check if they're equal. Here’s a copy of that code.
if( number == number2 ) return -1; int result = number ^ number2; for( int i = 0;; i++, result <<= 1 ) if( result >= 0x80 ) return i; If they are, there’s no point in doing anything, so I return -1 to show they're the same (although this generally shouldn’t happen, it could cause a nasty infinite loop below). Then, I take the exclusive or (or XOR) of the two numbers. This will make sure the first different bit is a 1 in the result (since XORing two different bits results in a 1, but if they're the same it will be a 0). Then, I put \ in a no-condition loop, so I had to guarantee it will exit (that is taken care of by the comparison above for equality). Also notice it has a double update instruction. It increments i (i++) and also left shifts the result by one (doubles it). Then you check if the result is >= 0x80 (128). If it is, the there is definitely a one in the first bit position (the 128 position), and possibly other positions have a 1 as well. So the count of i it took to get there by shifting left is the first different bit. To do a full string in the same manner, I simply had to iterate checking if each character was the same, and as soon as it differed, I called the character (or integer if you’d like) version of the function (“GetFirstDifferent”). Then I shifted the number of characters that were the same to the left by 3 (same as multiplying by 2^3 or 8 since each character I represented using 8 bits.), and added the different bit position that differed in the characters.
maximum word length long (see above) long. The word was followed by the character 0xFF to guarantee all bits after the string were 1s and make it simpler for me to understand and debug. This insertion logic was greatly simplified due to this, and may slightly help improve insert times. Lookup times should not be affected due to the fact it checks the first different bits, and the ones at the end are ignored. This helped to make sure upward pointing nodes did not try to check bits in positions that didn’t exist in smaller strings. Worst Case Complexity Analysis The worst case possible for this program (as a whole), is if every single combination of the board was a valid word in the dictionary. As you can imagine, this would require a lot of time, since it would require not only a full traversal of the highest combination of permutations possible (even with prefix checking), but it would require n squared (where n is the board size) traversals for EACH permutation (or n^2 times permutations possible) since each character position (and every permutation below it) would be checked. Clearly, as the board size increases, the time to do an exhaustive search would increase exponentially (especially if it must search all the paths, which is if we’re talking about absolute worst case time, and not including time saved by prefix checking). This is apparent by the following graph of board size (n where it is an n x n board, vs the total possible permutations). Notice the scale is logarithmic (hence showing an exponential increase by the linear looking line.)
Board Size vs Total Permutations 1 28 653 28512 3060417 1 10 100 1000 10000 100000 1000000 10000000 0 1 2 3 4 5 6 Board Size (n in a n by n board) Permutations Possible (Maximum) Series Adding a trend line gives the following: y = 0.0177e3.6794x Hypothesis of Average Case Complexity Analysis My hypothesis for the average case run time of this program, is when the program only encounters a word (and therefore also the prefix for any word) half of the time. Based on this, I would estimate that running times for the boggle problem would be relatively slow in exponential growth. Note that it is still exponential; however the growth is not extreme. This seems to hold true as my board size increased using the MakeBoggleBoard.java using say 1, 5, 20, 50, and 100 size boards. It definitely was not linear, and also definitely not logarithmic. All of my experimentation seemed to hold that it was a slow exponential growth, helped by the prefix checking and other methods, which resulted in the average case. Output on Sample Input Space 10 elrsecsnls
crest crt cry dace day die dig din dina dine dis dts eat eats ecu egad ego enid eon err fad fast fat fie fin final fine finis fog gad gal gale gel gig gigo got haole hoe hone honor honors hora ibices ibis ice ida
ilia ina inn iris lag lan lane lea leah leg legal legit lela leo leon leona liaise lon lone lorn lye lyses lysin mss nae nib noah noel noes noh noose nor nora norris oat oats old oldie ole oleo one oneiric oran orrin orris ran