Sunday, August 14, 2011

Tree Traversals

I had  recently written a small basic program on various tree traversal methods and ways to build a tree give Pre-order,Post-order and In-order here is the complete code snippet for the same.

//----------------------------------------------------------------------------------------
int In[17]   = {75,24,27,39,73,43,91,14,8,70,87,99,9,25,0,45,13}; /* In   Order  */
int Pre[17]  = {8,14,39,24,75,27,43,73,91,45,9,87,70,99,25,0,13}; /* Pre  Order  */
int Post[17] = {75,27,24,73,91,43,39,14,70,99,87,0,25,9,13,45,8}; /* Post Order  */
//----------------------------------------------------------------------------------------

int iLastIndex = 16;
class TreeNode
{
public:
      TreeNode* pLeft;
      TreeNode* pRight;
      int data;
/*This variable(index) is used only while building a tree using iteration*/
      int index;
};

TreeNode* pRoot=NULL;


TreeNode* makeNode()
{
      TreeNode* pNode =  new TreeNode();
      pNode->pLeft=NULL;
      pNode->pRight=NULL;
      return pNode;
}
int findNewRtIndex(int data)
{
      for(int i=0;i<=iLastIndex;i++)
      {
            if(In[i] == data )
            {
                  return i;  
            }
      }
}
void AddToTree(TreeNode* pParent , TreeNode* pNode)
{
     
      if(pNode->index <= pParent->index)
      {
            if(pParent->pLeft!=NULL)
                  AddToTree(pParent->pLeft,pNode);
            else
                  pParent->pLeft=pNode;
      }
      if(pNode->index > pParent->index)
      {
            if(pParent->pRight!=NULL)
                  AddToTree(pParent->pRight,pNode);
            else
                  pParent->pRight = pNode;
      }

}
/*
This function tries build a tree using the Pre-order and In-Order   Traversals without Recursion.
This is a a nice function in the sense that it builds the tree based on the index instead of the actual Pre/In order traversals, It needs and additional member variable called index for the same purpose.
*/
void makeTreeWithPreAndInUsingIteration(int iEndIndex)
{
      TreeNode* pNode=NULL;
      pRoot = makeNode();
      pRoot->data = Pre[0];
      pRoot->index =  findNewRtIndex(Pre[0]);
      for(int i=0;i<=iEndIndex;i++)
      {
            int iInIndex =  findNewRtIndex(Pre[i]);
            pNode = makeNode();
            pNode->index = iInIndex;
            pNode->data = Pre[i];
            AddToTree(pRoot,pNode);
      }
}

/*This function tries build a tree using the Pre-order and In-Order Traversals using Recursion*/
void makeTreeWithPreAndIn(TreeNode* pNode,int iStIndex,int iEndIndex)
{
     
      static int iCurIndex = -1;
      int iNewRtIndex =-1;
      if(iStIndex>iEndIndex)
            return;
      if(iCurIndex==-1)
      {
            iNewRtIndex =  findNewRtIndex(Pre[0]);
            iCurIndex =0;
            pRoot = makeNode();
            pRoot->data = Pre[0];
            pNode =  pRoot;
            pNode->pLeft  =  makeNode();
            pNode->pRight =  makeNode();
      }
      else
      {
            iNewRtIndex = findNewRtIndex(Pre[++iCurIndex]);
           
            pNode->data   = In[iNewRtIndex];
            pNode->pLeft  =  makeNode();
            pNode->pRight =  makeNode();
           
      }
      if(iStIndex==iEndIndex)
            return;
      makeTreeWithPreAndIn(pNode->pLeft,iStIndex,iNewRtIndex-1);
      makeTreeWithPreAndIn(pNode->pRight,iNewRtIndex+1,iEndIndex);
}
/* This function tries build a tree using the Post-order and In-Order Traversals using Recursion*/
TreeNode* makeTreeWithPostAndIn(int iStIndex,int iEndIndex)
{
      static int iCurIndex = -1;
      TreeNode* pNode=NULL;
      int iNewRtIndex =-1;
      if(iStIndex>iEndIndex)
            return pNode;
      if(iCurIndex==-1)
      {
            iNewRtIndex =  findNewRtIndex(Post[iLastIndex]);
            iCurIndex = iLastIndex;
            pRoot = makeNode();
            pRoot->data = Post[iLastIndex];
            pNode =  pRoot;
           
      }
      else
      {
            iNewRtIndex = findNewRtIndex(Post[--iCurIndex]);
            pNode = makeNode();
            pNode->data   = In[iNewRtIndex];
           
      }
      if(iStIndex==iEndIndex)
            return pNode;
     
      pNode->pRight = makeTreeWithPostAndIn(iNewRtIndex+1,iEndIndex);
     
      pNode->pLeft = makeTreeWithPostAndIn(iStIndex,iNewRtIndex-1);

      return pNode;
}



/* This function does Pre-order traversal of the tree using iteration.*/
void IterativePreOrderTraversal()
{
      std::stack<TreeNode*>   stck;
      stck.push(pRoot);
      while(!stck.empty())
      {
            TreeNode* pNode  =(TreeNode*)  stck.top();
            stck.pop();
            if(pNode->pRight!=NULL)
            {
                  stck.push(pNode->pRight);
            }
            if(pNode->pLeft!=NULL)
            {
                  stck.push(pNode->pLeft);
            }
            cout<<pNode->data<<endl;

      }
}

