diff --git a/YASI_12/YASI_12.vcxproj b/YASI_12/YASI_12.vcxproj index 5d673ee..81a27c4 100644 --- a/YASI_12/YASI_12.vcxproj +++ b/YASI_12/YASI_12.vcxproj @@ -76,10 +76,12 @@ + + diff --git a/YASI_12/YASI_12.vcxproj.filters b/YASI_12/YASI_12.vcxproj.filters index 2377fdd..ad4aa77 100644 --- a/YASI_12/YASI_12.vcxproj.filters +++ b/YASI_12/YASI_12.vcxproj.filters @@ -153,6 +153,12 @@ Header Files\Data Structures\List + Header Files\Data Structures\List + + + Header Files + + Header Files diff --git a/YASI_12/ds.arraybinarytree.h b/YASI_12/ds.arraybinarytree.h index 647d681..5fb048a 100644 --- a/YASI_12/ds.arraybinarytree.h +++ b/YASI_12/ds.arraybinarytree.h @@ -8,8 +8,12 @@ #include #include +using namespace std; + +// enable-disable testing classes in this file +#include "test.this.module.h" + namespace yasi{ - using namespace std; namespace ds{ ///// abstract class @@ -36,7 +40,7 @@ namespace yasi{ template class IndexedBTNode : public virtual IArrayBinaryTreeNode, public virtual TreeNode { - friend class IndexedBTNodeTest; // enable testing + FRIEND_TEST_CLASS( IndexedBTNodeTest); // enable testing protected: int _index; /// -1 by default const int NULL_INDEX; // marks whether a node is empty/invalid @@ -98,8 +102,8 @@ namespace yasi{ class ArrayBinaryTree : public virtual IArrayBinaryTree >, public virtual BinaryTreeBase>{ ///////////// enable testing //////////////// - friend class ArrayBinaryTreeTest; - friend class BinaryHeapTest; + FRIEND_TEST_CLASS(ArrayBinaryTreeTest); + FRIEND_TEST_CLASS(BinaryHeapTest); typedef IndexedBTNode node_t; const int ROOT_INDEX = 1; // for quick parent-child indexing, 1 instead of 0 @@ -584,423 +588,6 @@ namespace yasi{ return out; } - /// - /// Test IndexedBTNode - /// - class IndexedBTNodeTest :public yasi::Test{ - protected: - void init(){ - IndexedBTNode n1; - ASSERT_EQ(-1, n1._index) << "Default index should be -1" ; - n1.setIndex(5); - ASSERT_EQ(5, n1.index()) << "index should be 5"; - n1.setElement(7); - ASSERT_EQ(7, n1.element) << "element should be 5"; - - n1.makeNull(); - ASSERT_EQ(1, n1.isNull()) << "makeNull() and isNull() disagree"; - } - void indexing(){ - const int N = 7; - IndexedBTNode n[N]; - for (int i = 0; i < N; i++){ - n[i].setIndex(i); - } - ASSERT_EQ(0, n[0].leftIndex()) << "left of 0 must be 0"; - ASSERT_EQ(1, n[0].rightIndex()) << "right of 0 must be 1"; - - ASSERT_EQ(1, n[2].parentIndex()) << "parent of 2 must be 1"; - ASSERT_EQ(1, n[3].parentIndex()) << "parent of 3 must be 1"; - ASSERT_EQ(2, n[4].parentIndex()) << "parent of 4 must be 2"; - ASSERT_EQ(4, n[2].leftIndex()) << "left of 2 must be 4"; - ASSERT_EQ(5, n[2].rightIndex()) << "right of 2 must be 5"; - - } - }; - ADD_TEST_F(IndexedBTNodeTest, init); - ADD_TEST_F(IndexedBTNodeTest, indexing); - ////////////// end testing IndexedBTNode - - /// - /// Test ArrayBinaryTree - /// - class ArrayBinaryTreeTest : public yasi::Test{ - protected: - typedef ArrayBinaryTree::node_t node_t; - typedef ArrayBinaryTree::node_t* node_tptr; - public: - - template - static void checkElements(ArrayBinaryTree *pBt, const E* pElemsArr, const int numElems){ - // finally, check array - E *pTreeElems; - int n; - ArrayBinaryTree& bt = *pBt; // must use reference, otherwise the tree will be destroyed upon exit - bt.elements(&pTreeElems, n); - ASSERT_EQ(n, numElems) << "actual array size " << n << " should equal target size " << numElems << endl - << "actual : " << arrToString(pTreeElems, n) << endl - << "expected: " << arrToString(pElemsArr, n); - - ASSERT_EQ(true, arrcmp(pTreeElems, pElemsArr, n)) << "elements array not right." << endl - << "actual : " << arrToString(pTreeElems, n) << endl - << "expected: " << arrToString(pElemsArr, n); - - // done - DELETE_ARR_SAFE(pTreeElems); - } - - void constructor(){ - ArrayBinaryTree bt; - ASSERT_EQ(1, bt.ROOT_INDEX) << "Index of root is not 1"; - ASSERT_LE(bt.INIT_CAPACITY, bt._arr.capacity() ) << "Initial _capacity must be <= containers capacity"; - ASSERT_LE(2, bt._arr.capacity()) << "Initial capacity must be >= 2"; - ASSERT_EQ(0, bt.size()) << "Initial size is not zero"; - for (int i = 0; i < bt._capacity; i++){ - ASSERT_EQ(0, bt._arr[i]) << "Pointer at index " << i << " is not initialized to NULL"; - } - - ASSERT_EQ(NULL, bt.root()) << "root should have been NULL"; - } - - void elements(){ - int srcArr[] = { 10, 20, 30, 40, 50, 60 }; - int n = ARR_LENGTH(srcArr); - ArrayBinaryTree bt(srcArr, n); - - int* pElemArr; - int numElems; - bt.elements(&pElemArr, numElems); - ASSERT_EQ(n, numElems) << "number of elements is not " << n; - for (int i = 0; i < numElems; i++){ - ASSERT_EQ(srcArr[i], pElemArr[i]) << "element mismatch at index " << i; - } - DELETE_ARR_SAFE(pElemArr); - } - - void fromArr(){ - int srcArr[] = {10, 20, 30, 40, 50, 60}; - int n = ARR_LENGTH(srcArr); - ArrayBinaryTree bt(srcArr, n ); - ASSERT_EQ(n, bt.size()) << "size of tree is not " << n; - // check node-ptrs stored in internal container - int i = 0; - for (int i = 0; i < bt._capacity; i++){ - if (i >= 1 && i <= n){ - // valid node-ptrs - ASSERT_NE(0, (int)bt._arr[i]) << "Pointer NULL at index " << i; - ASSERT_EQ(srcArr[i-1], bt._arr[i]->element) << "array element mismatch for internal index " << i; - } - else{ - // invalid node-ptrs - ASSERT_EQ(0, (int)bt._arr[i]) << "Pointer not NULL at index " << i; - } - } - // also, use elements() method - int* pElemArr; - int numElems; - bt.elements(&pElemArr, numElems); - ASSERT_EQ(n, numElems) << "number of elements is not " << n; - for (int i = 0; i < numElems; i++){ - ASSERT_EQ(srcArr[i], pElemArr[i]) << "element mismatch at index " << i; - } - DELETE_ARR_SAFE(pElemArr); - } - - void isArrIndex(){ - ArrayBinaryTree bt; - ASSERT_EQ(false, bt.isArrIndex(-1)) << "Negative index is accepted"; - ASSERT_EQ(true, bt.isArrIndex(0)) << "0 index is rejected"; - ASSERT_EQ(true, bt.isArrIndex(bt._capacity - 1)) << "index (capacity - 1) is rejected"; - ASSERT_EQ(false, bt.isArrIndex(bt._capacity)) << "index beyond capacity is accepted"; - } - - void nodeAt(){ - ArrayBinaryTree bt; - bt.addRoot(5); - - bt.nodeAt(-1); - - ASSERT_EQ(0, (int) bt.nodeAt(-1)) << "Negative index is accepted"; - ASSERT_EQ(0, (int) bt.nodeAt(0)) << "Index 0 is accepted"; - ASSERT_EQ(0, (int) bt.nodeAt(bt._capacity)) << "Too large index is accepted"; - ASSERT_NE(0, (int) bt.nodeAt(1)) << "The root is not recognized"; - - int e; - bt.remove(bt.root(), e); // remove root - ASSERT_EQ(0, (int) bt.nodeAt(1)) << "TreeNode accepted after deletion"; - } - - void nodeNotNull(){ - ArrayBinaryTree bt; - bt.addRoot(5); - - ASSERT_EQ(false, bt.nodeNotNull(-1)) << "Negative index is accepted"; - ASSERT_EQ(false, bt.nodeNotNull(0)) << "Zero index is accepted"; - ASSERT_EQ(false, bt.nodeNotNull(bt._capacity)) << "Too large index is accepted"; - ASSERT_EQ(true, bt.nodeNotNull(1)) << "The root is not recognized"; - - int e; - bt.remove(bt.root(), e); // remove root - ASSERT_EQ(false, bt.nodeNotNull(1)) << "TreeNode accepted after deletion"; - } - - void addRoot(){ - ArrayBinaryTree bt; - ASSERT_EQ(0, bt.size()); - bt.addRoot(10); - ASSERT_EQ(1, bt.size()) << "tree-size should have been 1"; - ASSERT_EQ(0, (int) bt.nodeAt(0)) << "As per Goodrich-Tamassia convention, first slot in the array should have been empty"; - ASSERT_EQ(10, bt.nodeAt(1)->element) << "Value at the root should have been 10"; - ASSERT_EQ(false, bt.isLeft(bt.root())) << "root cannot be a left child"; - ASSERT_EQ(false, bt.isRight(bt.root())) << "root cannot be a right child"; - ASSERT_EQ(false, bt.isInternal(bt.root())) << "root should have been external"; - ASSERT_EQ(false, bt.hasLeft(bt.root())) << "root does not have a left child"; - ASSERT_EQ(false, bt.hasRight(bt.root())) << "root does not have a right child"; - } - - void insertAt(){ - ArrayBinaryTree bt; - EXPECT_EQ(0, (int)bt.insertAt(4, -1)) << "inserting at negative index succeeded"; - EXPECT_EQ(0, (int)bt.insertAt(4, 0)) << "inserting at 0 index succeeded"; - EXPECT_NE(0, (int)bt.insertAt(4, 2 * bt._capacity)) << "inserting at too large index failed"; - ASSERT_NE(0, (int)bt.insertAt(4, 1)) << "inserting at index 1 failed"; - ASSERT_EQ(0, (int)bt.insertAt(4, 1)) << "inserting at an occupied index succeeded"; - bt.remove(bt.nodeAt(1)); - ASSERT_NE(0, (int)bt.insertAt(4, 1)) << "inserting at a recently deleted slot failed"; - } - - void replaceAt(){ - ArrayBinaryTree bt; - EXPECT_EQ(0, (int)bt.replaceAt(4, -1)) << "replacing at negative index succeeded"; - EXPECT_EQ(0, (int)bt.replaceAt(4, 0)) << "replacing at 0 index succeeded"; - EXPECT_EQ(0, (int)bt.replaceAt(4, 2 * bt._capacity)) << "replacing at too large index succeeded"; - ASSERT_EQ(0, (int)bt.replaceAt(4, 1)) << "replacing at unused index 1 succeeded"; - bt.addRoot(10); - ASSERT_NE(0, (int)bt.replaceAt(4, 1)) << "replacing at occupied index 1 failed"; - int index = bt.root()->index(); - bt.remove(bt.root()); - ASSERT_EQ(0, (int)bt.replaceAt(4, index) ) << "replacing at a recently deleted index succeeded"; - } - - void sibling(){ - ArrayBinaryTree bt; - ASSERT_EQ(0, (int)bt.sibling(bt.nodeAt(0))) << "sibling of NULL node succeeded"; - bt.addRoot(4); - ASSERT_EQ(0, (int)bt.sibling(bt.root())) << "sibling of root node succeeded"; - ArrayBinaryTree::node_t* n1 = bt.addLeft(5, bt.root()); - ASSERT_EQ(0, (int)bt.sibling(n1)) << "sibling of only-child succeeded"; - ArrayBinaryTree::node_t* n2 = bt.addRight(5, bt.root()); - ASSERT_EQ(n2, bt.sibling(n1)) << "sibling of valid node failed"; - bt.remove(bt.left(bt.root())); // remove n1 - ASSERT_EQ(0, (int) bt.sibling(n2)) << "sibling of a deleted-sibling-node succeeded"; - - } - - void resize(){ - int srcArr[] = { 10, 20, 30, 40, 50 }; - int n = ARR_LENGTH(srcArr); - ArrayBinaryTree bt(srcArr, n); - int oldCapacity = bt._capacity; - // copy current data - // node_tptr is actually int (because it is a pointer) - node_tptr* pOldArr = new node_tptr[oldCapacity]; - memcpy(pOldArr, (node_tptr*)bt._arr.data(), sizeof(node_tptr) * oldCapacity); - - bt.resize(2 * oldCapacity + 5, 0); - int newCapacity = bt._capacity; - const node_tptr* pNewArr = (node_tptr*)bt._arr.data(); - // all new slots must be initialized to zero - for (int i = 0; i < newCapacity; i++){ - if (i < oldCapacity){ - // old slots - ASSERT_EQ(pOldArr[i], pNewArr[i]) << "content mismatch at index " << i; - } - else{ - // new slots - ASSERT_EQ(0, pNewArr[i]) << "new slots contain non-NULL pointer at index " << i; - } - } - // done test - DELETE_ARR_SAFE(pOldArr); - } - - void toString(){ - int srcArr[] = { 10, 20, 30, 40, 50, 60, 70 }; - int n = ARR_LENGTH(srcArr); - ArrayBinaryTree bt(srcArr, n); - // delete 50 and 60 - int e1, e2; - bool ok = bt.remove(bt.nodeAt(5), e1); - ASSERT_EQ(true, ok) << "falied to remove 50"; - ASSERT_EQ(50, e1) << "50 was not deleted"; - ok = bt.remove(bt.nodeAt(6), e2); - ASSERT_EQ(true, ok) << "falied to remove 60"; - ASSERT_EQ(60, e2) << "60 was not deleted"; - - // now print - const char* sDelim = "|"; // need to be single-char for testing purpose - const char* sEmptySlot = ""; // need to be empty for testing purpose - string strBt = bt.toStringNodeArray(sDelim, sEmptySlot); - // remove trailing single-char delimiters - for (int i = strBt.length() - 1; strBt[i] == sDelim[0]; i--){ - strBt[i] = NULL; - } - strBt = string(strBt.c_str()); - // now strBt should equal "|10|20|30|40|||70" - string strExpected = "|10|20|30|40|||70"; - ASSERT_EQ(strExpected, strBt) << "Expected " << strExpected << " but found " << strBt; - - - bt.clear(); - bt.fromArray(srcArr, n);// 10 20 30 40 50 60 70 - /////////// preorder - strBt = bt.toStringPreOrder(); - strBt = strPurge(strBt, "| "); - strExpected = "10204050306070"; - ASSERT_EQ(strExpected, strBt) << "preorder mismatch"; - - /////////// postorder - strBt = bt.toStringPostOrder(); - strBt = strPurge(strBt, "| "); - strExpected = "40502060703010"; - ASSERT_EQ(strExpected, strBt) << "postorder mismatch"; - - /////////// inorder - strBt = bt.toStringInOrder(); - strBt = strPurge(strBt, "| "); - strExpected = "40205010603070"; - ASSERT_EQ(strExpected, strBt) << "inorder mismatch"; - - - /////////// BFSorder - strBt = bt.toStringBFS(); - strBt = strPurge(strBt, "| "); - strExpected = "10203040506070"; - ASSERT_EQ(strExpected, strBt) << "BFS order mismatch"; - } - - void remove(){ - int e; - int srcArr[] = { 10, 20, 30, 40, 50, 60 }; - int n = ARR_LENGTH(srcArr); - ArrayBinaryTree bt(srcArr, n); - { - SCOPED_TRACE("tree arr before remove"); - checkElements(&bt, srcArr, n); - } - //bt.toString(&cBt); - //DELETE_ARR_SAFE(cBt); - - - bool ok = bt.remove(bt.nodeAt(0)); - ASSERT_EQ(false, ok) << "removing from index 0 succeeded"; - ok = bt.remove(bt.nodeAt(-1)); - ASSERT_EQ(false, ok) << "removing from negative index succeeded"; - - //bt.toString(&cBt); - //DELETE_ARR_SAFE(cBt); - - // removing the root will remove the entire tree - ok = bt.remove(bt.root(), e); // 10 - ASSERT_EQ(true, ok) << "remove(root) failed"; - ASSERT_EQ(10, e) << "removed element should have been 10"; - ASSERT_EQ(0, bt.size()) << "Deleting subtree at root should make the size zero."; - - // remove a subtree - bt.fromArray(srcArr, ARR_LENGTH(srcArr)); - // arr = { 10, 20, 30, 40, 50, 60 }; - ok = bt.remove(bt.left(bt.root()), e); // remove subtree 20 - ASSERT_EQ(true, ok) << "remove(20) failed"; - ASSERT_EQ(20, e) << "removed element should have been 20"; - ASSERT_EQ(ARR_LENGTH(srcArr) - 3, bt.size()) << "Remaining tree has improper size"; - { - SCOPED_TRACE("remove(20)"); - int newArr[] = {10, 30, 60}; - checkElements(&bt, newArr, ARR_LENGTH(newArr)); - } - } - - void removeNode(){ - int e; - int srcArr[] = { 10, 20, 30, 40, 50, 60 }; - int n = ARR_LENGTH(srcArr); - ArrayBinaryTree bt(srcArr, n); - { - SCOPED_TRACE("tree arr before remove"); - checkElements(&bt, srcArr, n); - } - - // remove a single node - bool ok = bt.removeNode(bt.root(), e); // 10 - ASSERT_EQ(true, ok) << "remove(root) failed"; - ASSERT_EQ(10, e) << "removed element should have been 10"; - // arr = { ?, 20, 30, 40, 50, 60 }; - { - SCOPED_TRACE("removeNode(10)"); - int newArr[] = { 20, 30, 40, 50, 60 }; - checkElements(&bt, newArr, 5); - - ASSERT_EQ(5, bt.size()) << "size of the tree should be 5"; - ASSERT_EQ(0, (int)bt.nodeAt(1)) << "the pointer at the deleted position must be NULL"; - } - - // remove another single node - ok = bt.removeNode(bt.nodeAt(3), e); // 30 - ASSERT_EQ(true, ok) << "removeNode(30) failed"; - ASSERT_EQ(30, e) << "removed element should have been 30"; - // arr = { ?, 20, ?, 40, 50, 60 }; - { - SCOPED_TRACE("removeNode(30)"); - int newArr[] = { 20, 40, 50, 60 }; - checkElements(&bt, newArr, 4); - - ASSERT_EQ(4, bt.size()) << "size of the tree should be 4"; - ASSERT_EQ(0, (int)bt.nodeAt(3)) << "the pointer at the deleted position must be NULL"; - } - - } - - void clear(){ - int srcArr[] = { 10, 20, 30, 40, 50, 60 }; - int n = ARR_LENGTH(srcArr); - ArrayBinaryTree bt(srcArr, n); - bt.clear(); - ASSERT_EQ(0, bt.size()) << "size not 0"; - ASSERT_EQ(true, bt.empty()) << "tree not empty"; - ASSERT_EQ(NULL, bt.root()) << "root not NULL"; - - } - - //void addElements(){ - // ArrayBinaryTree bt; - // bt.addRoot(10); - // bt.addLeft(20, bt.root()); - // bt.addRight(30, bt.root()); - // ASSERT_EQ(true, bt.isInternal(bt.root())) << "root should have been internal"; - // ASSERT_EQ(true, bt.isExternal(bt.left(bt.root()))) << "root's left child should have been external"; - // bt.addLeft(40, bt.left(bt.root())); - // ASSERT_EQ(false, bt.isExternal(bt.left(bt.root()))) << "root's left child should have been internal"; - // bt.addRight(70, bt.right(bt.root())); - //} - }; - - // create tests - ADD_TEST_F(ArrayBinaryTreeTest, constructor); - ADD_TEST_F(ArrayBinaryTreeTest, isArrIndex); - ADD_TEST_F(ArrayBinaryTreeTest, nodeAt); - ADD_TEST_F(ArrayBinaryTreeTest, nodeNotNull); - ADD_TEST_F(ArrayBinaryTreeTest, addRoot); - ADD_TEST_F(ArrayBinaryTreeTest, insertAt); - ADD_TEST_F(ArrayBinaryTreeTest, replaceAt); - ADD_TEST_F(ArrayBinaryTreeTest, remove); - ADD_TEST_F(ArrayBinaryTreeTest, removeNode); - ADD_TEST_F(ArrayBinaryTreeTest, sibling); - ADD_TEST_F(ArrayBinaryTreeTest, elements); - ADD_TEST_F(ArrayBinaryTreeTest, fromArr); - ADD_TEST_F(ArrayBinaryTreeTest, resize); - ADD_TEST_F(ArrayBinaryTreeTest, toString); - ADD_TEST_F(ArrayBinaryTreeTest, clear); - } } \ No newline at end of file diff --git a/YASI_12/ds.arraybinarytree.test.h b/YASI_12/ds.arraybinarytree.test.h new file mode 100644 index 0000000..27c50c0 --- /dev/null +++ b/YASI_12/ds.arraybinarytree.test.h @@ -0,0 +1,429 @@ +#pragma once + +#if YASI_TEST_THIS_MODULE != 1 +#define YASI_TEST_THIS_MODULE 1 +#endif +#include "ds.arraybinarytree.h" + +namespace yasi{ + namespace ds{ + + /// + /// Test IndexedBTNode + /// + class IndexedBTNodeTest :public yasi::Test{ + protected: + void init(){ + IndexedBTNode n1; + ASSERT_EQ(-1, n1._index) << "Default index should be -1"; + n1.setIndex(5); + ASSERT_EQ(5, n1.index()) << "index should be 5"; + n1.setElement(7); + ASSERT_EQ(7, n1.element) << "element should be 5"; + + n1.makeNull(); + ASSERT_EQ(1, n1.isNull()) << "makeNull() and isNull() disagree"; + } + void indexing(){ + const int N = 7; + IndexedBTNode n[N]; + for (int i = 0; i < N; i++){ + n[i].setIndex(i); + } + ASSERT_EQ(0, n[0].leftIndex()) << "left of 0 must be 0"; + ASSERT_EQ(1, n[0].rightIndex()) << "right of 0 must be 1"; + + ASSERT_EQ(1, n[2].parentIndex()) << "parent of 2 must be 1"; + ASSERT_EQ(1, n[3].parentIndex()) << "parent of 3 must be 1"; + ASSERT_EQ(2, n[4].parentIndex()) << "parent of 4 must be 2"; + ASSERT_EQ(4, n[2].leftIndex()) << "left of 2 must be 4"; + ASSERT_EQ(5, n[2].rightIndex()) << "right of 2 must be 5"; + + } + }; + ADD_TEST_F(IndexedBTNodeTest, init); + ADD_TEST_F(IndexedBTNodeTest, indexing); + ////////////// end testing IndexedBTNode + + /// + /// Test ArrayBinaryTree + /// + class ArrayBinaryTreeTest : public yasi::Test{ + protected: + typedef ArrayBinaryTree::node_t node_t; + typedef ArrayBinaryTree::node_t* node_tptr; + public: + + template + static void checkElements(ArrayBinaryTree *pBt, const E* pElemsArr, const int numElems){ + // finally, check array + E *pTreeElems; + int n; + ArrayBinaryTree& bt = *pBt; // must use reference, otherwise the tree will be destroyed upon exit + bt.elements(&pTreeElems, n); + ASSERT_EQ(n, numElems) << "actual array size " << n << " should equal target size " << numElems << endl + << "actual : " << arrToString(pTreeElems, n) << endl + << "expected: " << arrToString(pElemsArr, n); + + ASSERT_EQ(true, arrcmp(pTreeElems, pElemsArr, n)) << "elements array not right." << endl + << "actual : " << arrToString(pTreeElems, n) << endl + << "expected: " << arrToString(pElemsArr, n); + + // done + DELETE_ARR_SAFE(pTreeElems); + } + + void constructor(){ + ArrayBinaryTree bt; + ASSERT_EQ(1, bt.ROOT_INDEX) << "Index of root is not 1"; + ASSERT_LE(bt.INIT_CAPACITY, bt._arr.capacity()) << "Initial _capacity must be <= containers capacity"; + ASSERT_LE(2, bt._arr.capacity()) << "Initial capacity must be >= 2"; + ASSERT_EQ(0, bt.size()) << "Initial size is not zero"; + for (int i = 0; i < bt._capacity; i++){ + ASSERT_EQ(0, bt._arr[i]) << "Pointer at index " << i << " is not initialized to NULL"; + } + + ASSERT_EQ(NULL, bt.root()) << "root should have been NULL"; + } + + void elements(){ + int srcArr[] = { 10, 20, 30, 40, 50, 60 }; + int n = ARR_LENGTH(srcArr); + ArrayBinaryTree bt(srcArr, n); + + int* pElemArr; + int numElems; + bt.elements(&pElemArr, numElems); + ASSERT_EQ(n, numElems) << "number of elements is not " << n; + for (int i = 0; i < numElems; i++){ + ASSERT_EQ(srcArr[i], pElemArr[i]) << "element mismatch at index " << i; + } + DELETE_ARR_SAFE(pElemArr); + } + + void fromArr(){ + int srcArr[] = { 10, 20, 30, 40, 50, 60 }; + int n = ARR_LENGTH(srcArr); + ArrayBinaryTree bt(srcArr, n); + ASSERT_EQ(n, bt.size()) << "size of tree is not " << n; + // check node-ptrs stored in internal container + int i = 0; + for (int i = 0; i < bt._capacity; i++){ + if (i >= 1 && i <= n){ + // valid node-ptrs + ASSERT_NE(0, (int)bt._arr[i]) << "Pointer NULL at index " << i; + ASSERT_EQ(srcArr[i - 1], bt._arr[i]->element) << "array element mismatch for internal index " << i; + } + else{ + // invalid node-ptrs + ASSERT_EQ(0, (int)bt._arr[i]) << "Pointer not NULL at index " << i; + } + } + // also, use elements() method + int* pElemArr; + int numElems; + bt.elements(&pElemArr, numElems); + ASSERT_EQ(n, numElems) << "number of elements is not " << n; + for (int i = 0; i < numElems; i++){ + ASSERT_EQ(srcArr[i], pElemArr[i]) << "element mismatch at index " << i; + } + DELETE_ARR_SAFE(pElemArr); + } + + void isArrIndex(){ + ArrayBinaryTree bt; + ASSERT_EQ(false, bt.isArrIndex(-1)) << "Negative index is accepted"; + ASSERT_EQ(true, bt.isArrIndex(0)) << "0 index is rejected"; + ASSERT_EQ(true, bt.isArrIndex(bt._capacity - 1)) << "index (capacity - 1) is rejected"; + ASSERT_EQ(false, bt.isArrIndex(bt._capacity)) << "index beyond capacity is accepted"; + } + + void nodeAt(){ + ArrayBinaryTree bt; + bt.addRoot(5); + + bt.nodeAt(-1); + + ASSERT_EQ(0, (int)bt.nodeAt(-1)) << "Negative index is accepted"; + ASSERT_EQ(0, (int)bt.nodeAt(0)) << "Index 0 is accepted"; + ASSERT_EQ(0, (int)bt.nodeAt(bt._capacity)) << "Too large index is accepted"; + ASSERT_NE(0, (int)bt.nodeAt(1)) << "The root is not recognized"; + + int e; + bt.remove(bt.root(), e); // remove root + ASSERT_EQ(0, (int)bt.nodeAt(1)) << "TreeNode accepted after deletion"; + } + + void nodeNotNull(){ + ArrayBinaryTree bt; + bt.addRoot(5); + + ASSERT_EQ(false, bt.nodeNotNull(-1)) << "Negative index is accepted"; + ASSERT_EQ(false, bt.nodeNotNull(0)) << "Zero index is accepted"; + ASSERT_EQ(false, bt.nodeNotNull(bt._capacity)) << "Too large index is accepted"; + ASSERT_EQ(true, bt.nodeNotNull(1)) << "The root is not recognized"; + + int e; + bt.remove(bt.root(), e); // remove root + ASSERT_EQ(false, bt.nodeNotNull(1)) << "TreeNode accepted after deletion"; + } + + void addRoot(){ + ArrayBinaryTree bt; + ASSERT_EQ(0, bt.size()); + bt.addRoot(10); + ASSERT_EQ(1, bt.size()) << "tree-size should have been 1"; + ASSERT_EQ(0, (int)bt.nodeAt(0)) << "As per Goodrich-Tamassia convention, first slot in the array should have been empty"; + ASSERT_EQ(10, bt.nodeAt(1)->element) << "Value at the root should have been 10"; + ASSERT_EQ(false, bt.isLeft(bt.root())) << "root cannot be a left child"; + ASSERT_EQ(false, bt.isRight(bt.root())) << "root cannot be a right child"; + ASSERT_EQ(false, bt.isInternal(bt.root())) << "root should have been external"; + ASSERT_EQ(false, bt.hasLeft(bt.root())) << "root does not have a left child"; + ASSERT_EQ(false, bt.hasRight(bt.root())) << "root does not have a right child"; + } + + void insertAt(){ + ArrayBinaryTree bt; + EXPECT_EQ(0, (int)bt.insertAt(4, -1)) << "inserting at negative index succeeded"; + EXPECT_EQ(0, (int)bt.insertAt(4, 0)) << "inserting at 0 index succeeded"; + EXPECT_NE(0, (int)bt.insertAt(4, 2 * bt._capacity)) << "inserting at too large index failed"; + ASSERT_NE(0, (int)bt.insertAt(4, 1)) << "inserting at index 1 failed"; + ASSERT_EQ(0, (int)bt.insertAt(4, 1)) << "inserting at an occupied index succeeded"; + bt.remove(bt.nodeAt(1)); + ASSERT_NE(0, (int)bt.insertAt(4, 1)) << "inserting at a recently deleted slot failed"; + } + + void replaceAt(){ + ArrayBinaryTree bt; + EXPECT_EQ(0, (int)bt.replaceAt(4, -1)) << "replacing at negative index succeeded"; + EXPECT_EQ(0, (int)bt.replaceAt(4, 0)) << "replacing at 0 index succeeded"; + EXPECT_EQ(0, (int)bt.replaceAt(4, 2 * bt._capacity)) << "replacing at too large index succeeded"; + ASSERT_EQ(0, (int)bt.replaceAt(4, 1)) << "replacing at unused index 1 succeeded"; + bt.addRoot(10); + ASSERT_NE(0, (int)bt.replaceAt(4, 1)) << "replacing at occupied index 1 failed"; + int index = bt.root()->index(); + bt.remove(bt.root()); + ASSERT_EQ(0, (int)bt.replaceAt(4, index)) << "replacing at a recently deleted index succeeded"; + } + + void sibling(){ + ArrayBinaryTree bt; + ASSERT_EQ(0, (int)bt.sibling(bt.nodeAt(0))) << "sibling of NULL node succeeded"; + bt.addRoot(4); + ASSERT_EQ(0, (int)bt.sibling(bt.root())) << "sibling of root node succeeded"; + ArrayBinaryTree::node_t* n1 = bt.addLeft(5, bt.root()); + ASSERT_EQ(0, (int)bt.sibling(n1)) << "sibling of only-child succeeded"; + ArrayBinaryTree::node_t* n2 = bt.addRight(5, bt.root()); + ASSERT_EQ(n2, bt.sibling(n1)) << "sibling of valid node failed"; + bt.remove(bt.left(bt.root())); // remove n1 + ASSERT_EQ(0, (int)bt.sibling(n2)) << "sibling of a deleted-sibling-node succeeded"; + + } + + void resize(){ + int srcArr[] = { 10, 20, 30, 40, 50 }; + int n = ARR_LENGTH(srcArr); + ArrayBinaryTree bt(srcArr, n); + int oldCapacity = bt._capacity; + // copy current data + // node_tptr is actually int (because it is a pointer) + node_tptr* pOldArr = new node_tptr[oldCapacity]; + memcpy(pOldArr, (node_tptr*)bt._arr.data(), sizeof(node_tptr) * oldCapacity); + + bt.resize(2 * oldCapacity + 5, 0); + int newCapacity = bt._capacity; + const node_tptr* pNewArr = (node_tptr*)bt._arr.data(); + // all new slots must be initialized to zero + for (int i = 0; i < newCapacity; i++){ + if (i < oldCapacity){ + // old slots + ASSERT_EQ(pOldArr[i], pNewArr[i]) << "content mismatch at index " << i; + } + else{ + // new slots + ASSERT_EQ(0, pNewArr[i]) << "new slots contain non-NULL pointer at index " << i; + } + } + // done test + DELETE_ARR_SAFE(pOldArr); + } + + void toString(){ + int srcArr[] = { 10, 20, 30, 40, 50, 60, 70 }; + int n = ARR_LENGTH(srcArr); + ArrayBinaryTree bt(srcArr, n); + // delete 50 and 60 + int e1, e2; + bool ok = bt.remove(bt.nodeAt(5), e1); + ASSERT_EQ(true, ok) << "falied to remove 50"; + ASSERT_EQ(50, e1) << "50 was not deleted"; + ok = bt.remove(bt.nodeAt(6), e2); + ASSERT_EQ(true, ok) << "falied to remove 60"; + ASSERT_EQ(60, e2) << "60 was not deleted"; + + // now print + const char* sDelim = "|"; // need to be single-char for testing purpose + const char* sEmptySlot = ""; // need to be empty for testing purpose + string strBt = bt.toStringNodeArray(sDelim, sEmptySlot); + // remove trailing single-char delimiters + for (int i = strBt.length() - 1; strBt[i] == sDelim[0]; i--){ + strBt[i] = NULL; + } + strBt = string(strBt.c_str()); + // now strBt should equal "|10|20|30|40|||70" + string strExpected = "|10|20|30|40|||70"; + ASSERT_EQ(strExpected, strBt) << "Expected " << strExpected << " but found " << strBt; + + + bt.clear(); + bt.fromArray(srcArr, n);// 10 20 30 40 50 60 70 + /////////// preorder + strBt = bt.toStringPreOrder(); + strBt = strPurge(strBt, "| "); + strExpected = "10204050306070"; + ASSERT_EQ(strExpected, strBt) << "preorder mismatch"; + + /////////// postorder + strBt = bt.toStringPostOrder(); + strBt = strPurge(strBt, "| "); + strExpected = "40502060703010"; + ASSERT_EQ(strExpected, strBt) << "postorder mismatch"; + + /////////// inorder + strBt = bt.toStringInOrder(); + strBt = strPurge(strBt, "| "); + strExpected = "40205010603070"; + ASSERT_EQ(strExpected, strBt) << "inorder mismatch"; + + + /////////// BFSorder + strBt = bt.toStringBFS(); + strBt = strPurge(strBt, "| "); + strExpected = "10203040506070"; + ASSERT_EQ(strExpected, strBt) << "BFS order mismatch"; + } + + void remove(){ + int e; + int srcArr[] = { 10, 20, 30, 40, 50, 60 }; + int n = ARR_LENGTH(srcArr); + ArrayBinaryTree bt(srcArr, n); + { + SCOPED_TRACE("tree arr before remove"); + checkElements(&bt, srcArr, n); + } + //bt.toString(&cBt); + //DELETE_ARR_SAFE(cBt); + + + bool ok = bt.remove(bt.nodeAt(0)); + ASSERT_EQ(false, ok) << "removing from index 0 succeeded"; + ok = bt.remove(bt.nodeAt(-1)); + ASSERT_EQ(false, ok) << "removing from negative index succeeded"; + + //bt.toString(&cBt); + //DELETE_ARR_SAFE(cBt); + + // removing the root will remove the entire tree + ok = bt.remove(bt.root(), e); // 10 + ASSERT_EQ(true, ok) << "remove(root) failed"; + ASSERT_EQ(10, e) << "removed element should have been 10"; + ASSERT_EQ(0, bt.size()) << "Deleting subtree at root should make the size zero."; + + // remove a subtree + bt.fromArray(srcArr, ARR_LENGTH(srcArr)); + // arr = { 10, 20, 30, 40, 50, 60 }; + ok = bt.remove(bt.left(bt.root()), e); // remove subtree 20 + ASSERT_EQ(true, ok) << "remove(20) failed"; + ASSERT_EQ(20, e) << "removed element should have been 20"; + ASSERT_EQ(ARR_LENGTH(srcArr) - 3, bt.size()) << "Remaining tree has improper size"; + { + SCOPED_TRACE("remove(20)"); + int newArr[] = { 10, 30, 60 }; + checkElements(&bt, newArr, ARR_LENGTH(newArr)); + } + } + + void removeNode(){ + int e; + int srcArr[] = { 10, 20, 30, 40, 50, 60 }; + int n = ARR_LENGTH(srcArr); + ArrayBinaryTree bt(srcArr, n); + { + SCOPED_TRACE("tree arr before remove"); + checkElements(&bt, srcArr, n); + } + + // remove a single node + bool ok = bt.removeNode(bt.root(), e); // 10 + ASSERT_EQ(true, ok) << "remove(root) failed"; + ASSERT_EQ(10, e) << "removed element should have been 10"; + // arr = { ?, 20, 30, 40, 50, 60 }; + { + SCOPED_TRACE("removeNode(10)"); + int newArr[] = { 20, 30, 40, 50, 60 }; + checkElements(&bt, newArr, 5); + + ASSERT_EQ(5, bt.size()) << "size of the tree should be 5"; + ASSERT_EQ(0, (int)bt.nodeAt(1)) << "the pointer at the deleted position must be NULL"; + } + + // remove another single node + ok = bt.removeNode(bt.nodeAt(3), e); // 30 + ASSERT_EQ(true, ok) << "removeNode(30) failed"; + ASSERT_EQ(30, e) << "removed element should have been 30"; + // arr = { ?, 20, ?, 40, 50, 60 }; + { + SCOPED_TRACE("removeNode(30)"); + int newArr[] = { 20, 40, 50, 60 }; + checkElements(&bt, newArr, 4); + + ASSERT_EQ(4, bt.size()) << "size of the tree should be 4"; + ASSERT_EQ(0, (int)bt.nodeAt(3)) << "the pointer at the deleted position must be NULL"; + } + + } + + void clear(){ + int srcArr[] = { 10, 20, 30, 40, 50, 60 }; + int n = ARR_LENGTH(srcArr); + ArrayBinaryTree bt(srcArr, n); + bt.clear(); + ASSERT_EQ(0, bt.size()) << "size not 0"; + ASSERT_EQ(true, bt.empty()) << "tree not empty"; + ASSERT_EQ(NULL, bt.root()) << "root not NULL"; + + } + + //void addElements(){ + // ArrayBinaryTree bt; + // bt.addRoot(10); + // bt.addLeft(20, bt.root()); + // bt.addRight(30, bt.root()); + // ASSERT_EQ(true, bt.isInternal(bt.root())) << "root should have been internal"; + // ASSERT_EQ(true, bt.isExternal(bt.left(bt.root()))) << "root's left child should have been external"; + // bt.addLeft(40, bt.left(bt.root())); + // ASSERT_EQ(false, bt.isExternal(bt.left(bt.root()))) << "root's left child should have been internal"; + // bt.addRight(70, bt.right(bt.root())); + //} + }; + + // create tests + ADD_TEST_F(ArrayBinaryTreeTest, constructor); + ADD_TEST_F(ArrayBinaryTreeTest, isArrIndex); + ADD_TEST_F(ArrayBinaryTreeTest, nodeAt); + ADD_TEST_F(ArrayBinaryTreeTest, nodeNotNull); + ADD_TEST_F(ArrayBinaryTreeTest, addRoot); + ADD_TEST_F(ArrayBinaryTreeTest, insertAt); + ADD_TEST_F(ArrayBinaryTreeTest, replaceAt); + ADD_TEST_F(ArrayBinaryTreeTest, remove); + ADD_TEST_F(ArrayBinaryTreeTest, removeNode); + ADD_TEST_F(ArrayBinaryTreeTest, sibling); + ADD_TEST_F(ArrayBinaryTreeTest, elements); + ADD_TEST_F(ArrayBinaryTreeTest, fromArr); + ADD_TEST_F(ArrayBinaryTreeTest, resize); + ADD_TEST_F(ArrayBinaryTreeTest, toString); + ADD_TEST_F(ArrayBinaryTreeTest, clear); + + } +} \ No newline at end of file diff --git a/YASI_12/ds.binarytree.h b/YASI_12/ds.binarytree.h index dc8d8e2..194dc08 100644 --- a/YASI_12/ds.binarytree.h +++ b/YASI_12/ds.binarytree.h @@ -7,6 +7,8 @@ #include using namespace std; +#include "test.this.module.h" + namespace yasi{ namespace ds{ @@ -68,7 +70,7 @@ class BinaryTreeNode : public virtual TreeNode, template > class BinaryTree : public virtual BinaryTreeBase { //////////////// enable testing //////////// - friend class BinaryTreeTest; + FRIEND_TEST_CLASS(BinaryTreeTest); protected: typedef Node node_t; @@ -182,351 +184,6 @@ class BinaryTree : public virtual BinaryTreeBase { }; -// test -class BinaryTreeTest : public yasi::Test{ -public: - typedef BinaryTree > Tree; - typedef Tree::node_t node_t; - /////////////////////////// - /////// IBinaryTree methods - /////////////////////////// - - // size, empty - // left, right, parent, sibling, root, numChildren - // isLeft, isRight, hasLeft, hasRight - // isInternal, isExternal, isRoot - // addLeft, addRight, addRoot - void add(){ - Tree t; - - // add root - node_t* n0 = t.addRoot(0); - ASSERT_EQ(1, t.size()) << "size not 1"; - ASSERT_EQ(false, t.empty()) << "tree empty"; - ASSERT_EQ(n0, t.root()) << "root not n0"; - ASSERT_EQ(true, t.isRoot(n0)) << "root not n0"; - ASSERT_EQ(0, n0->element) << "root-element not 0"; - ASSERT_EQ(false, t.isLeft(n0)) << "n0 not a left child"; - ASSERT_EQ(false, t.isRight(n0)) << "n0 not a right child"; - ASSERT_EQ(false, t.hasLeft(n0)) << "root has not left child"; - ASSERT_EQ(false, t.hasRight(n0)) << "root has no right child"; - ASSERT_EQ(false, t.isInternal(n0)) << "root not internal yet"; - ASSERT_EQ(true, t.isExternal(n0)) << "root should be external now"; - ASSERT_EQ(NULL, t.left(n0)) << "left(root) should be NULL"; - ASSERT_EQ(NULL, t.right(n0)) << "right(root) should be NULL"; - ASSERT_EQ(NULL, t.parent(n0)) << "parent(root) should be NULL"; - ASSERT_EQ(NULL, t.sibling(n0)) << "sibling(root) should be NULL"; - ASSERT_EQ(0, t.numChildren(n0)) << "numChildren(root) should be 0"; - - /////////////// add root->left - node_t* n1 = t.addLeft(1, t.root()); - ASSERT_EQ(2, t.size()) << "size not 2"; - ASSERT_EQ(false, t.empty()) << "tree empty"; - // about root - ASSERT_EQ(n0, t.root()) << "root not n0"; - ASSERT_EQ(n0, t.parent(n1)) << "n1 not child of n0"; - ASSERT_EQ(true, t.hasLeft(n0)) << "root has a left child"; - ASSERT_EQ(false, t.hasRight(n0)) << "root has no right child"; - ASSERT_EQ(true, t.isInternal(n0)) << "root is internal"; - ASSERT_EQ(false, t.isExternal(n0)) << "root not external now"; - ASSERT_EQ(NULL, t.right(n0)) << "right(root) should be NULL"; - ASSERT_EQ(NULL, t.parent(n0)) << "parent(root) should be NULL"; - ASSERT_EQ(NULL, t.sibling(n0)) << "sibling(root) should be NULL"; - ASSERT_EQ(1, t.numChildren(n0)) << "numChildren(root) should be 1"; - // about root->left - ASSERT_EQ(1, n1->element) << "element not 1"; - ASSERT_EQ(n1, t.left(n0)) << "n1 not left child of n0"; - ASSERT_NE(n1, t.right(n0)) << "n1 right child of n0"; - ASSERT_EQ(true, t.isLeft(n1)) << "n1 is a left child"; - ASSERT_EQ(false, t.isRight(n1)) << "n1 is a right child"; - ASSERT_EQ(n0, t.parent(n1)) << "n0 not parent of n1"; - ASSERT_EQ(NULL, t.sibling(n1)) << "sibling(n1) wrong"; - ASSERT_EQ(false, t.isInternal(n1)) << "n1 is external"; - ASSERT_EQ(true, t.isExternal(n1)) << "n1 not internal now"; - ASSERT_EQ(false, t.hasLeft(n1)) << "n1 has left child"; - ASSERT_EQ(false, t.hasRight(n1)) << "n1 has right child"; - ASSERT_EQ(0, t.numChildren(n1)) << "numChildren(n1) should be 0"; - ASSERT_EQ(NULL, t.addLeft(-3, t.root())) << "root->left overwritten by addLeft()"; - - /////////// add root->right - node_t* n2 = t.addRight(2, t.root()); - ASSERT_EQ(3, t.size()) << "size not 3"; - ASSERT_EQ(false, t.empty()) << "tree empty"; - // about root - ASSERT_EQ(n0, t.root()) << "root not n0"; - ASSERT_EQ(n0, t.parent(n2)) << "n2 not child of n0"; - ASSERT_EQ(true, t.hasLeft(n0)) << "root has a left child"; - ASSERT_EQ(true, t.hasRight(n0)) << "root has no right child"; - ASSERT_EQ(true, t.isInternal(n0)) << "root is internal"; - ASSERT_EQ(false, t.isExternal(n0)) << "root not external now"; - ASSERT_EQ(n2, t.right(n0)) << "right(root) should be n2"; - ASSERT_EQ(NULL, t.parent(n0)) << "parent(root) should be NULL"; - ASSERT_EQ(NULL, t.sibling(n0)) << "sibling(root) should be NULL"; - ASSERT_EQ(2, t.numChildren(n0)) << "numChildren(root) should be 2"; - // about root->left - ASSERT_EQ(1, n1->element) << "element not 1"; - ASSERT_EQ(n1, t.left(n0)) << "n1 not left child of n0"; - ASSERT_NE(n1, t.right(n0)) << "n1 right child of n0"; - ASSERT_EQ(true, t.isLeft(n1)) << "n1 is a left child"; - ASSERT_EQ(false, t.isRight(n1)) << "n1 is a right child"; - ASSERT_EQ(n0, t.parent(n1)) << "n0 not parent of n1"; - ASSERT_EQ(n2, t.sibling(n1)) << "sibling(n1) wrong"; - ASSERT_EQ(false, t.isInternal(n1)) << "n1 is external"; - ASSERT_EQ(true, t.isExternal(n1)) << "n1 not internal now"; - ASSERT_EQ(false, t.hasLeft(n1)) << "n1 has left child"; - ASSERT_EQ(false, t.hasRight(n1)) << "n1 has right child"; - ASSERT_EQ(0, t.numChildren(n1)) << "numChildren(n1) should be 0"; - // about root->right - ASSERT_EQ(2, n2->element) << "element not 2"; - ASSERT_EQ(n2, t.right(n0)) << "n2 not right child of n0"; - ASSERT_NE(n2, t.left(n0)) << "n2 left child of n0"; - ASSERT_EQ(false, t.isLeft(n2)) << "n2 is a left child"; - ASSERT_EQ(true, t.isRight(n2)) << "n2 not a right child"; - ASSERT_EQ(n0, t.parent(n2)) << "n0 not parent of n2"; - ASSERT_EQ(n1, t.sibling(n2)) << "sibling(n2) should be n1"; - ASSERT_EQ(false, t.isInternal(n2)) << "n2 is external"; - ASSERT_EQ(true, t.isExternal(n2)) << "n2 not internal now"; - ASSERT_EQ(false, t.hasLeft(n2)) << "n2 has left child"; - ASSERT_EQ(false, t.hasRight(n2)) << "n2 has right child"; - ASSERT_EQ(0, t.numChildren(n2)) << "numChildren(n2) should be 0"; - ASSERT_EQ(NULL, t.addRight(-3, t.root())) << "root->right overwritten by addRight()"; - - /////////// add root->left->right - node_t* n4 = t.addRight(4, n1); - ASSERT_EQ(4, t.size()) << "size not 4"; - ASSERT_EQ(false, t.empty()) << "tree empty"; - // about root - ASSERT_EQ(n0, t.root()) << "root not n0"; - ASSERT_EQ(n0, t.parent(t.parent(n4))) << "n2 not grand child of n0"; - ASSERT_EQ(true, t.hasLeft(n0)) << "root has a left child"; - ASSERT_EQ(true, t.hasRight(n0)) << "root has no right child"; - ASSERT_EQ(true, t.isInternal(n0)) << "root is internal"; - ASSERT_EQ(false, t.isExternal(n0)) << "root not external now"; - ASSERT_EQ(n2, t.right(n0)) << "right(root) should be n2"; - ASSERT_EQ(n1, t.left(n0)) << "left(root) should be n1"; - ASSERT_EQ(NULL, t.parent(n0)) << "parent(root) should be NULL"; - ASSERT_EQ(NULL, t.sibling(n0)) << "sibling(root) should be NULL"; - ASSERT_EQ(2, t.numChildren(n0)) << "numChildren(root) should be 1"; - // about root->left - ASSERT_EQ(1, n1->element) << "element not 1"; - ASSERT_EQ(n1, t.left(n0)) << "n1 not left child of n0"; - ASSERT_NE(n1, t.right(n0)) << "n1 right child of n0"; - ASSERT_EQ(true, t.isLeft(n1)) << "n1 is a left child"; - ASSERT_EQ(false, t.isRight(n1)) << "n1 is a right child"; - ASSERT_EQ(n0, t.parent(n1)) << "n0 not parent of n1"; - ASSERT_EQ(n2, t.sibling(n1)) << "sibling(n1) wrong"; - ASSERT_EQ(true, t.isInternal(n1)) << "n1 external"; - ASSERT_EQ(false, t.isExternal(n1)) << "n1 internal now"; - ASSERT_EQ(false, t.hasLeft(n1)) << "n1 has no left child"; - ASSERT_EQ(true, t.hasRight(n1)) << "n1 has no right child"; - ASSERT_EQ(1, t.numChildren(n1)) << "numChildren(n1) should be 1"; - // about root->right - ASSERT_EQ(2, n2->element) << "element not 2"; - ASSERT_EQ(n2, t.right(n0)) << "n2 not right child of n0"; - ASSERT_NE(n2, t.left(n0)) << "n2 left child of n0"; - ASSERT_EQ(false, t.isLeft(n2)) << "n2 is a left child"; - ASSERT_EQ(true, t.isRight(n2)) << "n2 not a right child"; - ASSERT_EQ(n0, t.parent(n2)) << "n0 not parent of n2"; - ASSERT_EQ(n1, t.sibling(n2)) << "sibling(n2) should be n1"; - ASSERT_EQ(false, t.isInternal(n2)) << "n2 is external"; - ASSERT_EQ(true, t.isExternal(n2)) << "n2 not internal now"; - ASSERT_EQ(false, t.hasLeft(n2)) << "n2 has left child"; - ASSERT_EQ(false, t.hasRight(n2)) << "n2 has right child"; - ASSERT_EQ(0, t.numChildren(n2)) << "numChildren(n2) should be 0"; - // about root->left->right - ASSERT_EQ(4, n4->element) << "element not 4"; - ASSERT_EQ(n4, t.right(n1)) << "n4 not right child of n1"; - ASSERT_NE(n4, t.left(n1)) << "n4 left child of n1"; - ASSERT_EQ(false, t.isLeft(n4)) << "n4 is a left child"; - ASSERT_EQ(true, t.isRight(n4)) << "n4 not a right child"; - ASSERT_EQ(n1, t.parent(n4)) << "n1 not parent of n4"; - ASSERT_EQ(NULL, t.sibling(n4)) << "sibling(n4) should be NULL"; - ASSERT_EQ(false, t.isInternal(n4)) << "n4 is external"; - ASSERT_EQ(true, t.isExternal(n4)) << "n4 not internal now"; - ASSERT_EQ(false, t.hasLeft(n4)) << "n4 has left child"; - ASSERT_EQ(false, t.hasRight(n4)) << "n4 has right child"; - ASSERT_EQ(0, t.numChildren(n4)) << "numChildren(n4) should be 0"; - ASSERT_EQ(NULL, t.addRight(-3, t.root()->left() )) << "root->left->right overwritten by addRight()"; - - - - //ASSERT_EQ(0, 1) << "test incomplete"; - - } - - - - // remove - void removeNode(){ - Tree t; - node_t* n0 = t.addRoot(0); - node_t* n1 = t.addLeft(1, n0); - node_t* n2 = t.addRight(2, n0); - node_t* n4 = t.addRight(4, n1); - // remove root->left->right - int e; - bool ok = t.removeNode(n4, e); // remove n4 - ASSERT_EQ(true, ok) << "remove failed"; - ASSERT_EQ(4, e) << "wrong element"; - ASSERT_EQ(3, t.size()) << "size not 3"; - ASSERT_EQ(NULL, n1->left()) << "n1->left not NULL"; - ASSERT_EQ(0, t.numChildren(n1)) << "n1 has children"; - ASSERT_EQ(false, t.isInternal(n1)) << "n1 still internal"; - ASSERT_EQ(true, t.isExternal(n1)) << "n1 not external"; - - // now delete n2 - ok = t.removeNode(n2, e); // remove n4 - ASSERT_EQ(true, ok) << "remove failed"; - ASSERT_EQ(2, e) << "wrong element"; - ASSERT_EQ(2, t.size()) << "size not 2"; - ASSERT_EQ(NULL, n0->right()) << "n0->right not NULL"; - ASSERT_EQ(n1, n0->left()) << "n0->left not n1"; - ASSERT_EQ(false, t.hasRight(t.root())) << "root still has right"; - ASSERT_EQ(true, t.hasLeft(t.root())) << "root has no left"; - ASSERT_EQ(1, t.numChildren(t.root())) << "n1->left not NULL"; - ASSERT_EQ(NULL, t.sibling(n1)) << "n1 still has sibling"; - - // try to remove an internal node (should not work) - // add n4 back at root->left->right - n4 = t.addRight(4, t.root()->left()); - ASSERT_EQ(true, t.isInternal(n1)) << "n1 still external"; - ASSERT_EQ(3, t.size()) << "size not 3"; - ok = t.removeNode(n1, e); // attempt removing n1 - ASSERT_EQ(false, ok) << "removeNode() deleted internal node"; - - // try to delete root - ok = t.removeNode(t.root(), e); // remove n1 - ASSERT_EQ(false, ok) << "removeNode() deleted root"; - - - } - - void remove(){ - Tree t; - int e; - node_t* n0 = t.addRoot(0); - node_t* n1 = t.addLeft(1, n0); - node_t* n2 = t.addRight(2, n0); - node_t* n3 = t.addLeft(3, n1); - node_t* n4 = t.addRight(4, n1); - - ///////////////// try deleting subtree at internal node - ASSERT_EQ(5, t.size()) << "size not 4"; - - bool ok = t.remove(n1, e); // remove subtree at n1 - ASSERT_EQ(true, ok) << "remove failed"; - ASSERT_EQ(2, t.size()) << "size not 2"; - ASSERT_EQ(1, e) << "wrong element removed"; - ASSERT_EQ(false, t.hasLeft(t.root())) << "root still has left"; - ASSERT_EQ(1, t.numChildren(t.root())) << "root does not have 1 child"; - - // try removing external node - ok = t.remove(n2, e); // remove subtree at n2 (single node) - ASSERT_EQ(true, ok) << "remove failed"; - ASSERT_EQ(1, t.size()) << "size not 2"; - ASSERT_EQ(2, e) << "wrong element removed"; - ASSERT_EQ(false, t.isInternal(t.root())) << "root still internal"; - ASSERT_EQ(0, t.numChildren(t.root())) << "root does not have any child"; - - // try deleting the entire tree - n1 = t.addLeft(1, t.root()); - n2 = t.addRight(2, t.root()); - n3 = t.addLeft(3, n1); - n4 = t.addRight(4, n1); - node_t* n5 = t.addLeft(5, n2); - - ok = t.remove(t.root(), e); // remove subtree at root (whole tree) - ASSERT_EQ(true, ok) << "remove failed"; - ASSERT_EQ(0, t.size()) << "size not 0"; - ASSERT_EQ(true, t.empty()) << "tree not empty"; - ASSERT_EQ(0, e) << "wrong element removed"; - ASSERT_EQ(NULL, t.root()) << "root not NULL"; - - } - - void clear(){ - node_t *n0, *n1, *n2, *n3, *n4; - Tree t; - //////// clear - t.clear(); // should have no effect - - n0 = t.addRoot(0); - n1 = t.addLeft(1, t.root()); - n2 = t.addRight(2, t.root()); - n3 = t.addLeft(3, n1); - n4 = t.addRight(4, n1); - - ASSERT_EQ(4, t.size()) << "size not 4"; - ASSERT_EQ(false, t.empty()) << "tree empty"; - ASSERT_NE(NULL, (int)t.root()) << "root NULL"; - - t.clear(); - - ASSERT_EQ(0, t.size()) << "size not 0"; - ASSERT_EQ(true, t.empty()) << "tree not empty"; - ASSERT_EQ(NULL, (int) t.root()) << "root not NULL"; - - } - - void toString(){ - Tree t; - node_t* n0 = t.addRoot(0); - - node_t* n1 = t.addLeft(1, n0); - node_t* n2 = t.addRight(2, n0); - - node_t* n3 = t.addLeft(3, n1); - // no 4 - node_t* n5 = t.addLeft(5, n2); - node_t* n6 = t.addRight(6, n2); - // no 7 - node_t* n8 = t.addRight(8, n3); - /* - 0 - 1 2 - 3 - 5 6 - - 8 - - */ - - const string preorderTrimmed = "0138256"; // preorder, without space - string str = t.toString(); // result, with space - // remove space - string actualTrimmed = strPurge(str, "| "); // purge | and space - ASSERT_EQ(actualTrimmed, preorderTrimmed) << "toString() mismatch"; - - string strBt, strExpected; - /////////// preorder - strBt = t.toStringPreOrder(); - strBt = strPurge(strBt, "| "); - strExpected = "0138256"; - ASSERT_EQ(strExpected, strBt) << "preorder mismatch"; - - /////////// postorder - strBt = t.toStringPostOrder(); - strBt = strPurge(strBt, "| "); - strExpected = "8315620"; - ASSERT_EQ(strExpected, strBt) << "postorder mismatch"; - - /////////// inorder - strBt = t.toStringInOrder(); - strBt = strPurge(strBt, "| "); - strExpected = "3810526"; - ASSERT_EQ(strExpected, strBt) << "inorder mismatch"; - - - /////////// BFSorder - strBt = t.toStringBFS(); - strBt = strPurge(strBt, "| "); - strExpected = "0123568"; - ASSERT_EQ(strExpected, strBt) << "BFS order mismatch"; - } - -}; -ADD_TEST_F(BinaryTreeTest, add); -ADD_TEST_F(BinaryTreeTest, removeNode); -ADD_TEST_F(BinaryTreeTest, remove); -ADD_TEST_F(BinaryTreeTest, toString); } // namespace ds } // namespace yasi \ No newline at end of file diff --git a/YASI_12/ds.binarytree.test.h b/YASI_12/ds.binarytree.test.h new file mode 100644 index 0000000..29291ea --- /dev/null +++ b/YASI_12/ds.binarytree.test.h @@ -0,0 +1,357 @@ +#pragma once + +#if YASI_TEST_THIS_MODULE != 1 +#define YASI_TEST_THIS_MODULE 1 +#endif +#include "ds.binarytree.h" + +namespace yasi{ + namespace ds{ + + // test + class BinaryTreeTest : public yasi::Test{ + public: + typedef BinaryTree > Tree; + typedef Tree::node_t node_t; + /////////////////////////// + /////// IBinaryTree methods + /////////////////////////// + + // size, empty + // left, right, parent, sibling, root, numChildren + // isLeft, isRight, hasLeft, hasRight + // isInternal, isExternal, isRoot + // addLeft, addRight, addRoot + void add(){ + Tree t; + + // add root + node_t* n0 = t.addRoot(0); + ASSERT_EQ(1, t.size()) << "size not 1"; + ASSERT_EQ(false, t.empty()) << "tree empty"; + ASSERT_EQ(n0, t.root()) << "root not n0"; + ASSERT_EQ(true, t.isRoot(n0)) << "root not n0"; + ASSERT_EQ(0, n0->element) << "root-element not 0"; + ASSERT_EQ(false, t.isLeft(n0)) << "n0 not a left child"; + ASSERT_EQ(false, t.isRight(n0)) << "n0 not a right child"; + ASSERT_EQ(false, t.hasLeft(n0)) << "root has not left child"; + ASSERT_EQ(false, t.hasRight(n0)) << "root has no right child"; + ASSERT_EQ(false, t.isInternal(n0)) << "root not internal yet"; + ASSERT_EQ(true, t.isExternal(n0)) << "root should be external now"; + ASSERT_EQ(NULL, t.left(n0)) << "left(root) should be NULL"; + ASSERT_EQ(NULL, t.right(n0)) << "right(root) should be NULL"; + ASSERT_EQ(NULL, t.parent(n0)) << "parent(root) should be NULL"; + ASSERT_EQ(NULL, t.sibling(n0)) << "sibling(root) should be NULL"; + ASSERT_EQ(0, t.numChildren(n0)) << "numChildren(root) should be 0"; + + /////////////// add root->left + node_t* n1 = t.addLeft(1, t.root()); + ASSERT_EQ(2, t.size()) << "size not 2"; + ASSERT_EQ(false, t.empty()) << "tree empty"; + // about root + ASSERT_EQ(n0, t.root()) << "root not n0"; + ASSERT_EQ(n0, t.parent(n1)) << "n1 not child of n0"; + ASSERT_EQ(true, t.hasLeft(n0)) << "root has a left child"; + ASSERT_EQ(false, t.hasRight(n0)) << "root has no right child"; + ASSERT_EQ(true, t.isInternal(n0)) << "root is internal"; + ASSERT_EQ(false, t.isExternal(n0)) << "root not external now"; + ASSERT_EQ(NULL, t.right(n0)) << "right(root) should be NULL"; + ASSERT_EQ(NULL, t.parent(n0)) << "parent(root) should be NULL"; + ASSERT_EQ(NULL, t.sibling(n0)) << "sibling(root) should be NULL"; + ASSERT_EQ(1, t.numChildren(n0)) << "numChildren(root) should be 1"; + // about root->left + ASSERT_EQ(1, n1->element) << "element not 1"; + ASSERT_EQ(n1, t.left(n0)) << "n1 not left child of n0"; + ASSERT_NE(n1, t.right(n0)) << "n1 right child of n0"; + ASSERT_EQ(true, t.isLeft(n1)) << "n1 is a left child"; + ASSERT_EQ(false, t.isRight(n1)) << "n1 is a right child"; + ASSERT_EQ(n0, t.parent(n1)) << "n0 not parent of n1"; + ASSERT_EQ(NULL, t.sibling(n1)) << "sibling(n1) wrong"; + ASSERT_EQ(false, t.isInternal(n1)) << "n1 is external"; + ASSERT_EQ(true, t.isExternal(n1)) << "n1 not internal now"; + ASSERT_EQ(false, t.hasLeft(n1)) << "n1 has left child"; + ASSERT_EQ(false, t.hasRight(n1)) << "n1 has right child"; + ASSERT_EQ(0, t.numChildren(n1)) << "numChildren(n1) should be 0"; + ASSERT_EQ(NULL, t.addLeft(-3, t.root())) << "root->left overwritten by addLeft()"; + + /////////// add root->right + node_t* n2 = t.addRight(2, t.root()); + ASSERT_EQ(3, t.size()) << "size not 3"; + ASSERT_EQ(false, t.empty()) << "tree empty"; + // about root + ASSERT_EQ(n0, t.root()) << "root not n0"; + ASSERT_EQ(n0, t.parent(n2)) << "n2 not child of n0"; + ASSERT_EQ(true, t.hasLeft(n0)) << "root has a left child"; + ASSERT_EQ(true, t.hasRight(n0)) << "root has no right child"; + ASSERT_EQ(true, t.isInternal(n0)) << "root is internal"; + ASSERT_EQ(false, t.isExternal(n0)) << "root not external now"; + ASSERT_EQ(n2, t.right(n0)) << "right(root) should be n2"; + ASSERT_EQ(NULL, t.parent(n0)) << "parent(root) should be NULL"; + ASSERT_EQ(NULL, t.sibling(n0)) << "sibling(root) should be NULL"; + ASSERT_EQ(2, t.numChildren(n0)) << "numChildren(root) should be 2"; + // about root->left + ASSERT_EQ(1, n1->element) << "element not 1"; + ASSERT_EQ(n1, t.left(n0)) << "n1 not left child of n0"; + ASSERT_NE(n1, t.right(n0)) << "n1 right child of n0"; + ASSERT_EQ(true, t.isLeft(n1)) << "n1 is a left child"; + ASSERT_EQ(false, t.isRight(n1)) << "n1 is a right child"; + ASSERT_EQ(n0, t.parent(n1)) << "n0 not parent of n1"; + ASSERT_EQ(n2, t.sibling(n1)) << "sibling(n1) wrong"; + ASSERT_EQ(false, t.isInternal(n1)) << "n1 is external"; + ASSERT_EQ(true, t.isExternal(n1)) << "n1 not internal now"; + ASSERT_EQ(false, t.hasLeft(n1)) << "n1 has left child"; + ASSERT_EQ(false, t.hasRight(n1)) << "n1 has right child"; + ASSERT_EQ(0, t.numChildren(n1)) << "numChildren(n1) should be 0"; + // about root->right + ASSERT_EQ(2, n2->element) << "element not 2"; + ASSERT_EQ(n2, t.right(n0)) << "n2 not right child of n0"; + ASSERT_NE(n2, t.left(n0)) << "n2 left child of n0"; + ASSERT_EQ(false, t.isLeft(n2)) << "n2 is a left child"; + ASSERT_EQ(true, t.isRight(n2)) << "n2 not a right child"; + ASSERT_EQ(n0, t.parent(n2)) << "n0 not parent of n2"; + ASSERT_EQ(n1, t.sibling(n2)) << "sibling(n2) should be n1"; + ASSERT_EQ(false, t.isInternal(n2)) << "n2 is external"; + ASSERT_EQ(true, t.isExternal(n2)) << "n2 not internal now"; + ASSERT_EQ(false, t.hasLeft(n2)) << "n2 has left child"; + ASSERT_EQ(false, t.hasRight(n2)) << "n2 has right child"; + ASSERT_EQ(0, t.numChildren(n2)) << "numChildren(n2) should be 0"; + ASSERT_EQ(NULL, t.addRight(-3, t.root())) << "root->right overwritten by addRight()"; + + /////////// add root->left->right + node_t* n4 = t.addRight(4, n1); + ASSERT_EQ(4, t.size()) << "size not 4"; + ASSERT_EQ(false, t.empty()) << "tree empty"; + // about root + ASSERT_EQ(n0, t.root()) << "root not n0"; + ASSERT_EQ(n0, t.parent(t.parent(n4))) << "n2 not grand child of n0"; + ASSERT_EQ(true, t.hasLeft(n0)) << "root has a left child"; + ASSERT_EQ(true, t.hasRight(n0)) << "root has no right child"; + ASSERT_EQ(true, t.isInternal(n0)) << "root is internal"; + ASSERT_EQ(false, t.isExternal(n0)) << "root not external now"; + ASSERT_EQ(n2, t.right(n0)) << "right(root) should be n2"; + ASSERT_EQ(n1, t.left(n0)) << "left(root) should be n1"; + ASSERT_EQ(NULL, t.parent(n0)) << "parent(root) should be NULL"; + ASSERT_EQ(NULL, t.sibling(n0)) << "sibling(root) should be NULL"; + ASSERT_EQ(2, t.numChildren(n0)) << "numChildren(root) should be 1"; + // about root->left + ASSERT_EQ(1, n1->element) << "element not 1"; + ASSERT_EQ(n1, t.left(n0)) << "n1 not left child of n0"; + ASSERT_NE(n1, t.right(n0)) << "n1 right child of n0"; + ASSERT_EQ(true, t.isLeft(n1)) << "n1 is a left child"; + ASSERT_EQ(false, t.isRight(n1)) << "n1 is a right child"; + ASSERT_EQ(n0, t.parent(n1)) << "n0 not parent of n1"; + ASSERT_EQ(n2, t.sibling(n1)) << "sibling(n1) wrong"; + ASSERT_EQ(true, t.isInternal(n1)) << "n1 external"; + ASSERT_EQ(false, t.isExternal(n1)) << "n1 internal now"; + ASSERT_EQ(false, t.hasLeft(n1)) << "n1 has no left child"; + ASSERT_EQ(true, t.hasRight(n1)) << "n1 has no right child"; + ASSERT_EQ(1, t.numChildren(n1)) << "numChildren(n1) should be 1"; + // about root->right + ASSERT_EQ(2, n2->element) << "element not 2"; + ASSERT_EQ(n2, t.right(n0)) << "n2 not right child of n0"; + ASSERT_NE(n2, t.left(n0)) << "n2 left child of n0"; + ASSERT_EQ(false, t.isLeft(n2)) << "n2 is a left child"; + ASSERT_EQ(true, t.isRight(n2)) << "n2 not a right child"; + ASSERT_EQ(n0, t.parent(n2)) << "n0 not parent of n2"; + ASSERT_EQ(n1, t.sibling(n2)) << "sibling(n2) should be n1"; + ASSERT_EQ(false, t.isInternal(n2)) << "n2 is external"; + ASSERT_EQ(true, t.isExternal(n2)) << "n2 not internal now"; + ASSERT_EQ(false, t.hasLeft(n2)) << "n2 has left child"; + ASSERT_EQ(false, t.hasRight(n2)) << "n2 has right child"; + ASSERT_EQ(0, t.numChildren(n2)) << "numChildren(n2) should be 0"; + // about root->left->right + ASSERT_EQ(4, n4->element) << "element not 4"; + ASSERT_EQ(n4, t.right(n1)) << "n4 not right child of n1"; + ASSERT_NE(n4, t.left(n1)) << "n4 left child of n1"; + ASSERT_EQ(false, t.isLeft(n4)) << "n4 is a left child"; + ASSERT_EQ(true, t.isRight(n4)) << "n4 not a right child"; + ASSERT_EQ(n1, t.parent(n4)) << "n1 not parent of n4"; + ASSERT_EQ(NULL, t.sibling(n4)) << "sibling(n4) should be NULL"; + ASSERT_EQ(false, t.isInternal(n4)) << "n4 is external"; + ASSERT_EQ(true, t.isExternal(n4)) << "n4 not internal now"; + ASSERT_EQ(false, t.hasLeft(n4)) << "n4 has left child"; + ASSERT_EQ(false, t.hasRight(n4)) << "n4 has right child"; + ASSERT_EQ(0, t.numChildren(n4)) << "numChildren(n4) should be 0"; + ASSERT_EQ(NULL, t.addRight(-3, t.root()->left())) << "root->left->right overwritten by addRight()"; + + + + //ASSERT_EQ(0, 1) << "test incomplete"; + + } + + + + // remove + void removeNode(){ + Tree t; + node_t* n0 = t.addRoot(0); + node_t* n1 = t.addLeft(1, n0); + node_t* n2 = t.addRight(2, n0); + node_t* n4 = t.addRight(4, n1); + // remove root->left->right + int e; + bool ok = t.removeNode(n4, e); // remove n4 + ASSERT_EQ(true, ok) << "remove failed"; + ASSERT_EQ(4, e) << "wrong element"; + ASSERT_EQ(3, t.size()) << "size not 3"; + ASSERT_EQ(NULL, n1->left()) << "n1->left not NULL"; + ASSERT_EQ(0, t.numChildren(n1)) << "n1 has children"; + ASSERT_EQ(false, t.isInternal(n1)) << "n1 still internal"; + ASSERT_EQ(true, t.isExternal(n1)) << "n1 not external"; + + // now delete n2 + ok = t.removeNode(n2, e); // remove n4 + ASSERT_EQ(true, ok) << "remove failed"; + ASSERT_EQ(2, e) << "wrong element"; + ASSERT_EQ(2, t.size()) << "size not 2"; + ASSERT_EQ(NULL, n0->right()) << "n0->right not NULL"; + ASSERT_EQ(n1, n0->left()) << "n0->left not n1"; + ASSERT_EQ(false, t.hasRight(t.root())) << "root still has right"; + ASSERT_EQ(true, t.hasLeft(t.root())) << "root has no left"; + ASSERT_EQ(1, t.numChildren(t.root())) << "n1->left not NULL"; + ASSERT_EQ(NULL, t.sibling(n1)) << "n1 still has sibling"; + + // try to remove an internal node (should not work) + // add n4 back at root->left->right + n4 = t.addRight(4, t.root()->left()); + ASSERT_EQ(true, t.isInternal(n1)) << "n1 still external"; + ASSERT_EQ(3, t.size()) << "size not 3"; + ok = t.removeNode(n1, e); // attempt removing n1 + ASSERT_EQ(false, ok) << "removeNode() deleted internal node"; + + // try to delete root + ok = t.removeNode(t.root(), e); // remove n1 + ASSERT_EQ(false, ok) << "removeNode() deleted root"; + + + } + + void remove(){ + Tree t; + int e; + node_t* n0 = t.addRoot(0); + node_t* n1 = t.addLeft(1, n0); + node_t* n2 = t.addRight(2, n0); + node_t* n3 = t.addLeft(3, n1); + node_t* n4 = t.addRight(4, n1); + + ///////////////// try deleting subtree at internal node + ASSERT_EQ(5, t.size()) << "size not 4"; + + bool ok = t.remove(n1, e); // remove subtree at n1 + ASSERT_EQ(true, ok) << "remove failed"; + ASSERT_EQ(2, t.size()) << "size not 2"; + ASSERT_EQ(1, e) << "wrong element removed"; + ASSERT_EQ(false, t.hasLeft(t.root())) << "root still has left"; + ASSERT_EQ(1, t.numChildren(t.root())) << "root does not have 1 child"; + + // try removing external node + ok = t.remove(n2, e); // remove subtree at n2 (single node) + ASSERT_EQ(true, ok) << "remove failed"; + ASSERT_EQ(1, t.size()) << "size not 2"; + ASSERT_EQ(2, e) << "wrong element removed"; + ASSERT_EQ(false, t.isInternal(t.root())) << "root still internal"; + ASSERT_EQ(0, t.numChildren(t.root())) << "root does not have any child"; + + // try deleting the entire tree + n1 = t.addLeft(1, t.root()); + n2 = t.addRight(2, t.root()); + n3 = t.addLeft(3, n1); + n4 = t.addRight(4, n1); + node_t* n5 = t.addLeft(5, n2); + + ok = t.remove(t.root(), e); // remove subtree at root (whole tree) + ASSERT_EQ(true, ok) << "remove failed"; + ASSERT_EQ(0, t.size()) << "size not 0"; + ASSERT_EQ(true, t.empty()) << "tree not empty"; + ASSERT_EQ(0, e) << "wrong element removed"; + ASSERT_EQ(NULL, t.root()) << "root not NULL"; + + } + + void clear(){ + node_t *n0, *n1, *n2, *n3, *n4; + Tree t; + //////// clear + t.clear(); // should have no effect + + n0 = t.addRoot(0); + n1 = t.addLeft(1, t.root()); + n2 = t.addRight(2, t.root()); + n3 = t.addLeft(3, n1); + n4 = t.addRight(4, n1); + + ASSERT_EQ(4, t.size()) << "size not 4"; + ASSERT_EQ(false, t.empty()) << "tree empty"; + ASSERT_NE(NULL, (int)t.root()) << "root NULL"; + + t.clear(); + + ASSERT_EQ(0, t.size()) << "size not 0"; + ASSERT_EQ(true, t.empty()) << "tree not empty"; + ASSERT_EQ(NULL, (int)t.root()) << "root not NULL"; + + } + + void toString(){ + Tree t; + node_t* n0 = t.addRoot(0); + + node_t* n1 = t.addLeft(1, n0); + node_t* n2 = t.addRight(2, n0); + + node_t* n3 = t.addLeft(3, n1); + // no 4 + node_t* n5 = t.addLeft(5, n2); + node_t* n6 = t.addRight(6, n2); + // no 7 + node_t* n8 = t.addRight(8, n3); + /* + 0 + 1 2 + 3 - 5 6 + - 8 + + */ + + const string preorderTrimmed = "0138256"; // preorder, without space + string str = t.toString(); // result, with space + // remove space + string actualTrimmed = strPurge(str, "| "); // purge | and space + ASSERT_EQ(actualTrimmed, preorderTrimmed) << "toString() mismatch"; + + string strBt, strExpected; + /////////// preorder + strBt = t.toStringPreOrder(); + strBt = strPurge(strBt, "| "); + strExpected = "0138256"; + ASSERT_EQ(strExpected, strBt) << "preorder mismatch"; + + /////////// postorder + strBt = t.toStringPostOrder(); + strBt = strPurge(strBt, "| "); + strExpected = "8315620"; + ASSERT_EQ(strExpected, strBt) << "postorder mismatch"; + + /////////// inorder + strBt = t.toStringInOrder(); + strBt = strPurge(strBt, "| "); + strExpected = "3810526"; + ASSERT_EQ(strExpected, strBt) << "inorder mismatch"; + + + /////////// BFSorder + strBt = t.toStringBFS(); + strBt = strPurge(strBt, "| "); + strExpected = "0123568"; + ASSERT_EQ(strExpected, strBt) << "BFS order mismatch"; + } + + }; + ADD_TEST_F(BinaryTreeTest, add); + ADD_TEST_F(BinaryTreeTest, removeNode); + ADD_TEST_F(BinaryTreeTest, remove); + ADD_TEST_F(BinaryTreeTest, toString); + } +} \ No newline at end of file diff --git a/YASI_12/ds.binarytreebase.h b/YASI_12/ds.binarytreebase.h index 0e47c10..a3f1629 100644 --- a/YASI_12/ds.binarytreebase.h +++ b/YASI_12/ds.binarytreebase.h @@ -1,5 +1,6 @@ #pragma once #include "common.h" +#include "ds.tree.h" #include "ds.doublylinkedlist.h" #include using namespace std; diff --git a/YASI_12/main.cpp b/YASI_12/main.cpp index 14941fc..ac4a420 100644 --- a/YASI_12/main.cpp +++ b/YASI_12/main.cpp @@ -1,7 +1,5 @@ #include "common.h" -//#include "utils.h" -//#include "ds.singlylinkedlist.h" -//#include "ds.doublylinkedlist.h" + //#include "ds.arraybinarytree.h" //#include "ds.binaryheap.h" //#include "ds.binarytree.h" @@ -31,6 +29,8 @@ using namespace std; #include "ds.iterator.test.h" #include "ds.singlylinkedlist.test.h" #include "ds.doublylinkedlist.test.h" +#include "ds.binarytree.test.h" +#include "ds.arraybinarytree.test.h" int testAll(int* argc, char** argv){