CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Greg Young [MVP]


Bread Crumb Trail

Had someone ask an interesting question the other day ... they wanted to serialize call stacks with data in an object, obviously this can't be done. My initial response was to tell them to use a state machine to get around this but it turned out they were doing a depth first search. Since it was a large depth first search they wanted to remember where they were and survive process shut down. I hacked together something in a few minutes as an example.

 

I am just throwing this code up so I don't lose it and it may be of use to someone else in the future, it is a resumable depth first search. You could do this on an object graph etc so long as the traversal maintains a reference to the graph (so when serialized/deserialized the external objects came back the same). Code is just a simple example of using a crumb trail to remember where you were in recursion so you can re-enter where you left.

 Note this is not thread safe and will only work for one thread. You could make this much more generic, its a quick example on the key feature.

    public class PositionSavingTraversal<T>
    {
       
        private List<T> m_Data;
        private int[] m_Positions;
        public PositionSavingTraversal(IEnumerable<T> _Data)
        {
            m_Data = new List<T>(_Data); //copy to our local list
            m_Positions = new int[m_Data.Count];
        }

        public void Recurse()
        {
            RecurseInternal(0);
            Console.WriteLine("Recursion completed");
        }

        public void RecurseInternal(int _CurrentDepth)
        {
            if (_CurrentDepth == m_Data.Count)
            {
                return;
            }
            if (m_Positions[_CurrentDepth] == m_Data.Count)
            {
                m_Positions[_CurrentDepth] = 0;
            }
            while (m_Positions[_CurrentDepth] < m_Data.Count)
            {
                if (m_Data.Count - _CurrentDepth > 7)
                {
                    Console.WriteLine(new string('\t', _CurrentDepth) + m_Positions[_CurrentDepth]);
                }
                RecurseInternal(_CurrentDepth + 1);
                m_Positions[_CurrentDepth]++;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            int[] test = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            PositionSavingTraversal<int> foo = new PositionSavingTraversal<int>(test);
            while (true)
            {
                Thread t = new Thread(new ThreadStart(foo.Recurse));
                t.Start();
                Console.WriteLine("Thread started, press enter to kill thread");
                Console.ReadLine();
                t.Abort();
                Console.WriteLine("press enter to start new thread and resume");
                Console.ReadLine();
            }
        }
    }
 

p.s. answers are written up for quiz and will be posted tonight so if you want to wager a quick guess today is the time to do it. 



Comments

Radu Grigore said:

Sometimes it might be easier to just not use recursion.
# August 13, 2007 2:24 PM

Greg said:

Yes absolutely (this case could easily be done without recursion) but this is just a simple example (to show the method), often times its harder to make non-recursive.

# August 13, 2007 4:26 PM

Jason Haley said:

# August 14, 2007 9:47 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!