Home > Recursion > ActionScript 3.0 Recursive Binary Search: The Vice!

ActionScript 3.0 Recursive Binary Search: The Vice!

recursiveBinaryThe Recursive Vice

After our post on the binary search algorithm, I found that no one had cooked up an example of a Recursive Binary Search. So, I did. In a recent post, we looked at linked lists and used a recursive algorithm to move through the list. The algorithm is simple, and I hope explains both binary search and how to use recursion with such a search. As with the other posts in this recent series, we’re working our way to skip lists, and I hope this will aid in understanding how skip lists work.

Divide and Conquer

The binary search algorithm uses a divide and conquer approach that works like a vice. With each division in half, the bottom range gets higher and the top range gets lower and the search object is either squeezed out or not found. This saves a lot of poking around an array (or other list) to find what you’re looking for.

When using recursion, the function containing the search algorithm keeps calling itself until a match occurs or it runs out of places to look. In order to provide a visual representation of what’s going on, I used trace statements with each call to a recursive function. As you will see, with each recursive call, the search function displays the call and the values. The first parameter is the search value (44 in this case) and the second two parameters represent the beginning and ending values of the search fields. When you run the program, you will see something like the following:

recursive call to: recursiveBinarySearch(44,0,49);
recursive call to: recursiveBinarySearch(44,25,49);
recursive call to: recursiveBinarySearch(44,38,49);
recursive call to: recursiveBinarySearch(44,38,42);
recursive call to: recursiveBinarySearch(44,41,42);
recursive call to: recursiveBinarySearch(44,42,42);
Your number is at position 42

The beginning search of 100 elements is 49 for the top and 0 for the bottom. It then moves up through the numeric elements of the array until it finally squeezes out the found item in array element 42. (The array is randomly populated from 1 to 100 and then sorted—binary searches require sorted lists.)

Normally in these posts I don’t use a lot of comments in the code because the text in the post is supposed to explain everything. (Also, comments often get in the way of the flow of the programming logic and good agile programming shouldn’t need comments.) However, for this algorithm, I found that it probably helps to see each step in detail so I put in quite a few comments.

I also put the algorithm in a class. Because,

…an algorithm without a class is like a child without a mother…

That reminds me, Happy Mothers Day to all of you mothers out there.

(I suppose a corollary would be,

…a class without a design pattern is like a child without a father…

but I’d never say that because people might get the wrong idea about the latter piece of wisdom.)

Okay, so let’s take a look at the class containing the algorithm:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package
{
	import flash.display.Sprite;
 
	public class Binary extends Sprite
	{
		private var searchArray:Array=new Array();
		private var sizeNow:int;
		private var mid:int;
		private var poke:int;
		private var begin:int;
		private var end:int;
		private var flagUp:Boolean=true;
 
		public function Binary()
		{
			for (var stuff:int=0; stuff<100; stuff++)
			{
				searchArray.push(int(Math.random()*100));
			}
			searchArray.sort();
			sizeNow=searchArray.length;
		}
 
		public function recursiveBinarySearch(valueN:int,begin:int,end:int):int
		{
			/*Only on the first time through use the array
			length as the end value. The Algorithm keeps
			changing the end value so you don't want to use
			the array length more than once.    */
			if (flagUp)
			{
				end=sizeNow;
				flagUp=false;
			}
 
			/*If the end value is smaller than the begin value
			the search is over and item was not found.    */
			if (end<begin)
			{
				return -1;
			}
 
			/*Find the midway point between begin and end
			and use it as the numeric key for the current search
			value—guess (poke).     */
			mid=int((begin + end)/2);
			poke=searchArray[mid];
 
			/*If a match occurs return
			the value of the numeric key.  Search ends here.  */
			if (poke==valueN)
			{
				return mid;
			}
 
			/*If no match; guess larger than value; the end value
			becomes the midway value minus 1. Otherwise, the begin
			value becomes the midway value plus 1.     */
			else
			{
				if (poke>valueN)
				{
					end=mid-1;
				}
				else
				{
					if (poke<valueN)
					{
						begin=mid+1;
					}
				}
			}
 
			/* Keep making the recursive call until value is found
			or all possible values are searched */
			trace("recursive call to: recursiveBinarySearch("+valueN+","+begin+","+end+");");
			return recursiveBinarySearch(valueN,begin,end);
		}
	}
}

Like I said, there are a lot of comments there so that you can see the steps through the algorithm. Now, a second class acts like a client and calls the method in the Binary class:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package
{
	import flash.display.Sprite;
	public class Searcher extends Sprite
	{
		private var searching:Binary=new Binary();
		private var searchElement:Number;
		private var searchNow:Number;
 
		public function Searcher()
		{
			searchNow=searching.recursiveBinarySearch(44,0,0);
			if (searchNow>=0 && searchNow != 4294967295)
			{
				trace("Your number is at position " + searchNow );
			}
			else
			{
				trace("Not found");
			}
		}
	}
}

