In fact, searching for depth at first (or even wide) is not enough. You need a more spectacular more complex algorithm.
For example, suppose that there exists a graph with nodes {a, b, c, d} and edges {(a, b), (b, c), (b, d), (d, c)}, where an edge ( x, y) is an edge from x to y. (looks something like this, with all edges pointing down).
(a) | | (b) / \ (d) | | | \ / (c)
Then, doing the depth of the first search, you can visit node a, then b, then c, then go back to c, then visit d, and finally visit c again and end the loop when that doesn't happen. A similar thing happens with the first.
What you need to do is keep track of which sites you are visiting in the middle. In the above example, when the algorithm reaches (d), it completed a visit to (c), but not (a) or (b). So revising the finished node is fine, but visiting the unfinished node means you have a loop. The usual way to do this is to color each node white (not yet visited), gray (visiting descendants) or black (completing the visit).
here is some kind of pseudo code!
define visit(node n): if n.colour == grey: //if we're still visiting this node or its descendants throw exception("Cycle found") n.colour = grey //to indicate this node is being visited for node child in n.children(): if child.colour == white: //if the child is unexplored visit(child) n.colour = black //to show we're done visiting this node return
then starting a visit (root_node) will throw an exception if and only if there is a loop (initially all nodes should be white).
Sorry, if you already know all this, it is possible that you meant the depth of the first search anyway, but I hope this helps.