finding boundary elements in cartesian grid
Headers

I had to ditch the non-standard and missing "stdafx.h", add &lt;algorithm&gt; and fix the spelling of &lt;iostream&gt; to compile this.

Correct std::size_t

This type is consistently written as size_t without its namespace prefix, which is not portable.

Cell type

struct cell could simply be a std::pair, but there may be benefit to stronger typing as you have it.  I recommend you prefer initialization of members rather than assignment (and that conveniently allows us to simply omit the constructor).  We can also change the == operator to take a reference and make it const (we could lean on std::tuple for the implementation, but it doesn't seem worth it for two members and only one operator).

struct cell
{
    const std::size_t x;
    const std::size_t y;

    bool operator==(const cell&amp; a) const { return a.x == x &amp;&amp; a.y == y; }
};


Algorithm

Repeatedly searching for elements looks like a very time-consuming way of examining every cell.  Instead, we could just iterate over the known cells and update a set of minima and maxima for its row and column:

#include &lt;iostream&gt;
#include &lt;map&gt;
#include &lt;set&gt;
#include &lt;utility&gt;
#include &lt;vector&gt;

struct cell
{
    const std::size_t x;
    const std::size_t y;
};

int main()
{
    std::vector&lt;cell&gt; cartesian = {
        {0, 1}, {0, 2}, {0, 3},
        {1, 2}, {1, 3}, {1, 4}, {1, 5},
        {2, 1}, {2, 2}, {2, 3}, {2, 4}, {2, 5},
        {3, 0}, {3, 1}, {3, 2}, {3, 3}, {3, 4}, {3, 5}, {3, 6},
        {4, 2}, {4, 3}, {4, 4}, {4, 5}, {4, 6}
    };

    // map each row and column to (min,max) filled cell in that column
    std::map&lt;std::size_t, std::pair&lt;std::size_t,std::size_t&gt;&gt; row_range;
    std::map&lt;std::size_t, std::pair&lt;std::size_t,std::size_t&gt;&gt; column_range;

    for (const auto&amp; c: cartesian) {
        auto rit = row_range.find(c.y);
        if (rit != row_range.end()) {
            auto&amp; row = rit-&gt;second;
            if (c.x &lt; row.first) {
                row.first = c.x;
            } else if (row.second &lt; c.x) {
                row.second = c.x;
            }
        } else {
            row_range.insert({c.y, {c.x, c.x}});
        }

        auto cit = column_range.find(c.x);
        if (cit != column_range.end()) {
            auto&amp; col = cit-&gt;second;
            if (c.y &lt; col.first) {
                col.first = c.y;
            } else if (col.second &lt; c.y) {
                col.second = c.y;
            }
        } else {
            column_range.insert({c.x, {c.y, c.y}});
        }
    }

    // show the results for column 0
    const auto zr = column_range[0];

    std::cout  &lt;&lt; zr.first &lt;&lt; ',' &lt;&lt; zr.second &lt;&lt; std::endl;
}


We can refactor the part that's common to rows and columns into a small helper method:

using range_map = std::map&lt;std::size_t, std::pair&lt;std::size_t,std::size_t&gt;&gt;;

static void update_min_max(range_map&amp; ranges, std::size_t index,
                           std::size_t value)
{
    auto it = ranges.find(index);
    if (it != ranges.end()) {
        auto&amp; range = it-&gt;second;
        if (value &lt; range.first) {
            range.first = value;
        } else if (range.second &lt; value) {
            range.second = value;
        }
    } else {
        ranges.insert({index, {value, value}});
    }
}


And then the loop becomes

    range_map row_range;
    range_map column_range;

    for (const auto&amp; c: cartesian) {
        update_min_max(row_range, c.y, c.x);
        update_min_max(column_range, c.x, c.y);
    }