/* This function does Post-order traversal of the tree using iteration.*/
void IterativePostOrderTraversal()
{
      std::stack<TreeNode*>   stck;
      stck.push(pRoot);
      while(!stck.empty())
      {
            TreeNode* pNode  =(TreeNode*)  stck.top();
            stck.pop();
           
            if(pNode->pLeft!=NULL)
            {
                  stck.push(pNode->pLeft);
            }
            if(pNode->pRight!=NULL)
            {
                  stck.push(pNode->pRight);
            }
            cout<<pNode->data<<endl;

      }
}

/* This function does In-order traversal of the tree using iteration.*/
void IterativeInOrderTraversal()
{
      std::stack<TreeNode*>stck;
      stck.push(pRoot);
      TreeNode* pNode = pRoot;
      while(!stck.empty())
      {
            if(pNode!=NULL)
            {
                             
                  stck.push(pNode);
                  pNode = pNode->pLeft;
                  continue;
            }
            else
            {
                  if(!stck.empty())
                  {
                        pNode = (TreeNode*) stck.top();
                        stck.pop();
                        if(!stck.empty())
                        {
                              cout<<pNode->data<<endl;
                              pNode = (TreeNode*)pNode->pRight;
                        }
                        else
                              break;
                 
                  }
                  else
                        break;
            }
           
      }
}

int _tmain(int argc, _TCHAR* argv[])
{
      //makeTreeWithPreAndIn(NULL,0,16);
      cout<<"-------------------------------------------"<<endl;
      //makeTreeWithPostAndIn(NULL,0,16);
      pRoot = makeTreeWithPostAndIn(0,16);
      cout<<"-------------------------------------------"<<endl;
      //makeTreeWithPreAndInUsingIteration(16);
      cout<<"-------------------------------------------"<<endl;
      IterativePreOrderTraversal();
      cout<<"-------------------------------------------"<<endl;
      IterativePostOrderTraversal();
      cout<<"-------------------------------------------"<<endl;
      IterativeInOrderTraversal();
      cout<<"-------------------------------------------"<<endl;
      return 0;
}

Saturday, August 13, 2011

Perils of using W2A

Ever wondered why W2A leaks a lot of memory when used in a loop?

for(int i=0;i<count;i++)
{
      str= W2A(bstr);
      cout<<str<<endl;
           
}
When we try and step in at W2A we end up with following ASM code.
*********************************************************************************
_alloca_probe_16 proc                   ; 16 byte aligned alloca

        push    ecx
        lea     ecx, [esp] + 8          ; TOS before entering this function
        sub     ecx, eax                ; New TOS
        and     ecx, (16 - 1)           ; Distance from 16 bit align (align down)
        add     eax, ecx                ; Increase allocation size
        sbb     ecx, ecx                ; ecx = 0xFFFFFFFF if size wrapped around
        or      eax, ecx                ; cap allocation size on wraparound
        pop     ecx                     ; Restore ecx
        jmp     _chkstk
***********************************************************************************
What we see here is the stack is resized as in, W2A does an allocation on the stack
      so what would happen when this goes in a loop? obvious answer would be, the stack
      grows, and ends up with Stack Overflow problem.

So we end up with a couple of questions..
1.What is the best way takle this problem.
2.Are there any alternatives.
      3.Why USES_CONVERSION MACRO when we use W2A.

1.One way is to manually convert it CString like this function MyW2A
  does.

CString MyW2A(BSTR bstr)
{
      CString s;
      If(bstr!=NULL)
{
      LPSTR p = s.GetBuffer(SysStringLen(bstr) + 1);
      ::WideCharToMultiByte(CP_ACP,           
                                      0,                
                                      bstr,                 
                                      -1,                // assume NUL-terminated
                                      p,                
                                      SysStringLen(bstr)+1,
                                      NULL,             
                                      NULL);            
      s.ReleaseBuffer();
      }
      return s;
}//MyW2A
     
JNM(Joseph NewComer) has a very good article on String management here


      2. CW2A which has been provided as part of ATL 7.0 can be used instead of W2A,
                another cool thing about this is, USES_CONVERSION is not required for CW2A.


3. Why do we need, USES_CONVERSION MACRO when we use W2A?
   The answer lies in Atlconv.h file and the way these macros have been defined.
  
/*
*where is the _lpw defined?
*where is _convert defined?
*where is _acp defined?
*/
   #define W2A(lpw) (\
      ((_lpw = lpw) == NULL) ? NULL : (\
            (_convert = (lstrlenW(_lpw)+1), \
            (_convert>INT_MAX/2) ? NULL : \
            ATLW2AHELPER((LPSTR) alloca(_convert*sizeof(WCHAR)), _lpw, 
   _convert*sizeof(WCHAR), _acp))))

/*
* U guessed it right? Look at the definition of USES_CONVERSION
* Simple right!!!
*/
#define USES_CONVERSION int _convert = 0; (_convert);\
UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/;\
(_acp); LPCWSTR _lpw = NULL; (_lpw); \
LPCSTR _lpa = NULL; (_lpa)

Another clue would be when we compile without the USES_CONVERSION macro, we end up with the following errors.

1>c:\..\vc days\.....\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_lpw' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_convert' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_lpw' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_convert' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_convert' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_lpw' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_convert' : undeclared identifier
1>c:\..\vc days\......\w2atest\w2atest\w2atest.cpp(45) : error C2065: '_acp' : undeclared identifier