Keep in mind that all of the searches are searching the numeric element keys of the array—not the values. Therefore, you shouldn’t expect the found value to be the same as the numeric key value. Also, since the values are generated randomly, the value you place in the first parameter of the line:

searchNow=searching.recursiveBinarySearch(44,0,0);

may not be found at all. I put in 44 for the search value, but you can add any value you want between 1 and 100. Alternatively, you can fix it up so that you can dynamically enter different values or even change it to make it look for string values. However, the point is simply to demonstrate how to create and use a recursive binary search.

As always, your comments, corrections and wisdom are always welcomed.

Share

Related posts:

  1. A Funny Thing Happened on the way to Skip Lists: The ActionScript 3.0 Binary Search Algorithm
Categories: Recursion
  1. May 12, 2010 at 2:58 pm | #1

    This is great.
    Minor optimization suggestion, use bitwise operator for division by2
    mid=uint((begin + end)/2);
    becomes
    mid=uint((begin + end)>>1);

    Also to make the Binary class more useful, I would do the following-
    allow the array to be passed in, by default search the entire array.
    To search part of the array add optional arguments for star and end.
    Also allow for searching of both strings as well as numbers

  2. May 12, 2010 at 3:31 pm | #2

    seem to also get an error 5-10% of the time
    Error: Error #1023: Stack overflow occurred.

  3. May 12, 2010 at 4:10 pm | #3

    This implementation also seems work and follows the Java implementation
    see http://stackoverflow.com/questions/1987163/binary-search-from-java-to-actionscript.
    Example code:

    ?View Code ACTIONSCRIPT
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    public  function find(keys:Array, target:Object):int {
            var high:int = keys.length;
            var low:int = -1;
            while (high - low &gt; 1) {
                var probe:int = (low + high) / 2;
                if (keys[probe] &gt; target)
                    high = probe;
                else
                    low = probe;
            }
     
            if (low == -1 || keys[low] !== target)
                return -1;
            else
                return low;
        }
  4. May 13, 2010 at 1:44 am | #4

    Hi eco_bach Dude,

    Thanks for all of the suggestions. I really like the binary divide. I believe that in our original binary search post, one of the comments had an identical iterative algorithm; and I’ve been trying to find a recursive algorithm with the results from this post.

    Do you think that you can find the problem in the binary search algorithm using recursion and suggest a fix?

    Thanks for your great ideas,
    Bill

  5. Atarsh
    June 5, 2010 at 7:55 am | #5

    Flash has a limit of recursion levels it may use, and this limit is changeable on each machine. if you use a REALLY big array, it is possible you will encounter a stack overflow.
    However, I tried running a similar program (same idea, wrote it after the previous post) and while running several 100-calls cycles didn’t encounter any such error.
    I didn’t see any major differences between my code and yours, I’m attaching it here:

    ?View Code ACTIONSCRIPT
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    
    /**
     * finds an item in an array.
     * @param item the item to find
     * @param array	the array to search
     * @return index of given item in array, or -1 if the item is not in the array
     */
    private function find(item:int, array:Array):int {
    	var upperIndex:int = array.length;
    	var lowerIndex:int = 0;
    	var midIndex:int = Math.floor((lowerIndex + upperIndex) / 2);
     
    	if (array[lowerIndex] == item) {
    		return lowerIndex;
    	}
    	if (array[upperIndex] == item) {
    		return upperIndex;
    	}
     
    	return findHelper(item, array, upperIndex, midIndex, lowerIndex);
     
    }
     
    private function findHelper(item:int, array:Array, upIndex:int, midIndex:int, lowIndex:int):int {
    	if (item  array[midIndex]) {
    		trace("raising lower bound from ",lowIndex, " to ", midIndex);
    		lowIndex = midIndex + 1;
    	}
    	else {
    		// item == array[midIndex]
    		return midIndex;
    	}
    	midIndex = Math.floor((lowIndex + upIndex) / 2);
    	if (midIndex == lowIndex) {
    		// happens if upper and lower are consecutives,
    		// meaning the item is not in the array
    		return -1;
    	}
    	return findHelper(item, array, upIndex, midIndex, lowIndex);
    }
  6. June 5, 2010 at 7:24 pm | #6

    Hi Atarsh,

    Thanks for your comment. I like the way that the first function calls the second and the second is recursive. A number of problems regarding recursion is far overstated and recursion is a valuable tool for programmers.

    Kindest regards,
    Bill

  7. Mad Doctor
    February 21, 2011 at 7:33 am | #7

    @William Just a small glitch in the code – recursiveBinarySearch() is set to return uint, but if the search value is not found, it will return -1. This will produce warning when trying to compile.

  8. February 21, 2011 at 10:32 am | #8

    Hi Mad Doc!

    You’re right! Good catch. I changed them all to int.

    Kindest regards,
    Bill

  1. May 8, 2010 at 8:13 am | #1

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>