Un ejemplo muy sencillo de entender... es la jerarquía de ficheros del PC...
Sabrás bien que una carpeta puede contener ficheros y otras carpetas. Y cada carpeta interna, igualmente puede contener más ficheros y más subcarpetas, y esas... lo mismo.
Entonces se plantea... cómo recorrer cada carpeta?. La recursividad simplifica enormemente el proceso de dicho recorrido.
Imagineos que se nos pide el tamaño total que ocupa una carpeta con todo su contenido...
entero = funcion RecorrerCarpetas( string Ruta)
string fichero, carpeta
entero size
por cada fichero en ruta
size += fichero.length
siguiente
por cada carpeta en ruta
size += RecorrerCarpetas(carpeta) //<--------- aquí la recursividad.
siguiente
devolver size
fin funcion
Hay dos bucles dentro de esa función, el primero recorge el tamaño de cada fichero suelto en esa carpeta.
El segundo bucle recoge cada carpeta que mantiene la ruta... y como cada carpeta puede contener más carpetas y o ficheros, hace una llamada a la función que totaliza el contenido de dicha carpeta, que curiosamente es la misma función en la que está.
Eso es la recursividad, una función que directamente se llama a sí misma (o indirectamwente a través de otra).
Todo lo que tenga una estructura arbórea es factible de ser recorrido recursivamente, aunque hay más situacione en programación, por ejemplo al tratar con combinatoria, utilizar recursividad puede simplificar ciertas operaciones.
La recursividad debe limitarse a ser usado cuando es preciso, siempre que se pueda es preferible usar iteratividad, pero hay determinadas situaciones, en las que diseñar bucles iterativos es mucho más complejo que bucles iterativos.
El mismo ejemplo anterior utilizando bucles iterativos sería bastante más engorroso... puedes intentarlo, si quieres.