<!--
    Licensed to the Apache Software  Foundation (ASF) under one or more
    contributor  license agreements.  See  the NOTICE  file distributed
    with  this  work  for  additional information  regarding  copyright
    ownership.   The ASF  licenses this  file to  you under  the Apache
    License, Version  2.0 (the  License); you may  not use  this file
    except in  compliance with the License.   You may obtain  a copy of
    the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the  License is distributed on an  "AS IS" BASIS,
    WITHOUT  WARRANTIES OR CONDITIONS  OF ANY  KIND, either  express or
    implied.   See  the License  for  the  specific language  governing
    permissions and limitations under the License.

    Copyright 1999-2007 Rogue Wave Software, Inc.
-->

<HTML>
<HEAD>
<TITLE>lexicographical_compare()</TITLE>
<LINK REL=StyleSheet HREF="../rw.css" TYPE="text/css" TITLE="Apache stdcxx Stylesheet"></HEAD>
<BODY BGCOLOR=#FFFFFF>
<A HREF="less-equal.html"><IMG SRC="images/bprev.gif" WIDTH=20 HEIGHT=21 ALT="Previous file" BORDER=O></A><A HREF="noframes.html"><IMG SRC="images/btop.gif" WIDTH=56 HEIGHT=21 ALT="Top of Document" BORDER=O></A><A HREF="booktoc.html"><IMG SRC="images/btoc.gif" WIDTH=56 HEIGHT=21 ALT="Contents" BORDER=O></A><A HREF="tindex.html"><IMG SRC="images/bindex.gif" WIDTH=56 HEIGHT=21 ALT="Index page" BORDER=O></A><A HREF="limits-h.html"><IMG SRC="images/bnext.gif" WIDTH=25 HEIGHT=21 ALT="Next file" BORDER=O></A><DIV CLASS="DOCUMENTNAME"><B>Apache C++ Standard Library Reference Guide</B></DIV>
<H2>lexicographical_compare()</H2>
<P><B>Library:</B>&nbsp;&nbsp;<A HREF="2-9.html">Algorithms</A></P>

<PRE><HR><B><I>Function</I></B><HR></PRE>

<UL>
<LI><A HREF="#sec1">Local Index</A></LI>
<LI><A HREF="#sec2">Summary</A></LI>
<LI><A HREF="#sec3">Synopsis</A></LI>
<LI><A HREF="#sec4">Description</A></LI>
<LI><A HREF="#sec5">Complexity</A></LI>
<LI><A HREF="#sec6">Example</A></LI>
<LI><A HREF="#sec7">Standards Conformance</A></LI>
</UL>
<A NAME="sec1"><H3>Local Index</H3></A>
No Entries
<A NAME="sec2"><H3>Summary</H3></A>
<P>Algorithm that returns <SAMP>true</SAMP> if one sequence compares lexicographically less than another, <SAMP>false</SAMP> otherwise</P>
<A NAME="sec3"><H3>Synopsis</H3></A>

<PRE>#include &lt;algorithm&gt;

namespace std {
  template &lt;class InputIterator1, class InputIterator2&gt;
  bool
  lexicographical_compare(InputIterator1 start1,
                          InputIterator1 finish1,
                          InputIterator2 start2,
                          InputIterator2 finish2);

  template &lt;class InputIterator1, class InputIterator2, 
            class Compare&gt;
   bool
   lexicographical_compare(InputIterator1 start1,
                           InputIterator1 finish1,
                           InputIterator2 start2,
                           InputIterator2 finish2, 
                           Compare comp);
}
</PRE>
<A NAME="sec4"><H3>Description</H3></A>
<P>The <SAMP>lexicographical_compare()</SAMP> functions compare each element in the range <SAMP>[start1, finish1)</SAMP> to the corresponding element in the range <SAMP>[start2, finish2)</SAMP> using iterators <SAMP>i</SAMP> and <SAMP>j</SAMP>. </P>
<P>The first version of the algorithm uses <SAMP>operator&lt;()</SAMP> as the default comparison operator. It immediately returns <SAMP>true</SAMP> if it encounters any pair in which <SAMP>*i</SAMP> is less than <SAMP>*j</SAMP>, and immediately returns <SAMP>false</SAMP> if <SAMP>*j</SAMP> is less than <SAMP>*i</SAMP>. If the algorithm reaches the end of the first sequence before reaching the end of the second sequence, it also returns <SAMP>true</SAMP>. </P>
<P>The second version of the function takes an argument <SAMP>comp</SAMP> that defines a comparison function that is used in place of the default <SAMP>operator&lt;()</SAMP>.</P>
<P>The <SAMP>lexicographical_compare()</SAMP> functions can be used with all the data types included in the standard library.</P>
<A NAME="sec5"><H3>Complexity</H3></A>
<P><SAMP>lexicographical_compare()</SAMP> performs at most <SAMP>min((finish1 - start1), (finish2  -  start2))</SAMP> applications of the comparison function.</P>
<A NAME="sec6"><H3>Example</H3></A>

<UL><PRE>//
//  lex_comp.cpp
//

#include &lt;algorithm&gt;
#include &lt;functional&gt;
#include &lt;iostream&gt;
#include &lt;vector&gt;

int main()
{
    typedef std::vector&lt;int, std::allocator&lt;int&gt; &gt; Vector;

    const Vector::value_type d1[] = { 1, 3, 5, 32, 64 };     
    const Vector::value_type d2[] = { 1, 3, 2, 43, 56 };

    // Create vectors.
    Vector v1 (d1 + 0, d1 + sizeof d1 / sizeof *d1);
    Vector v2 (d2 + 0, d2 + sizeof d1 / sizeof *d2);

    // Is v1 less than v2 (I think not).
    bool b1 = std::lexicographical_compare (v1.begin (), 
                      v1.end (), v2.begin (), v2.end ());
 
    // Is v2 less than v1 (yup, sure is).
    bool b2 = std::lexicographical_compare(v2.begin (), 
                      v2.end (), v1.begin (), v1.end (),
                      std::less&lt;int&gt;());

    std::cout &lt;&lt; std::boolalpha &lt;&lt; b1
              &lt;&lt; " " &lt;&lt; b2 &lt;&lt; std::endl;

    return 0;
}


Program Output:
</PRE></UL>
<UL><PRE>false true

</PRE></UL>
<A NAME="sec7"><H3>Standards Conformance</H3></A>
<P><I>ISO/IEC 14882:1998 -- International Standard for Information Systems -- Programming Language C++, Section 25.3.8</I></P>

<BR>
<HR>
<A HREF="less-equal.html"><IMG SRC="images/bprev.gif" WIDTH=20 HEIGHT=21 ALT="Previous file" BORDER=O></A><A HREF="noframes.html"><IMG SRC="images/btop.gif" WIDTH=56 HEIGHT=21 ALT="Top of Document" BORDER=O></A><A HREF="booktoc.html"><IMG SRC="images/btoc.gif" WIDTH=56 HEIGHT=21 ALT="Contents" BORDER=O></A><A HREF="tindex.html"><IMG SRC="images/bindex.gif" WIDTH=56 HEIGHT=21 ALT="Index page" BORDER=O></A><A HREF="limits-h.html"><IMG SRC="images/bnext.gif" WIDTH=20 HEIGHT=21 ALT="Next file" BORDER=O></A>

<!-- Google Analytics tracking code -->
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
    _uacct = "UA-1775151-1";
    urchinTracker();
</script>
<!-- end of Google Analytics tracking code -->

</BODY>
</HTML>
