There are a number of things that can cause different execution plans. First up, and usually the most common, is parameter sniffing. A value is passed to a stored procedure. Said value returns, for our example, 100 rows. An execution plan optimized around returning 100 rows is created. Data changes occur on the table. Statistics get updated. Your query gets marked for recompile. Next time it gets executed, a new value, this time returning 100,000 rows is passed. A new plan, optimized for 100,000 rows is created.
You can get the same effect with hard coded values too. It doesn't have to be a parameter. Also, in the case of recompiles, local variables can be sniffed and their precise value can lead to different row estimates, again, resulting in different plans.
You can also get different plans if you have different connections using different ANSI settings. These can compile into different plans for the same query.
There's probably a couple of other reasons I'm not remembering at the moment. However, the data distribution and row estimates are usually the driver for different plans. I have a query I demonstrate from the AdventureWorks database that can produce up to 8 different plans, based on the values in a single column in one table. It's just a question of getting the recompile to get the optimizer to pick different row counts based on the parameter value.