<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>two algorithms &#8211; stoimen&#039;s web log</title>
	<atom:link href="/tag/two-algorithms/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>on web development</description>
	<lastBuildDate>Tue, 13 Feb 2018 08:18:15 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.0.3</generator>
	<item>
		<title>Computer Algorithms: Graph Best-First Search</title>
		<link>/2012/09/24/computer-algorithms-graph-best-first-search/</link>
		<comments>/2012/09/24/computer-algorithms-graph-best-first-search/#comments</comments>
		<pubDate>Mon, 24 Sep 2012 10:44:53 +0000</pubDate>
		<dc:creator><![CDATA[Stoimen]]></dc:creator>
				<category><![CDATA[algorithms]]></category>
		<category><![CDATA[data structures]]></category>
		<category><![CDATA[Adjacency matrix]]></category>
		<category><![CDATA[Algebraic graph theory]]></category>
		<category><![CDATA[Breadth-first search]]></category>
		<category><![CDATA[Depth-first search]]></category>
		<category><![CDATA[Graph]]></category>
		<category><![CDATA[Graph theory]]></category>
		<category><![CDATA[graph traversal algorithms]]></category>
		<category><![CDATA[Hopcroft–Karp algorithm]]></category>
		<category><![CDATA[Matching]]></category>
		<category><![CDATA[Mathematics]]></category>
		<category><![CDATA[Path decomposition]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[possible solution]]></category>
		<category><![CDATA[search algorithms]]></category>
		<category><![CDATA[two algorithms]]></category>
		<category><![CDATA[typical greedy algorithm]]></category>
		<category><![CDATA[USD]]></category>

		<guid isPermaLink="false">/?p=3347</guid>
		<description><![CDATA[Introduction So far we know how to implement graph depth-first and breadth-first search. These two approaches are crucial in order to understand graph traversal algorithms. However they are just explaining how we can walk through in breadth or depth and sometimes this isn&#8217;t enough for an efficient solution of graph traversal. In the examples so &#8230; <a href="/2012/09/24/computer-algorithms-graph-best-first-search/" class="more-link">Continue reading <span class="screen-reader-text">Computer Algorithms: Graph Best-First Search</span> <span class="meta-nav">&#8594;</span></a><div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href="/2012/09/17/computer-algorithms-graph-depth-first-search/" rel="bookmark" title="Computer Algorithms: Graph Depth-First Search">Computer Algorithms: Graph Depth-First Search </a></li>
<li><a href="/2012/09/10/computer-algorithms-graph-breadth-first-search/" rel="bookmark" title="Computer Algorithms: Graph Breadth First Search">Computer Algorithms: Graph Breadth First Search </a></li>
<li><a href="/2012/10/15/computer-algorithms-dijkstra-shortest-path-in-a-graph/" rel="bookmark" title="Computer Algorithms: Dijkstra Shortest Path in a Graph">Computer Algorithms: Dijkstra Shortest Path in a Graph </a></li>
<li><a href="/2012/10/08/computer-algorithms-shortest-path-in-a-graph/" rel="bookmark" title="Computer Algorithms: Shortest Path in a Graph">Computer Algorithms: Shortest Path in a Graph </a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<h2>Introduction</h2>
<p>So far we know how to implement graph <a href="/2012/09/17/computer-algorithms-graph-depth-first-search/" title="Computer Algorithms: Graph Depth-First Search">depth-first</a> and <a href="/2012/09/10/computer-algorithms-graph-breadth-first-search/" title="Computer Algorithms: Graph Breadth First Search">breadth-first</a> search. These two approaches are crucial in order to understand graph traversal algorithms. However they are just explaining how we can walk through in breadth or depth and sometimes this isn&#8217;t enough for an efficient solution of graph traversal.</p>
<p>In the examples so far we had an undirected, unweighted graph and we were using adjacency matrices to represent the graphs. By <a href="/2012/08/31/computer-algorithms-graphs-and-their-representation/" title="Computer Algorithms: Graphs and their Representation">using adjacency matrices</a> we store <strong>1</strong> in the A[i][j] if there’s an edge between vertex i and vertex j. Otherwise we put a <strong>0</strong>. However the value of <strong>1</strong> gives us only the information that we have an edge between two vertices, which is not always enough when designing graphs.</p>
<p>Indeed graphs can be weighted. Sometimes the path between two vertices can have a value. Thinking of a road map we know that distances between cities are represented in miles or kilometers. Thus often representing a road map as a graph, we don’t put just 1 between city A and city B, to say that there is a path between them, but also we put some meaningful information – let’s say the distance in miles between A and B. </p>
<p>Note that this value can be the distance in miles, but it can be something else, like the time in hours we’ve to walk between those two cities. In general this value is a function of A and B. So if we keep the distance between A and B we can say this function is F(A, B) = X, or distance(A, B) = X miles.</p>
<p>Of course in this particular example F(A, B) = F(B, A), but this isn’t always true in practice. We can have a directed graph where F(A, B) != F(B, A).</p>
<p>Here I talk about distance between two cities and it is the edge that brings some additional information. However sometimes we have to store the value of the vertices. Let&#8217;s say I&#8217;m playing a game (like chess) and each move brings me some additional benefit. So each move (vertex) can be evaluated with some particular value. Thus sometimes we don&#8217;t have a function of and edge like F(A, B), but function of the vertices, like F(A) and F(B).</p>
<p>In breadth-first search and depth-first search we just pick up a vertex and we consecutively walk through all its successors that haven’t been visited yet.</p>
<figure id="attachment_3357" style="width: 620px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/09/1.-Unweithed-Graph-Walkthrough.png"><img src="/wp-content/uploads/2012/09/1.-Unweithed-Graph-Walkthrough.png" alt="Walk Through an Unweithed Graph" title="Unweithed Graph Walkthrough" width="620" height="399" class="size-full wp-image-3357" srcset="/wp-content/uploads/2012/09/1.-Unweithed-Graph-Walkthrough.png 620w, /wp-content/uploads/2012/09/1.-Unweithed-Graph-Walkthrough-300x193.png 300w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption class="wp-caption-text">In order to walk through an unweithed graph using DFS, we chose consecutively each successor of node i!</figcaption></figure>
<p>So in DFS in particular we started from left to right in the array above. So the first node that has to be explored is vertex “1”.</p>
<pre lang="PHP">
0: [0, 1, 0, 0, 1, 1]
</pre>
<p>However sometimes, as I said above, we have weighted graphs, so the question is – is there any problem, regarding to the algorithm speed, if we go consecutively through all successors. The answer in general is yes, so we must modify a bit our code in order to continue not with the first but with the best matching successor. By best-matching we mean that the successor should match some criteria like – minimal or maximal value.<span id="more-3347"></span></p>
<h2>Overview</h2>
<p>In the following example we see that some of the successors of vertex 0 are very far from it, while others are closer. Thus 4 has the value of 5, while node 1’s value is 2 and 5 is 1.</p>
<figure id="attachment_3359" style="width: 620px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/09/2.-BFS-and-Weighted-Graph.png"><img src="/wp-content/uploads/2012/09/2.-BFS-and-Weighted-Graph.png" alt="DFS and Weighted Graph" title="DFS and Weighted Graph" width="620" height="399" class="size-full wp-image-3359" srcset="/wp-content/uploads/2012/09/2.-BFS-and-Weighted-Graph.png 620w, /wp-content/uploads/2012/09/2.-BFS-and-Weighted-Graph-300x193.png 300w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption class="wp-caption-text">Weithed graph brings us more information about the successors of a given vertex. Thus we have to chose carefully which one to get first in our path exploration!</figcaption></figure>
<pre lang="PHP">
0: [0, 2, 0, 0, 5, 1]
</pre>
<p>In this case if we’re searching for the shortest path between 1 and 3, although 1 and 4 are the first two successors in the adjacency matrix of the &#8220;start&#8221; vertex, we don&#8217;t choose them since there’s a better solution – going through node 5.</p>
<figure id="attachment_3360" style="width: 620px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/09/3.-Best-First-Search.png"><img src="/wp-content/uploads/2012/09/3.-Best-First-Search.png" alt="Best-First Search" title="Best-First Search" width="620" height="399" class="size-full wp-image-3360" srcset="/wp-content/uploads/2012/09/3.-Best-First-Search.png 620w, /wp-content/uploads/2012/09/3.-Best-First-Search-300x193.png 300w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption class="wp-caption-text">In best-first search we continue the path to the target through the best-matching successor!</figcaption></figure>
<h3>Problems</h3>
<p>The question is – are we sure that by choosing node 5, we’ll find the best path? Even more! Is there a path through node 5? As we see on the image below both cases are possible.</p>
<figure id="attachment_3361" style="width: 620px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/09/4.-BFS-problems.png"><img src="/wp-content/uploads/2012/09/4.-BFS-problems.png" alt="BFS problems" title="BFS problems" width="620" height="399" class="size-full wp-image-3361" srcset="/wp-content/uploads/2012/09/4.-BFS-problems.png 620w, /wp-content/uploads/2012/09/4.-BFS-problems-300x193.png 300w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption class="wp-caption-text">Somtimes best-first search doesn&#8217;t find the &#8220;best&#8221; (shortest/longest/cheapest) path to the target!</figcaption></figure>
<p>Practically best-first search is identical with depth-first search, with the main difference that we choose the best-matching successor instead of choosing the first matching successor. So we’re sure that we’re going through all the successors but in some particular order, different from DFS. Thus we know that if there’s a path we’ll find it.</p>
<p>However even if we find the path between A and B, we can’t be sure that there is not a better path. We only know that this path is the best so far. </p>
<p>Another question is – how can we find the best matching successor effectively. Well if we’re looking for the minimal or maximal value one possible solution is to sort the array of successors.</p>
<figure id="attachment_3363" style="width: 620px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/09/5.-Using-Priority-Queues.png"><img src="/wp-content/uploads/2012/09/5.-Using-Priority-Queues.png" alt="Using Priority Queues" title="Using Priority Queues" width="620" height="412" class="size-full wp-image-3363" srcset="/wp-content/uploads/2012/09/5.-Using-Priority-Queues.png 620w, /wp-content/uploads/2012/09/5.-Using-Priority-Queues-300x199.png 300w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption class="wp-caption-text">The difference between depth-first and best-first is that we change the order of chosing the next successor!</figcaption></figure>
<pre lang="PHP">
0: [0 => 0, 1 => 2, 2 => 0, 3 => 0, 4 => 5, 5 => 1]
// sorted by value
0: [5 => 1, 1 => 2, 4 => 5, 0 => 0, 2 => 0, 3 => 1]
</pre>
<p>Another good approach will be to use priority queues or heaps.</p>
<p>Thus on every step we’ll get the best matching successor.</p>
<h2>Code</h2>
<p>In general best-first search uses the ground of depth-first search, so its implementation isn&#8217;t more difficult! The following PHP code snippet shows the very small difference between these two algorithms.</p>
<pre lang="PHP">
class Graph 
{
    protected $_len = 0;
    protected $_g = array();
    protected $_visited = array();
    
    public function __construct()
    {
        $this->_g = array(
            array(0, 2, 0, 0, 5, 1),
            array(1, 0, 3, 0, 0, 0),
            array(0, 2, 0, 8, 0, 0),
            array(0, 0, 3, 0, 5, 0),
            array(1, 0, 0, 8, 0, 1),
            array(1, 0, 0, 0, 5, 0),
        );
        
        $this->_len = count($this->_g);
        
        $this->_initVisited();
    }
    
    protected function _initVisited()
    {
        for ($i = 0; $i < $this->_len; $i++) {
            $this->_visited[$i] = 0;
        }
    }
    
    public function bestFirst($vertex)
    {
        $this->_visited[$vertex] = 1;
    
        echo $vertex . "\n";
        
        asort($this->_g[$vertex]);
        
        foreach ($this->_g[$vertex] as $key => $v) {
            if ($v > 0 && !$this->_visited[$key]) {
                $this->bestFirst($key);
            }
        }
    }
}

$g = new Graph();
// 2 1 0 5 4 3
$g->bestFirst(2);
</pre>
<h2>Application</h2>
<p>Best-first search is a typical greedy algorithm. In its principles lies the main greedy approach of chosing the best possible solution so far. It is important to note that depth-first search and breadth-first search are the very basic graph walk through approaches, but they can be also widely extended in order to solve more complex problems.</p>
<div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href="/2012/09/17/computer-algorithms-graph-depth-first-search/" rel="bookmark" title="Computer Algorithms: Graph Depth-First Search">Computer Algorithms: Graph Depth-First Search </a></li>
<li><a href="/2012/09/10/computer-algorithms-graph-breadth-first-search/" rel="bookmark" title="Computer Algorithms: Graph Breadth First Search">Computer Algorithms: Graph Breadth First Search </a></li>
<li><a href="/2012/10/15/computer-algorithms-dijkstra-shortest-path-in-a-graph/" rel="bookmark" title="Computer Algorithms: Dijkstra Shortest Path in a Graph">Computer Algorithms: Dijkstra Shortest Path in a Graph </a></li>
<li><a href="/2012/10/08/computer-algorithms-shortest-path-in-a-graph/" rel="bookmark" title="Computer Algorithms: Shortest Path in a Graph">Computer Algorithms: Shortest Path in a Graph </a></li>
</ol></p>
</div>
]]></content:encoded>
			<wfw:commentRss>/2012/09/24/computer-algorithms-graph-best-first-search/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Computer Algorithms: Finding the Lowest Common Ancestor</title>
		<link>/2012/08/24/computer-algorithms-finding-the-lowest-common-ancestor/</link>
		<comments>/2012/08/24/computer-algorithms-finding-the-lowest-common-ancestor/#comments</comments>
		<pubDate>Fri, 24 Aug 2012 12:54:54 +0000</pubDate>
		<dc:creator><![CDATA[Stoimen]]></dc:creator>
				<category><![CDATA[algorithms]]></category>
		<category><![CDATA[data structures]]></category>
		<category><![CDATA[B-tree]]></category>
		<category><![CDATA[Binary search tree]]></category>
		<category><![CDATA[binary search trees]]></category>
		<category><![CDATA[Binary trees]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[Graph theory]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[Lowest common ancestor]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[proper solution]]></category>
		<category><![CDATA[Rope]]></category>
		<category><![CDATA[Ternary tree]]></category>
		<category><![CDATA[Tree]]></category>
		<category><![CDATA[two algorithms]]></category>

		<guid isPermaLink="false">/?p=3314</guid>
		<description><![CDATA[Introduction Here’s one task related to the tree data structure. Given two nodes, can you find their lowest common ancestor? In a matter of fact this task always has a proper solution, because at least the root node is a common ancestor of all pairs of nodes. However here the task is to find the &#8230; <a href="/2012/08/24/computer-algorithms-finding-the-lowest-common-ancestor/" class="more-link">Continue reading <span class="screen-reader-text">Computer Algorithms: Finding the Lowest Common Ancestor</span> <span class="meta-nav">&#8594;</span></a><div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href="/2012/07/03/computer-algorithms-balancing-a-binary-search-tree/" rel="bookmark" title="Computer Algorithms: Balancing a Binary Search Tree">Computer Algorithms: Balancing a Binary Search Tree </a></li>
<li><a href="/2012/06/22/computer-algorithms-binary-search-tree-data-structure/" rel="bookmark" title="Computer Algorithms: Binary Search Tree">Computer Algorithms: Binary Search Tree </a></li>
<li><a href="/2012/08/07/computer-algorithms-heap-and-heapsort-data-structure/" rel="bookmark" title="Computer Algorithms: Heap and Heapsort">Computer Algorithms: Heap and Heapsort </a></li>
<li><a href="/2010/09/29/construct-a-sorted-php-linked-list/" rel="bookmark" title="Construct a Sorted PHP Linked List">Construct a Sorted PHP Linked List </a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<h2>Introduction</h2>
<p>Here’s one task related to the tree data structure. Given two nodes, can you find their lowest common ancestor? </p>
<p>In a matter of fact this task always has a proper solution, because at least the root node is a common ancestor of all pairs of nodes. However here the task is to find the lowest one, which can be quite far from the root. </p>
<figure id="attachment_3315" style="width: 620px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/08/1.-Finding-the-Lowest-Common-Ancestor.png"><img src="/wp-content/uploads/2012/08/1.-Finding-the-Lowest-Common-Ancestor.png" alt="Finding the Lowest Common Ancestor" title="Finding the Lowest Common Ancestor" width="620" height="362" class="size-full wp-image-3315" srcset="/wp-content/uploads/2012/08/1.-Finding-the-Lowest-Common-Ancestor.png 620w, /wp-content/uploads/2012/08/1.-Finding-the-Lowest-Common-Ancestor-300x175.png 300w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption class="wp-caption-text">Finding the Lowest Common Ancestor</figcaption></figure>
<p>We don’t care what kind of trees we have. However the solution, as we will see, can be very different depending on the tree type. Indeed finding the lowest common ancestor can have linear complexity for binary search trees, which isn’t true for ordinary trees.<span id="more-3314"></span></p>
<h2>Overview</h2>
<p>Let’s say we have a tree (not binary!) and two nodes from this tree. The task is to find their lowest common ancestor. The thing is that we don’t know much about where they appear to be in the tree. </p>
<p>We can think of this tree as a DOM tree of any single HTML page online. It is not binary or balanced and can’t be sure where these nodes are. </p>
<figure id="attachment_3317" style="width: 620px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/08/2.-Lowest-Common-Ancestor.png"><img src="/wp-content/uploads/2012/08/2.-Lowest-Common-Ancestor.png" alt="Lowest Common Ancestor" title="Lowest Common Ancestor" width="620" height="399" class="size-full wp-image-3317" srcset="/wp-content/uploads/2012/08/2.-Lowest-Common-Ancestor.png 620w, /wp-content/uploads/2012/08/2.-Lowest-Common-Ancestor-300x193.png 300w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption class="wp-caption-text">&nbsp;</figcaption></figure>
<p>First we must find both paths from the root to each one of the target nodes. Note that this requires additional memory! Then, in linear time we can pass through these “paths” and scan them from the root down to the nodes. We expect these to arrays to be equal at least in their first element (the root).  Using this scenario the lowest common ancestor is the last equal element in both arrays. </p>
<figure id="attachment_3318" style="width: 621px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/08/3.-Lowest-Common-Ancestor.png"><img src="/wp-content/uploads/2012/08/3.-Lowest-Common-Ancestor.png" alt="Lowest Common Ancestor Paths" title="Lowest Common Ancestor Paths" width="621" height="338" class="size-full wp-image-3318" srcset="/wp-content/uploads/2012/08/3.-Lowest-Common-Ancestor.png 621w, /wp-content/uploads/2012/08/3.-Lowest-Common-Ancestor-300x163.png 300w" sizes="(max-width: 621px) 100vw, 621px" /></a><figcaption class="wp-caption-text">Once we know the paths from the root down to the nodes, we can compare them in order to find the lowest common ancestor!</figcaption></figure>
<p>To see how this algorithm can be dramatically changed depending on the data structure, let’s see another example. Now let’s say we have a binary search tree (BST). We know that in a BST all the elements in the left sub-tree are smaller than the root and all the items on the right sub-tree are greater than the root. This is true also for the left and the right sub-trees.</p>
<p>Now because we’re searching the lowest common ancestor, we don’t need to collect the paths from the root to the nodes in two arrays. We just know that the greater items are on the right, while the smaller items are on the left. This can help us find the lowest ancestor starting directly from the root.</p>
<figure id="attachment_3319" style="width: 620px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/08/4.-Lowest-Common-in-a-BST.png"><img src="/wp-content/uploads/2012/08/4.-Lowest-Common-in-a-BST.png" alt="Lowest Common in a BST" title="Lowest Common in a BST" width="620" height="399" class="size-full wp-image-3319" srcset="/wp-content/uploads/2012/08/4.-Lowest-Common-in-a-BST.png 620w, /wp-content/uploads/2012/08/4.-Lowest-Common-in-a-BST-300x193.png 300w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption class="wp-caption-text">In a BST we compare both values with a given node (starting from the root). In case the node&#8217;s value is in between them &#8211; this is the lowest common ancestor. If not &#8211; we go either on the left or on the right!</figcaption></figure>
<p>What we do is to compare the two keys of the target nodes with the root key. If one of the keys are smaller, and the other is greater than the root&#8217;s key, then obviously the root is the lowest common ancestor. This is true because one of the items will be somewhere in the left sub-tree, while the other will be in the right sub-tree. </p>
<p>In case both values are greater (or smaller) than the root, we can move to the right (or to the left) sub-tree and try again with the same procedure. Thus the first node which key is in between the two target values will be the lowest common ancestor.</p>
<h2>Code</h2>
<p>Here’s a very simple PHP implementation showing us these two algorithms.</p>
<pre lang="PHP">
class Tree
{
    public $node = null;
    public $id = null;
    public $parent = null;
    public $children = array();
    
    public function __construct($node, $id = null)
    {
        $this->node = $node;
        $this->id = $id;
    }
    
    public function addChild(Node &$n)
    {
        $n->parent = $this;
        $this->children[] = $n;
    }
    
    /**
     * Returns an element by its id
     * 
     * @param mixed $id
     * @return Node 
     */
    public function search($id)
    {
        if ($this->id == $id) {
            return $this;
        }

        $a = false;
        
        // search all the children starting from the left-most
        foreach ($this->children as $child) {
            $a = $child->search($id);
        }
        
        return $a;
    }
    
    /**
     * Finds a path from the root to the 
     * item and returns it as a list
     * 
     * @param mixed $id 
     * @return array
     */
    public function find_path($id, &$path)
    {
        array_push($path, $this->id);
        
        if ($this->id == $id) {
            return 1;
        }
        
        foreach ($this->children as $child)  {
            if (1 == $child->find_path($id, $path)) return 1;
            array_pop($path);
        }
    }
    
    public function __toString()
    {
        return $this->node . ' ' . $this->id . "\n";
    }
}

$dom = new Tree('DOM', 'ROOT');

$body = new Tree('BODY', 1);
$div1 = new Tree('DIV', 'div-1');
$div2 = new Tree('DIV', 'my-id');

$a = new Tree("A", 'some-link');

$dom->addChild($body);
$body->addChild($div1);
$body->addChild($div2);
$div2->addChild($a);

$path1 = $path2 = array();
$dom->find_path('div-1', $path1);
$dom->find_path('some-link', $path2);
</pre>
<h3>Finding Lowest Common Ancestor in a BST</h3>
<pre lang="PHP">
class Tree
{
    public $key;
    
    public $parent  = null;
    public $left    = null;
    public $right   = null;
    
    public function __construct($key) 
    {
        $this->key = $key;
    }
    
    public function insert(Tree $n) 
    {
        if ($this->key < $n->key) {
            if ($this->right == null) {
                // insert
                $this->right = $n;
                $n->parent = $this;
            } else {
                $this->right->insert($n);
            }
        }
        if ($this->key > $n->key) {
            if ($this->left == null) {
                // insert
                $this->left = $n;
                $n->parent = $this;
            } else {
                $this->left->insert($n);
            }
        }
    }
}

$t = new Tree(10);

$n1 = new Tree(20);
$n2 = new Tree(5);
$n3 = new Tree(7);
$n4 = new Tree(13);

$t->insert($n1);
$t->insert($n2);
$t->insert($n3);

function find_common($node1, $node2, $tree) 
{
    if ($node1->key < $tree->key && $node2->key > $tree->key) {
        return $tree;
    } else if ($node1->key < $tree->key && $node2->key < $tree->key) {
        find_common($node1, $node2, $tree->left);
    } else if ($node1->key > $tree->key && $node2->key > $tree->key) {
        find_common($node1, $node2, $tree->right);
    }
}

$node = find_common($n3, $n4, $t);
</pre>
<h2>Application</h2>
<p>A typical use-case of this algorithm is finding the lowest common ancestor of two nodes in a DOM tree. Sometimes we just need to attach an event listener to both items (even before they are attached to the DOM!). Although attaching this event to the “document” will work just fine, all the elements from the nodes up to the root will be “capturing” these events due to event bubbling. Thus attaching the event to the lowest common ancestor is a better solution.</p>
<div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href="/2012/07/03/computer-algorithms-balancing-a-binary-search-tree/" rel="bookmark" title="Computer Algorithms: Balancing a Binary Search Tree">Computer Algorithms: Balancing a Binary Search Tree </a></li>
<li><a href="/2012/06/22/computer-algorithms-binary-search-tree-data-structure/" rel="bookmark" title="Computer Algorithms: Binary Search Tree">Computer Algorithms: Binary Search Tree </a></li>
<li><a href="/2012/08/07/computer-algorithms-heap-and-heapsort-data-structure/" rel="bookmark" title="Computer Algorithms: Heap and Heapsort">Computer Algorithms: Heap and Heapsort </a></li>
<li><a href="/2010/09/29/construct-a-sorted-php-linked-list/" rel="bookmark" title="Construct a Sorted PHP Linked List">Construct a Sorted PHP Linked List </a></li>
</ol></p>
</div>
]]></content:encoded>
			<wfw:commentRss>/2012/08/24/computer-algorithms-finding-the-lowest-common-ancestor/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Computer Algorithms: Binary Search</title>
		<link>/2011/12/26/computer-algorithms-binary-search/</link>
		<comments>/2011/12/26/computer-algorithms-binary-search/#comments</comments>
		<pubDate>Mon, 26 Dec 2011 13:14:25 +0000</pubDate>
		<dc:creator><![CDATA[Stoimen]]></dc:creator>
				<category><![CDATA[algorithms]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[binary search]]></category>
		<category><![CDATA[Binary search algorithm]]></category>
		<category><![CDATA[Control flow]]></category>
		<category><![CDATA[famous and best suitable search algorithm]]></category>
		<category><![CDATA[Fibonacci number]]></category>
		<category><![CDATA[Fibonacci search algorithm]]></category>
		<category><![CDATA[Fibonacci search technique]]></category>
		<category><![CDATA[Golden section search]]></category>
		<category><![CDATA[golden section search algorithm]]></category>
		<category><![CDATA[Jump search]]></category>
		<category><![CDATA[Mathematics]]></category>
		<category><![CDATA[Recursion]]></category>
		<category><![CDATA[Recursion theory]]></category>
		<category><![CDATA[recursive and iterative solution]]></category>
		<category><![CDATA[search algorithm]]></category>
		<category><![CDATA[search algorithms]]></category>
		<category><![CDATA[sequential search]]></category>
		<category><![CDATA[suitable search algorithm]]></category>
		<category><![CDATA[Theoretical computer science]]></category>
		<category><![CDATA[two algorithms]]></category>

		<guid isPermaLink="false">/?p=2538</guid>
		<description><![CDATA[Overview The binary search is perhaps the most famous and best suitable search algorithm for sorted arrays. Indeed when the array is sorted it is useless to check every single item against the desired value. Of course a better approach is to jump straight to the middle item of the array and if the item’s &#8230; <a href="/2011/12/26/computer-algorithms-binary-search/" class="more-link">Continue reading <span class="screen-reader-text">Computer Algorithms: Binary Search</span> <span class="meta-nav">&#8594;</span></a><div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href="/2012/01/02/computer-algorithms-interpolation-search/" rel="bookmark" title="Computer Algorithms: Interpolation Search">Computer Algorithms: Interpolation Search </a></li>
<li><a href="/2011/12/12/computer-algorithms-jump-search/" rel="bookmark" title="Computer Algorithms: Jump Search">Computer Algorithms: Jump Search </a></li>
<li><a href="/2012/07/03/computer-algorithms-balancing-a-binary-search-tree/" rel="bookmark" title="Computer Algorithms: Balancing a Binary Search Tree">Computer Algorithms: Balancing a Binary Search Tree </a></li>
<li><a href="/2011/11/24/computer-algorithms-sequential-search/" rel="bookmark" title="Computer Algorithms: Sequential Search">Computer Algorithms: Sequential Search </a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<h2>Overview</h2>
<p>The binary search is perhaps the most famous and best suitable search algorithm for sorted arrays. Indeed when the array is sorted it is useless to check every single item against the desired value. Of course a better approach is to jump straight to the middle item of the array and if the item’s value is greater than the desired one, we can jump back again to the middle of the interval. Thus the new interval is half the size of the initial one.</p>
<figure id="attachment_2561" style="width: 620px" class="wp-caption alignnone"><a href="/wp-content/uploads/2011/12/BinarySearchfig.1.png"><img class="size-full wp-image-2561" title="Binary Search fig.1" src="/wp-content/uploads/2011/12/BinarySearchfig.1.png" alt="Binary search basic implementation" width="620" srcset="/wp-content/uploads/2011/12/BinarySearchfig.1.png 959w, /wp-content/uploads/2011/12/BinarySearchfig.1-300x75.png 300w" sizes="(max-width: 959px) 100vw, 959px" /></a><figcaption class="wp-caption-text">Basic implementation of binary search</figcaption></figure>
<p>If the searched value is greater than the one placed at the middle of the sorted array, we can jump forward. Again on each step the considered list is getting half as long as the list on the previous step, as shown on the image bellow.</p>
<figure id="attachment_2564" style="width: 620px" class="wp-caption alignnone"><a href="/wp-content/uploads/2011/12/BinarySearchfig.2.png"><img src="/wp-content/uploads/2011/12/BinarySearchfig.2.png" alt="Binary search - basic implementation" title="Binary Search fig.2" width="620" class="size-full wp-image-2564" srcset="/wp-content/uploads/2011/12/BinarySearchfig.2.png 961w, /wp-content/uploads/2011/12/BinarySearchfig.2-300x65.png 300w" sizes="(max-width: 961px) 100vw, 961px" /></a><figcaption class="wp-caption-text">Binary search - basic implementation</figcaption></figure>
<h2>Implementation</h2>
<p>Here’s a sample implementation of this algorithm on <a href="/category/php/" title="PHP on stoimen.com">PHP</a>. Obviously the nature of this approach is guiding us to a recursive implementation, but as we know, sometimes recursion can be dangerous. That&#8217;s why here we can see either the recursive and iterative solution.<span id="more-2538"></span></p>
<h3>Recursive Binary Search</h3>
<pre lang="PHP">
$list = array(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144);
$x = 55;

function binary_search($x, $list, $left, $right) 
{
	if ($left > $right)
		return -1;
	
	$mid = ($left + $right) >> 1;

	if ($list[$mid] == $x) {
		return $mid;
	} elseif ($list[$mid] > $x) {
		return binary_search($x, $list, $left, $mid-1);
	} elseif ($list[$mid] < $x) {
		return binary_search($x, $list, $mid+1, $right);
	}
}

echo binary_search($x, $list, 0, count($list)-1);
</pre>
<h3>Iterative Binary Search</h3>
<pre lang="PHP">
$list = array(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144);
$x = 55;

function iterative_binary_search($x, $list) 
{
	$left = 0;
	$right = count($list)-1;
	
	while ($left <= $right) {
		$mid = ($left + $right) >> 1;
		
		if ($list[$mid] == $x) {
			return $mid;
		} elseif ($list[$mid] > $x) {
			$right = $mid - 1;
		} elseif ($list[$mid] < $x) {
			$left = $mid + 1;
		}
	}
	
	return -1;
}

echo iterative_binary_search($x, $list);
</pre>
<h2>Caution: Optimization</h2>
<p>Most of the optimization techniques mentioned online recommend to replace the expensive operation of dividing by 2 with its bitwise equivalent (n >> 1) == n/2. That is not always true and it is very dependant from the programming language. Thus in PHP those operations are fairly similar as PHP is written in C. You’ve to be aware of the language specific features when optimizing code.</p>
<h2>Fibonacci Search</h2>
<p>Every developer has heard of Fibonacci and his sequence. The Fibonacci search algorithm is practically a variation of the binary search algorithm. In fact the only difference is that the binary search algorithm divides the list into two equal parts, while the Fibonacci search divides it in two but not equal parts. In fact sometimes it is faster to search if you divide the list by such non equal sub-lists. However the length of the sub-lists is not random.</p>
<p>It is clear that the ratio of any two consecutive numbers in the Fibonacci sequence is practically forming the golden ratio. This can lead us to another variation of Fibonacci and binary search - the golden section search. The only different thing is that you’ve to divide the length of the list in two parts exactly by the golden ratio.</p>
<figure id="attachment_2563" style="width: 620px" class="wp-caption alignnone"><a href="/wp-content/uploads/2011/12/GoldenRatioSearch.png"><img src="/wp-content/uploads/2011/12/GoldenRatioSearch.png" alt="Golden Section Search" title="Golden Section Search" width="620" class="size-full wp-image-2563" srcset="/wp-content/uploads/2011/12/GoldenRatioSearch.png 960w, /wp-content/uploads/2011/12/GoldenRatioSearch-300x225.png 300w" sizes="(max-width: 960px) 100vw, 960px" /></a><figcaption class="wp-caption-text">The golden section search doesn&#039;t divide the array on two equal sub-lists!</figcaption></figure>
<p>The complexity both of the Fibonacci and the golden section search algorithm is identical with the complexity of the binary search. However these two algorithms are rarely used in practice. Also it is more difficult to implement these two algorithms than the binary search and their advantage depends on specifically dispersed data.</p>
<h2>Complexity</h2>
<p>The complexity of the binary search algorithm is intuitively clear - O(log(n)), which makes it far more effective than the sequential search.</p>
<figure id="attachment_2562" style="width: 600px" class="wp-caption alignnone"><a href="/wp-content/uploads/2011/12/chart_1.png"><img src="/wp-content/uploads/2011/12/chart_1.png" alt="log(n)" title="log(n)" width="600" height="371" class="size-full wp-image-2562" srcset="/wp-content/uploads/2011/12/chart_1.png 600w, /wp-content/uploads/2011/12/chart_1-300x185.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></a><figcaption class="wp-caption-text">f(n) = log(n) compared to f(n) = n</figcaption></figure>
<h2>Application</h2>
<p>It is useless to mention examples of its use. This algorithm is easy to implement and in the same times it is very fast. Yes, indeed, this algorithm is only possible on sorted lists and this is a limitation. Also, as I said, compared to the jump search here we have more than one jump back in most of the cases, which sometimes can be more expensive than jump forward. However is this the fastest search algorithm? I’ll try to answer this question in my next article.</p>
<div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href="/2012/01/02/computer-algorithms-interpolation-search/" rel="bookmark" title="Computer Algorithms: Interpolation Search">Computer Algorithms: Interpolation Search </a></li>
<li><a href="/2011/12/12/computer-algorithms-jump-search/" rel="bookmark" title="Computer Algorithms: Jump Search">Computer Algorithms: Jump Search </a></li>
<li><a href="/2012/07/03/computer-algorithms-balancing-a-binary-search-tree/" rel="bookmark" title="Computer Algorithms: Balancing a Binary Search Tree">Computer Algorithms: Balancing a Binary Search Tree </a></li>
<li><a href="/2011/11/24/computer-algorithms-sequential-search/" rel="bookmark" title="Computer Algorithms: Sequential Search">Computer Algorithms: Sequential Search </a></li>
</ol></p>
</div>
]]></content:encoded>
			<wfw:commentRss>/2011/12/26/computer-algorithms-binary-search/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
