//----------------------------------------------------------------------
//  IMPLEMENTATION FILE (treesort.cpp)
//  This module exports a function to sort an integer vector
//  into ascending order.
//----------------------------------------------------------------------
#include "treesort.h"
#include "inttree.h"    // For IntTree objects and operations
#include <stddef.h>     // For NULL

//  Algorithm: tree sort

//------------------------------------------------------------------
// Note:
// EMPTY is a constant used to signify a node with no data contents.
// The value of EMPTY must be chosen to compare greater than
// any actual data value in a tree.
//    The value below is machine dependent!
//------------------------------------------------------------------
const int EMPTY = 32767;

void BuildLeafTree( NodePtr, int, int&, const int[], int );
void Treesort( IntTree&, int[], int );
void PromoteSmallest( NodePtr );
void FillVacancies( NodePtr );

void Sort( /* inout */ int vec[],
           /* in */    int vSize )
    //..................................................................
    // PRE:  Assigned(vSize)  &&  Assigned(vec[0..vSize-1])
    // POST: vec[0..vSize-1] contain same values as
    //       vec[0..vSize-1]<entry> but are sorted into ascending order
    //..................................................................
{
    IntTree leafTree;
    int vecIndx = 0;

    leafTree.BuildRoot(EMPTY);
    BuildLeafTree(leafTree.Root(), 1, vecIndx, vec, vSize);
    // ASSERT: leafTree is a binary tree with all nodes containing EMPTY
    //         except the leftmost leaves, which contain vec[0..vSize-1]                      
    Treesort(leafTree, vec, vSize );
}

void BuildLeafTree( /* in */    NodePtr   ptr,
                    /* in */    int       levelNodeCount,
                    /* inout */ int&      vecIndx,
                    /* in */    const int vec[],
                    /* in */    int       vSize          )
    //..................................................................
    // PRE:  *ptr is the root of a binary tree
    // POST: *ptr is the root of a binary tree with all nodes
    //       containing EMPTY except the leftmost leaves, which
    //       contain vec[vecIndx..vSize-1]
    //..................................................................
{
    if (levelNodeCount >= vSize) {   // Have reached leaf
        if (vecIndx < vSize) {
            Store(ptr, vec[vecIndx]);
            vecIndx++;
        }
    }
    else {
        AppendLeft(ptr, EMPTY);
        BuildLeafTree(LChild(ptr), levelNodeCount*2, vecIndx, vec, vSize);
        AppendRight(ptr, EMPTY);
        BuildLeafTree(RChild(ptr), levelNodeCount*2, vecIndx, vec, vSize);
    }
}

void Treesort( /* inout */ IntTree& someTree,
               /* out */   int      resultVec[],
               /* in */    int      vSize       )
    //..................................................................
    // PRE:  vSize > 1
    //    && someTree is a full binary tree of at least 3 nodes
    //       and all nodes contain EMPTY, except for the
    //       leftmost vSize leaves
    // POST: resultVec[0..vSize-1] contain same values as the leaves
    //       of someTree<entry>, arranged in ascending order
    //    && All nodes of someTree contain EMPTY
    //..................................................................
{
    // Phase 1 of treesort
    PromoteSmallest(someTree.Root());

    // Phase 2 of treesort
    int i;
    for (i = 0; i < vSize; i++) {
                    // INV (prior to test):
                    //     resultVec[0..i-1] contain the first i sorted
                    //       values from the leaves of someTree<entry>
                    //  && All values remaining in someTree
                    //       are >= resultVec[i-1]
                    //  && i <= vSize
        resultVec[i] = Data(someTree.Root());
        FillVacancies(someTree.Root());
    }
}

void PromoteSmallest( /* in */ NodePtr ptr )
    //..................................................................
    // PRE:  *ptr is the root of a binary tree
    // POST: The node *ptr contains the smallest data value in the tree
    //    && The root of every subtree of *ptr contains the smallest
    //       data value in that subtree
    //..................................................................
{
    if (LChild(LChild(ptr)) == NULL)
        if (Data(LChild(ptr)) <= Data(RChild(ptr))) {
            Store(ptr, Data(LChild(ptr)));
            Store(LChild(ptr), EMPTY);
        }
        else {        // Right child value less than left child's
            Store(ptr, Data(RChild(ptr)));
            Store(RChild(ptr),EMPTY);
        }
    else {              // Children have not yet been promoted to
        PromoteSmallest(LChild(ptr));
        PromoteSmallest(RChild(ptr));
        if (Data(LChild(ptr)) <= Data(RChild(ptr))) {
            Store(ptr, Data(LChild(ptr)));
            FillVacancies(LChild(ptr));
        }
        else {        // Right child value less than left child's
            Store(ptr, Data(RChild(ptr)));
            FillVacancies(RChild(ptr));
        }
    }
}

void FillVacancies( /* in */ NodePtr justPromoted )
    //..................................................................
    // PRE:  Value in node *justPromoted has just been promoted
    // POST: Value in *justPromoted filled in with value promoted from
    //       its left or right child
    //    && All ensuing vacancies filled in by subsequent promotions
    //    && Final vacated node contains the value EMPTY
    //..................................................................
{
    NodePtr vacantPtr = justPromoted;

    while (LChild(vacantPtr) != NULL &&
           (Data(LChild(vacantPtr)) != EMPTY ||
            Data(RChild(vacantPtr)) != EMPTY))

        if (Data(LChild(vacantPtr)) < Data(RChild(vacantPtr))) {
            Store(vacantPtr, Data(LChild(vacantPtr)));
            vacantPtr = LChild(vacantPtr);
        }
        else {        // Right child value less than left child's
            Store(vacantPtr, Data(RChild(vacantPtr)));
            vacantPtr = RChild(vacantPtr);
        }
    Store(vacantPtr, EMPTY);
}


