diff --git a/YASI_12/YASI_12.vcxproj b/YASI_12/YASI_12.vcxproj index 81a27c4..a47d2e8 100644 --- a/YASI_12/YASI_12.vcxproj +++ b/YASI_12/YASI_12.vcxproj @@ -79,6 +79,7 @@ + @@ -99,8 +100,13 @@ + + + + + diff --git a/YASI_12/YASI_12.vcxproj.filters b/YASI_12/YASI_12.vcxproj.filters index ad4aa77..4fa2405 100644 --- a/YASI_12/YASI_12.vcxproj.filters +++ b/YASI_12/YASI_12.vcxproj.filters @@ -155,10 +155,28 @@ Header Files\Data Structures\List + + Header Files\Data Structures\Tree + + Header Files\Data Structures\Tree + + + Header Files\Data Structures\Heap + + + Header Files\Data Structures\Heap + + + Header Files\Data Structures\Heap + + Header Files - + + Header Files + + Header Files diff --git a/YASI_12/ds.binaryheap.h b/YASI_12/ds.binaryheap.h index 880f29b..1453180 100644 --- a/YASI_12/ds.binaryheap.h +++ b/YASI_12/ds.binaryheap.h @@ -7,10 +7,12 @@ #include "ds.aux.hastree.h" #include "ds.kvpair.h" +using namespace std; -namespace yasi{ +// enable-disable testing classes in this file +#include "test.this.module.h" -using namespace std; +namespace yasi{ namespace ds{ @@ -68,7 +70,7 @@ class BinaryHeapBase : public IBinaryHeap >, // template > class BinaryHeap : public BinaryHeapBase{ - friend class BinaryHeapTest; + FRIEND_TEST_CLASS( BinaryHeapTest); public: // public typedef typedef ArrayBinaryTree Tree; @@ -344,490 +346,6 @@ class BinaryHeap : public BinaryHeapBase{ }; -// test the BinaryHeap class -class BinaryHeapTest : public yasi::Test{ -protected: - typedef BinaryHeap::node_t node_t; - -public: - - template > - void checkHeapElements(HeapType* pHeap, const E* pElemsArr, const int numElems){ - return ArrayBinaryTreeTest::checkElements(&pHeap->bt, pElemsArr, numElems); - } - - void heapify(){ - const int heapSize = 5; - int arr[] = { 10, 5, 20, 15, 25 }; - int n = ARR_LENGTH(arr); - BinaryHeap h; - bool ok = h.heapify(arr, n); - ASSERT_EQ(true, ok) << "heapify failed"; - - // assuming min-heap - { - SCOPED_TRACE("heapify #1"); - int newArr[] = { 5, 10, 20, 15, 25 }; - checkHeapElements(&h, newArr, heapSize); - } - - ok = h.heapify(arr, -1); - ASSERT_EQ(false, ok) << "heapify succeeded with negative size"; - - ok = h.heapify(NULL, 4); - ASSERT_EQ(false, ok) << "heapify succeeded with NULL array"; - - } - - void top(){ - int e; - bool ok = true; - BinaryHeap h; - - h.insert(15); - h.insert(5); - h.insert(25); - h.insert(10); - h.insert(20); - - // assuming min-heap - ASSERT_EQ(5, h.size()) << "heap size should have been 5"; - e = h.top(); - ASSERT_EQ(5, e) << "top should have been 5"; - e = h.top(); - ASSERT_EQ(5, e) << "top should still have been 5"; - h.pop(); // pop 5 - e = h.top(); - ASSERT_EQ(10, e) << "top should still have been 10"; - h.pop(); // pop 10 - e = h.top(); - ASSERT_EQ(15, e) << "top should have been 15"; - h.pop(); // pop 15 - e = h.top(); - ASSERT_EQ(20, e) << "top should have been 20"; - h.pop(); // pop 20 - e = h.top(); - ASSERT_EQ(25, e) << "top should have been 25"; - h.pop(); // pop 25 - ASSERT_EQ(0, h.size()) << "heap size should have been 0"; - - - } - - void bubbleUp(){ - const int heapSize = 6; - int arr[] = { 5, 10, 15, 2, 30, 7 }; // 2 (child of 10) and 7 (child of 15), violate heap property - int n = ARR_LENGTH(arr); - BinaryHeap h; - h.setTree(arr, n); - // now the binary tree has heap-property violations - - node_t* pNode = h.bt.nodeAt(4); // 2 - h.bubbleUp(pNode); - // arr = {2, 5, 15, 10, 30, 7} - { - SCOPED_TRACE("bubbleUp(2)"); - int newArr[] = { 2, 5, 15, 10, 30, 7 }; - checkHeapElements(&h, newArr, heapSize); - } - - pNode = h.bt.nodeAt(6); // 7 - h.bubbleUp(pNode); // 7 should stop as a child of 2 - // arr = {2, 5, 7, 10, 30, 15} - { - SCOPED_TRACE("bubbleUp(7)"); - int newArr[] = { 2, 5, 7, 10, 30, 15 }; - checkHeapElements(&h, newArr, heapSize); - } - } - - void selectChildForBubbleDown(){ - BinaryHeap h; - // case: bubbleDown along right child - int arr[] = { 10, 20, 30 }; // 35 (parent of 100 and 15) and 15 (parent of 7) violate heap property - h.setTree(arr, 3); - node_t* pNode = h.selectChildForBubbleDown(h.bt.root()); // should be NULL - ASSERT_EQ(0, (int)pNode) << "should not bubble down"; - - h.clear(); - int arr2[] = { 10, 5, 8 }; - h.setTree(arr2, 3); - pNode = h.selectChildForBubbleDown(h.bt.root()); // should be 5 - ASSERT_EQ(5, pNode->element) << "should be 5"; - - h.clear(); - int arr3[] = { 10, 15, 8 }; - h.setTree(arr3, 3); - pNode = h.selectChildForBubbleDown(h.bt.root()); // should be 8 - ASSERT_EQ(8, pNode->element) << "should be 8"; - - h.clear(); - int arr4[] = { 5, 10, 10 }; - h.setTree(arr4, 3); - pNode = h.selectChildForBubbleDown(h.bt.root()); // should be right child of root - ASSERT_EQ(0, (int) pNode) << "should not bubble down"; - - h.clear(); - int arr5[] = { 10, 10, 10 }; - h.setTree(arr5, 3); - pNode = h.selectChildForBubbleDown(h.bt.root()); // should not bubble down - ASSERT_EQ(0, (int) pNode) << "should not bubble down when all equal"; - } - - void bubbleDown(){ - const int heapSize = 6; - // case: bubbleDown along right child - int arr[] = { 35, 100, 15, 50, 30, 7 }; // 35 (parent of 100 and 15) and 15 (parent of 7) violate heap property - int n = ARR_LENGTH(arr); - BinaryHeap h; - h.setTree(arr, n); - // now the binary tree has heap-property violations - - node_t* pNode = h.bt.root(); // 35 - h.bubbleDown(pNode); - // arr={15, 100, 7, 50, 30, 35} - { - SCOPED_TRACE("bubbleDown(35)"); - int newArr[] = { 15, 100, 7, 50, 30, 35 }; - checkHeapElements(&h, newArr, heapSize); - } - - h.bubbleDown(h.bt.root()); // 15 - // arr={7, 100, 15, 50, 30, 35} - { - SCOPED_TRACE("bubbleDown(15)"); - int newArr[] = { 7, 100, 15, 50, 30, 35 }; - checkHeapElements(&h, newArr, heapSize); - } - - h.bubbleDown(h.bt.nodeAt(4)); // no effect: external - // arr={7, 100, 15, 50, 30, 35} - { - SCOPED_TRACE("bubbleDown(50)"); - int newArr[] = { 7, 100, 15, 50, 30, 35 }; - checkHeapElements(&h, newArr, heapSize); - } - - // case: bubbleDown along left child - int arr2[] = { 35, 15, 100, 50, 30, 7 }; // 35 (parent of 100 and 15) and 100 (parent of 7) violate heap property - n = ARR_LENGTH(arr2); - BinaryHeap h2; - h2.setTree(arr2, n); - // now the binary tree has heap-property violations - - pNode = h2.bt.root(); // 35 - h2.bubbleDown(pNode); - // arr={15, 30, 100, 50, 35, 7} - { - SCOPED_TRACE("bubbleDown(35)"); - int newArr[] = { 15, 30, 100, 50, 35, 7 }; - checkHeapElements(&h2, newArr, heapSize); - } - } - - void insert(){ - BinaryHeap h; - - // root - h.insert(5); - // arr={5} - { - SCOPED_TRACE("insert(5)"); - int newArr[] = { 5 }; - checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); - } - - // add a large element, should not bubble up - h.insert(10); - // arr={5, 10} - { - SCOPED_TRACE("insert(10)"); - int newArr[] = { 5, 10 }; - checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); - } - - // add a small element, should bubble up - h.insert(3); - // arr = {3, 10, 5} - { - SCOPED_TRACE("insert(3)"); - int newArr[] = { 3, 10, 5 }; - checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); - } - - // add another small element, should bubble up - h.insert(1); - // arr = {1, 3, 5, 10} - { - SCOPED_TRACE("insert(1)"); - int newArr[] = { 1, 3, 5, 10 }; - checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); - } - - h.insert(2); - // arr = {1, 2, 5, 10, 3} - { - SCOPED_TRACE("insert(2)"); - int newArr[] = { 1, 2, 5, 10, 3 }; - checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); - } - - } - - void pop(){ - const int heapSize = 6; - int arr[] = { 5, 10, 15, 20, 25, 30 }; // valid heap - int n = ARR_LENGTH(arr); - BinaryHeap h; - h.setTree(arr, n); // valid heap - int e; - - e = h.top(); // e = 5 - h.pop(); - ASSERT_EQ(5, e) << "top elem should be 5"; - // arr={10, 20, 15, 30, 25} - { - SCOPED_TRACE("pop #1"); - int newArr[] = { 10, 20, 15, 30, 25 }; - checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); - } - - e = h.top(); // e = 10 - h.pop(); - ASSERT_EQ(10, e) << "top elem should be 10"; - // arr={15, 20, 25, 30} - { - SCOPED_TRACE("pop #2"); - int newArr[] = { 15, 20, 25, 30 }; - checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); - } - - e = h.top(); // e = 15 - h.pop(); - ASSERT_EQ(15, e) << "top elem should be 15"; - // arr={20, 30, 25} - { - SCOPED_TRACE("pop #3"); - int newArr[] = { 20, 30, 25 }; - checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); - } - - e = h.top(); // e = 20 - h.pop(); - ASSERT_EQ(20, e) << "top elem should be 20"; - // arr={25, 30} - { - SCOPED_TRACE("pop #4"); - int newArr[] = { 25, 30 }; - checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); - } - - e = h.top(); // e = 25 - h.pop(); - ASSERT_EQ(25, e) << "top elem should be 25"; - // arr={30} - { - SCOPED_TRACE("pop #5"); - int newArr[] = { 30 }; - checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); - } - - e = h.top(); // e = 30 - h.pop(); - ASSERT_EQ(30, e) << "top elem should be 30"; - // arr={} - ASSERT_EQ(true, h.empty()) << "heap should have been empty"; - - } - - void maxHeap(){ - const int heapSize = 5; - int arr[] = { 10, 5, 20, 15, 25 }; - int n = ARR_LENGTH(arr); - typedef BinaryHeap > HeapType; - HeapType h; - bool ok = h.heapify(arr, n); - ASSERT_EQ(true, ok) << "heapify failed"; - - // should be max-heap - { - /* heap: - 25 - 20 10 - 5 15 - */ - SCOPED_TRACE("max-heap #1"); - //int newArr[] = { 25, 20, 10, 5, 15 }; - //checkHeapElements(&h, newArr, heapSize); - string actual = strPurge(h.toStringBFS(), "| "); - ASSERT_EQ("252010515", actual) << "bad max heap from heapify"; - } - - // add some more items - { - h.push(12); - h.push(30); - h.push(3); - h.push(40); - /* heap: - 40 - 30 25 - 20 15 10 12 - 3 5 - */ - SCOPED_TRACE("max-heap #2"); - string actual = strPurge(h.toStringBFS(), "| "); - ASSERT_EQ("4030252015101235", actual) << "bad max heap after add"; - } - - - } - - // compare a heap made of numeric strings, - // and the comparison will be done after turning them into numbers - // creates a max heap with predicate NumericStringMaxHeapPredicate - void customComparatorHeap(){ - const int heapSize = 5; - typedef string HeapElement; - HeapElement srcArr[] = { - HeapElement("10"), - HeapElement("5"), - HeapElement("20"), - HeapElement("15"), - HeapElement("25") - }; - int n = ARR_LENGTH(srcArr); - // max heap with binary trees as elements - typedef BinaryHeap HeapType; - HeapType h; - bool ok = h.heapify(srcArr, n); - ASSERT_EQ(true, ok) << "heapify failed"; - // should be max-heap - { - /* heap: - 25 - 20 10 - 5 15 - */ - SCOPED_TRACE("max-heap #1"); - string actual = strPurge(h.toStringBFS(), "| "); - ASSERT_EQ("252010515", actual) << "bad max heap from heapify"; - } - - // add some more items - { - h.push("12"); - h.push("30"); - h.push("3"); - h.push("40"); - /* heap: - 40 - 30 25 - 20 15 10 12 - 3 5 - */ - SCOPED_TRACE("max-heap #2"); - string actual = strPurge(h.toStringBFS(), "| "); - ASSERT_EQ("4030252015101235", actual) << "bad max heap after add"; - } - - - } - -}; - - - -ADD_TEST_F(BinaryHeapTest, heapify); -ADD_TEST_F(BinaryHeapTest, top); -ADD_TEST_F(BinaryHeapTest, pop); -ADD_TEST_F(BinaryHeapTest, insert); -ADD_TEST_F(BinaryHeapTest, bubbleUp); -ADD_TEST_F(BinaryHeapTest, selectChildForBubbleDown); -ADD_TEST_F(BinaryHeapTest, bubbleDown); -ADD_TEST_F(BinaryHeapTest, maxHeap); -ADD_TEST_F(BinaryHeapTest, customComparatorHeap); - - -////////////////////////////////////////////// -//////////////// Mutable Heap //////////////// -////////////////////////////////////////////// -template -class MutableHeap : public BinaryHeap < KVPair > { - ////////// enable testing /////////// - friend class MutableHeapTest; - typedef KVPair HeapElement; - typedef BinaryHeap Heap; - typedef typename Heap::HeapNode Node; - -public: - virtual ~MutableHeap(){} - MutableHeap(){} - MutableHeap(const HeapElement* pArr, const int numElems) : Heap(pArr, numElems){} - void updateKey(Node* pNode, const Key newKey){ - if (pNode){ - HeapElement newElem(newKey); - if (pNode->element != newElem){ - // need update - if (newElem < pNode->element){ - // need bubble-up - ((HeapElement*)& pNode->element)->key = newKey; // updated - bubbleUp(pNode); - } - else{ - // need bubble-down - ((HeapElement*)& pNode->element)->key = newKey; // updated - bubbleDown(pNode); - } - } - } - } -}; - -class MutableHeapTest : public yasi::Test{ - typedef KVPair Pair; - typedef MutableHeap MHeap; -public: - void updateKey(){ - MHeap h; - MHeap::HeapNode* n[5]; - for (int i = 0; i < 5; i++){ - n[i] = h.insert(Pair(i)); // both key and value are i - } - - string str = h.toStringBFS(); // should be 0 1 2 3 4 - string strBefore = strPurge(str, "| "); - string expectedStrBefore = "01234"; - ASSERT_EQ(expectedStrBefore, strBefore) << "heap toString() mismatch"; - - // now update key 3 to 9 - h.updateKey(n[3], 9); - // heap: 0 1 2 9 4 - str = h.toStringBFS(); - string strAfter = strPurge(str, "| "); - string expectedStrAfter = "01294"; - ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 3-->9"; - - // now update key 2 to -8 - h.updateKey(n[2], -8); - // heap: -8 1 0 9 4 - str = h.toStringBFS(); - strAfter = strPurge(str, "| "); - expectedStrAfter = "-81094"; - ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 2-->-8"; - - // now update key 9 to -9 - h.updateKey(n[3], -9); - // heap: -9 -8 0 1 4 - str = h.toStringBFS(); - strAfter = strPurge(str, "| "); - expectedStrAfter = "-9-8014"; - ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 9-->-9"; - - } -}; - -ADD_TEST_F(MutableHeapTest, updateKey); } // namespace yasi.ds diff --git a/YASI_12/ds.binaryheap.test.h b/YASI_12/ds.binaryheap.test.h new file mode 100644 index 0000000..c198b59 --- /dev/null +++ b/YASI_12/ds.binaryheap.test.h @@ -0,0 +1,418 @@ +#pragma once + +#if YASI_TEST_THIS_MODULE != 1 +#define YASI_TEST_THIS_MODULE 1 +#endif +#include "ds.binaryheap.h" + +namespace yasi{ + namespace ds{ + + // test the BinaryHeap class + class BinaryHeapTest : public yasi::Test{ + protected: + typedef BinaryHeap::node_t node_t; + + public: + + template > + void checkHeapElements(HeapType* pHeap, const E* pElemsArr, const int numElems){ + return ArrayBinaryTreeTest::checkElements(&pHeap->bt, pElemsArr, numElems); + } + + void heapify(){ + const int heapSize = 5; + int arr[] = { 10, 5, 20, 15, 25 }; + int n = ARR_LENGTH(arr); + BinaryHeap h; + bool ok = h.heapify(arr, n); + ASSERT_EQ(true, ok) << "heapify failed"; + + // assuming min-heap + { + SCOPED_TRACE("heapify #1"); + int newArr[] = { 5, 10, 20, 15, 25 }; + checkHeapElements(&h, newArr, heapSize); + } + + ok = h.heapify(arr, -1); + ASSERT_EQ(false, ok) << "heapify succeeded with negative size"; + + ok = h.heapify(NULL, 4); + ASSERT_EQ(false, ok) << "heapify succeeded with NULL array"; + + } + + void top(){ + int e; + bool ok = true; + BinaryHeap h; + + h.insert(15); + h.insert(5); + h.insert(25); + h.insert(10); + h.insert(20); + + // assuming min-heap + ASSERT_EQ(5, h.size()) << "heap size should have been 5"; + e = h.top(); + ASSERT_EQ(5, e) << "top should have been 5"; + e = h.top(); + ASSERT_EQ(5, e) << "top should still have been 5"; + h.pop(); // pop 5 + e = h.top(); + ASSERT_EQ(10, e) << "top should still have been 10"; + h.pop(); // pop 10 + e = h.top(); + ASSERT_EQ(15, e) << "top should have been 15"; + h.pop(); // pop 15 + e = h.top(); + ASSERT_EQ(20, e) << "top should have been 20"; + h.pop(); // pop 20 + e = h.top(); + ASSERT_EQ(25, e) << "top should have been 25"; + h.pop(); // pop 25 + ASSERT_EQ(0, h.size()) << "heap size should have been 0"; + + + } + + void bubbleUp(){ + const int heapSize = 6; + int arr[] = { 5, 10, 15, 2, 30, 7 }; // 2 (child of 10) and 7 (child of 15), violate heap property + int n = ARR_LENGTH(arr); + BinaryHeap h; + h.setTree(arr, n); + // now the binary tree has heap-property violations + + node_t* pNode = h.bt.nodeAt(4); // 2 + h.bubbleUp(pNode); + // arr = {2, 5, 15, 10, 30, 7} + { + SCOPED_TRACE("bubbleUp(2)"); + int newArr[] = { 2, 5, 15, 10, 30, 7 }; + checkHeapElements(&h, newArr, heapSize); + } + + pNode = h.bt.nodeAt(6); // 7 + h.bubbleUp(pNode); // 7 should stop as a child of 2 + // arr = {2, 5, 7, 10, 30, 15} + { + SCOPED_TRACE("bubbleUp(7)"); + int newArr[] = { 2, 5, 7, 10, 30, 15 }; + checkHeapElements(&h, newArr, heapSize); + } + } + + void selectChildForBubbleDown(){ + BinaryHeap h; + // case: bubbleDown along right child + int arr[] = { 10, 20, 30 }; // 35 (parent of 100 and 15) and 15 (parent of 7) violate heap property + h.setTree(arr, 3); + node_t* pNode = h.selectChildForBubbleDown(h.bt.root()); // should be NULL + ASSERT_EQ(0, (int)pNode) << "should not bubble down"; + + h.clear(); + int arr2[] = { 10, 5, 8 }; + h.setTree(arr2, 3); + pNode = h.selectChildForBubbleDown(h.bt.root()); // should be 5 + ASSERT_EQ(5, pNode->element) << "should be 5"; + + h.clear(); + int arr3[] = { 10, 15, 8 }; + h.setTree(arr3, 3); + pNode = h.selectChildForBubbleDown(h.bt.root()); // should be 8 + ASSERT_EQ(8, pNode->element) << "should be 8"; + + h.clear(); + int arr4[] = { 5, 10, 10 }; + h.setTree(arr4, 3); + pNode = h.selectChildForBubbleDown(h.bt.root()); // should be right child of root + ASSERT_EQ(0, (int)pNode) << "should not bubble down"; + + h.clear(); + int arr5[] = { 10, 10, 10 }; + h.setTree(arr5, 3); + pNode = h.selectChildForBubbleDown(h.bt.root()); // should not bubble down + ASSERT_EQ(0, (int)pNode) << "should not bubble down when all equal"; + } + + void bubbleDown(){ + const int heapSize = 6; + // case: bubbleDown along right child + int arr[] = { 35, 100, 15, 50, 30, 7 }; // 35 (parent of 100 and 15) and 15 (parent of 7) violate heap property + int n = ARR_LENGTH(arr); + BinaryHeap h; + h.setTree(arr, n); + // now the binary tree has heap-property violations + + node_t* pNode = h.bt.root(); // 35 + h.bubbleDown(pNode); + // arr={15, 100, 7, 50, 30, 35} + { + SCOPED_TRACE("bubbleDown(35)"); + int newArr[] = { 15, 100, 7, 50, 30, 35 }; + checkHeapElements(&h, newArr, heapSize); + } + + h.bubbleDown(h.bt.root()); // 15 + // arr={7, 100, 15, 50, 30, 35} + { + SCOPED_TRACE("bubbleDown(15)"); + int newArr[] = { 7, 100, 15, 50, 30, 35 }; + checkHeapElements(&h, newArr, heapSize); + } + + h.bubbleDown(h.bt.nodeAt(4)); // no effect: external + // arr={7, 100, 15, 50, 30, 35} + { + SCOPED_TRACE("bubbleDown(50)"); + int newArr[] = { 7, 100, 15, 50, 30, 35 }; + checkHeapElements(&h, newArr, heapSize); + } + + // case: bubbleDown along left child + int arr2[] = { 35, 15, 100, 50, 30, 7 }; // 35 (parent of 100 and 15) and 100 (parent of 7) violate heap property + n = ARR_LENGTH(arr2); + BinaryHeap h2; + h2.setTree(arr2, n); + // now the binary tree has heap-property violations + + pNode = h2.bt.root(); // 35 + h2.bubbleDown(pNode); + // arr={15, 30, 100, 50, 35, 7} + { + SCOPED_TRACE("bubbleDown(35)"); + int newArr[] = { 15, 30, 100, 50, 35, 7 }; + checkHeapElements(&h2, newArr, heapSize); + } + } + + void insert(){ + BinaryHeap h; + + // root + h.insert(5); + // arr={5} + { + SCOPED_TRACE("insert(5)"); + int newArr[] = { 5 }; + checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); + } + + // add a large element, should not bubble up + h.insert(10); + // arr={5, 10} + { + SCOPED_TRACE("insert(10)"); + int newArr[] = { 5, 10 }; + checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); + } + + // add a small element, should bubble up + h.insert(3); + // arr = {3, 10, 5} + { + SCOPED_TRACE("insert(3)"); + int newArr[] = { 3, 10, 5 }; + checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); + } + + // add another small element, should bubble up + h.insert(1); + // arr = {1, 3, 5, 10} + { + SCOPED_TRACE("insert(1)"); + int newArr[] = { 1, 3, 5, 10 }; + checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); + } + + h.insert(2); + // arr = {1, 2, 5, 10, 3} + { + SCOPED_TRACE("insert(2)"); + int newArr[] = { 1, 2, 5, 10, 3 }; + checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); + } + + } + + void pop(){ + const int heapSize = 6; + int arr[] = { 5, 10, 15, 20, 25, 30 }; // valid heap + int n = ARR_LENGTH(arr); + BinaryHeap h; + h.setTree(arr, n); // valid heap + int e; + + e = h.top(); // e = 5 + h.pop(); + ASSERT_EQ(5, e) << "top elem should be 5"; + // arr={10, 20, 15, 30, 25} + { + SCOPED_TRACE("pop #1"); + int newArr[] = { 10, 20, 15, 30, 25 }; + checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); + } + + e = h.top(); // e = 10 + h.pop(); + ASSERT_EQ(10, e) << "top elem should be 10"; + // arr={15, 20, 25, 30} + { + SCOPED_TRACE("pop #2"); + int newArr[] = { 15, 20, 25, 30 }; + checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); + } + + e = h.top(); // e = 15 + h.pop(); + ASSERT_EQ(15, e) << "top elem should be 15"; + // arr={20, 30, 25} + { + SCOPED_TRACE("pop #3"); + int newArr[] = { 20, 30, 25 }; + checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); + } + + e = h.top(); // e = 20 + h.pop(); + ASSERT_EQ(20, e) << "top elem should be 20"; + // arr={25, 30} + { + SCOPED_TRACE("pop #4"); + int newArr[] = { 25, 30 }; + checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); + } + + e = h.top(); // e = 25 + h.pop(); + ASSERT_EQ(25, e) << "top elem should be 25"; + // arr={30} + { + SCOPED_TRACE("pop #5"); + int newArr[] = { 30 }; + checkHeapElements(&h, newArr, ARR_LENGTH(newArr)); + } + + e = h.top(); // e = 30 + h.pop(); + ASSERT_EQ(30, e) << "top elem should be 30"; + // arr={} + ASSERT_EQ(true, h.empty()) << "heap should have been empty"; + + } + + void maxHeap(){ + const int heapSize = 5; + int arr[] = { 10, 5, 20, 15, 25 }; + int n = ARR_LENGTH(arr); + typedef BinaryHeap > HeapType; + HeapType h; + bool ok = h.heapify(arr, n); + ASSERT_EQ(true, ok) << "heapify failed"; + + // should be max-heap + { + /* heap: + 25 + 20 10 + 5 15 + */ + SCOPED_TRACE("max-heap #1"); + //int newArr[] = { 25, 20, 10, 5, 15 }; + //checkHeapElements(&h, newArr, heapSize); + string actual = strPurge(h.toStringBFS(), "| "); + ASSERT_EQ("252010515", actual) << "bad max heap from heapify"; + } + + // add some more items + { + h.push(12); + h.push(30); + h.push(3); + h.push(40); + /* heap: + 40 + 30 25 + 20 15 10 12 + 3 5 + */ + SCOPED_TRACE("max-heap #2"); + string actual = strPurge(h.toStringBFS(), "| "); + ASSERT_EQ("4030252015101235", actual) << "bad max heap after add"; + } + + + } + + // compare a heap made of numeric strings, + // and the comparison will be done after turning them into numbers + // creates a max heap with predicate NumericStringMaxHeapPredicate + void customComparatorHeap(){ + const int heapSize = 5; + typedef string HeapElement; + HeapElement srcArr[] = { + HeapElement("10"), + HeapElement("5"), + HeapElement("20"), + HeapElement("15"), + HeapElement("25") + }; + int n = ARR_LENGTH(srcArr); + // max heap with binary trees as elements + typedef BinaryHeap HeapType; + HeapType h; + bool ok = h.heapify(srcArr, n); + ASSERT_EQ(true, ok) << "heapify failed"; + // should be max-heap + { + /* heap: + 25 + 20 10 + 5 15 + */ + SCOPED_TRACE("max-heap #1"); + string actual = strPurge(h.toStringBFS(), "| "); + ASSERT_EQ("252010515", actual) << "bad max heap from heapify"; + } + + // add some more items + { + h.push("12"); + h.push("30"); + h.push("3"); + h.push("40"); + /* heap: + 40 + 30 25 + 20 15 10 12 + 3 5 + */ + SCOPED_TRACE("max-heap #2"); + string actual = strPurge(h.toStringBFS(), "| "); + ASSERT_EQ("4030252015101235", actual) << "bad max heap after add"; + } + + + } + + }; + + + ADD_TEST_F(BinaryHeapTest, heapify); + ADD_TEST_F(BinaryHeapTest, top); + ADD_TEST_F(BinaryHeapTest, pop); + ADD_TEST_F(BinaryHeapTest, insert); + ADD_TEST_F(BinaryHeapTest, bubbleUp); + ADD_TEST_F(BinaryHeapTest, selectChildForBubbleDown); + ADD_TEST_F(BinaryHeapTest, bubbleDown); + ADD_TEST_F(BinaryHeapTest, maxHeap); + ADD_TEST_F(BinaryHeapTest, customComparatorHeap); + + + + + } +} \ No newline at end of file diff --git a/YASI_12/ds.mutableheap.h b/YASI_12/ds.mutableheap.h index 3c9342d..a20f48b 100644 --- a/YASI_12/ds.mutableheap.h +++ b/YASI_12/ds.mutableheap.h @@ -1,17 +1,22 @@ #pragma once #include "ds.binaryheap.h" -#include "gtest\gtest.h" -#include "ds.kvpair.h" -#include "utils.h" + +// enable-disable testing classes in this file +#include "test.this.module.h" namespace yasi{ namespace ds{ using namespace std; + + + ////////////////////////////////////////////// + //////////////// Mutable Heap //////////////// + ////////////////////////////////////////////// template - class MutableHeap : public BinaryHeap < KVPair > { + class MutableHeap : public BinaryHeap < KVPair > { ////////// enable testing /////////// - friend class MutableHeapTest; + FRIEND_TEST_CLASS(MutableHeapTest); typedef KVPair HeapElement; typedef BinaryHeap Heap; typedef typename Heap::HeapNode Node; @@ -27,12 +32,12 @@ namespace yasi{ // need update if (newElem < pNode->element){ // need bubble-up - ((HeapElement*) & pNode->element)->key = newKey; // updated + ((HeapElement*)& pNode->element)->key = newKey; // updated bubbleUp(pNode); } else{ // need bubble-down - ((HeapElement*) & pNode->element)->key = newKey; // updated + ((HeapElement*)& pNode->element)->key = newKey; // updated bubbleDown(pNode); } } @@ -40,51 +45,7 @@ namespace yasi{ } }; - class MutableHeapTest : public ::testing::Test{ - typedef KVPair Pair; - typedef MutableHeap MHeap; - public: - void updateKey(){ - MHeap h; - MHeap::HeapNode* n[5]; - for (int i = 0; i < 5; i++){ - n[i] = h.insert(Pair(i)); // both key and value are i - } - - string str; - h.toString(str); // should be 0 1 2 3 4 - string strBefore = strPurge(str, "| "); - string expectedStrBefore = "01234"; - ASSERT_EQ(expectedStrBefore, strBefore) << "heap toString() mismatch"; - - // now update key 3 to 9 - h.updateKey(n[3], 9); - // heap: 0 1 2 9 4 - h.toString(str); - string strAfter = strPurge(str, "| "); - string expectedStrAfter = "01294"; - ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 3-->9"; - - // now update key 2 to -8 - h.updateKey(n[2], -8); - // heap: -8 1 0 9 4 - h.toString(str); - strAfter = strPurge(str, "| "); - expectedStrAfter = "-81094"; - ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 2-->-8"; - - // now update key 9 to -9 - h.updateKey(n[3], -9); - // heap: -9 -8 0 1 4 - h.toString(str); - strAfter = strPurge(str, "| "); - expectedStrAfter = "-9-8014"; - ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 9-->-9"; - - } - }; - ADD_TEST_F(MutableHeapTest, updateKey); } // namespace ds } // namespace yasi \ No newline at end of file diff --git a/YASI_12/ds.mutableheap.test.h b/YASI_12/ds.mutableheap.test.h new file mode 100644 index 0000000..6a2898c --- /dev/null +++ b/YASI_12/ds.mutableheap.test.h @@ -0,0 +1,57 @@ +#pragma once + +#if YASI_TEST_THIS_MODULE != 1 +#define YASI_TEST_THIS_MODULE 1 +#endif +#include "ds.mutableheap.h" + +namespace yasi{ + namespace ds{ + + + class MutableHeapTest : public yasi::Test{ + typedef KVPair Pair; + typedef MutableHeap MHeap; + public: + void updateKey(){ + MHeap h; + MHeap::HeapNode* n[5]; + for (int i = 0; i < 5; i++){ + n[i] = h.insert(Pair(i)); // both key and value are i + } + + string str = h.toStringBFS(); // should be 0 1 2 3 4 + string strBefore = strPurge(str, "| "); + string expectedStrBefore = "01234"; + ASSERT_EQ(expectedStrBefore, strBefore) << "heap toString() mismatch"; + + // now update key 3 to 9 + h.updateKey(n[3], 9); + // heap: 0 1 2 9 4 + str = h.toStringBFS(); + string strAfter = strPurge(str, "| "); + string expectedStrAfter = "01294"; + ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 3-->9"; + + // now update key 2 to -8 + h.updateKey(n[2], -8); + // heap: -8 1 0 9 4 + str = h.toStringBFS(); + strAfter = strPurge(str, "| "); + expectedStrAfter = "-81094"; + ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 2-->-8"; + + // now update key 9 to -9 + h.updateKey(n[3], -9); + // heap: -9 -8 0 1 4 + str = h.toStringBFS(); + strAfter = strPurge(str, "| "); + expectedStrAfter = "-9-8014"; + ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 9-->-9"; + + } + }; + + ADD_TEST_F(MutableHeapTest, updateKey); + } +} \ No newline at end of file diff --git a/YASI_12/ds.mutablepriorityqueue.h b/YASI_12/ds.mutablepriorityqueue.h new file mode 100644 index 0000000..075c436 --- /dev/null +++ b/YASI_12/ds.mutablepriorityqueue.h @@ -0,0 +1,104 @@ +#pragma once +#include "ds.priorityqueue.h" +#include "ds.BSTDictionary.h" // for mutable priority queue + +// enable-disable testing classes in this file +#include "test.this.module.h" + +using namespace std; + +namespace yasi{ + namespace ds{ + + + /////////////////////////////////// + ////// mutable priority queue ///// + /////////////////////////////////// + template + class MutablePriorityQueue { + /////////// enable testing //////////// + FRIEND_TEST_CLASS( MutablePriorityQueueTest); + + typedef MutableHeap < Key, Value > HeapType; + typedef KVPair Pair; + public: + typedef typename HeapType::HeapNode Node; + + protected: + // value-to-heapnode lookup + typedef Node* DictValue; + typedef Value DictKey; + typedef BSTDictionary Dict; + Dict d; + + // the internal priority queue + PriorityQueue < Pair, HeapType > pq; + protected: + DictValue findNode(const Value& v) const { + DictValue* pValue = d.find(v); // d.find() returns a ptr to value, and NULL if not found + return pValue ? *pValue : NULL; + } + + public: + typedef typename HeapType::HeapNode Node; + + MutablePriorityQueue(){ } + virtual ~MutablePriorityQueue(){ pq.clear(); } + + // modify existing priority queue methods to support key update + // input arg kv is an instance of the KVPair class + void push(const Key& k, const Value& v) { + insert(kv.key, kv.value); + } + void pop() { + if (!empty()){ + removeTop(); + } + } + + // on empty queue, behavior undefined + Value removeTop() { + Pair kv; + if (!empty()){ + kv = (Pair)pq.top(); + + // remove the element from dictionary + d.remove(kv.value); + + // now pop from heap + pq.pop(); + + } + // done + return kv.value; + } + + // undefined on empty queue + const Value& top() const { return pq.top(); } + int size() const { return pq.size(); } + bool empty() const { return pq.empty(); } + string toStringBFS(){ return pq.toStringBFS(); } + + + // new methods on top of PriorityQueue + Node* insert(const Key& k, const Value& v) { + Node* pNode = pq.heap().insert(Pair(k, v)); + // add the node to dictionary + // with key = kv.value + d.insert(v, pNode); + return pNode; + } + Node* insert(const Key& k) { return insert(k, k); } + //Node* insert(const Pair& e) { return h.insert(e); } + + // update the key in a HeapNode pointer + void updateKey(Node* pNode, const Key newKey){ if (pNode) pq.heap().updateKey(pNode, newKey); } + // update the key of a value; if values are not unique, behavior is undefined + void updateKey(const Value& v, const Key newKey){ + Node* pNode = findNode(v); + if (pNode) updateKey(pNode, newKey); + } + }; + + } +} \ No newline at end of file diff --git a/YASI_12/ds.mutablepriorityqueue.test.h b/YASI_12/ds.mutablepriorityqueue.test.h new file mode 100644 index 0000000..388b45a --- /dev/null +++ b/YASI_12/ds.mutablepriorityqueue.test.h @@ -0,0 +1,84 @@ +#pragma once + +#if YASI_TEST_THIS_MODULE != 1 +#define YASI_TEST_THIS_MODULE 1 +#endif +#include "ds.mutablepriorityqueue.h" + +namespace yasi{ + namespace ds{ + + + class MutablePriorityQueueTest : public yasi::Test{ + typedef MutablePriorityQueue MPQ; + typedef MPQ::Node Node; + public: + void dictionary(){ + // insert key-values and check the dictionary + MPQ pq; + Node* n[5]; + for (int i = 0; i < 5; i++){ + n[i] = pq.insert(i, i * 10); // key i, value i*10 + } + ASSERT_EQ(pq.size(), pq.d.size()) << "dictionary and pq size not same"; + + // now check dictionary + string strDictBfs = pq.d.toStringBFS(); + string strDictPreorder = pq.d.toStringPreOrder(); + for (int i = 0; i < 5; i++){ + // lookup node by value + Node* pNode = pq.findNode(i * 10); + ASSERT_NE(0, (int)pNode) << "pq node NULL"; + ASSERT_EQ(pNode, n[i]) << "dictionary entry mismatch"; + } + + // remove a node + int topValue = pq.removeTop(); + ASSERT_EQ(0, (int)pq.findNode(topValue)) << "removed node still in dictionary"; + ASSERT_EQ(pq.size(), pq.d.size()) << "dictionary and pq size not same"; + + } + void updateKey(){ + MPQ pq; + MPQ::Node* n[5]; + for (int i = 0; i < 5; i++){ + n[i] = pq.insert(i); // both key and value are i + } + + string str; + str = pq.toStringBFS(); // should be 0 1 2 3 4 + string strBefore = strPurge(str, "| "); + string expectedStrBefore = "01234"; + ASSERT_EQ(expectedStrBefore, strBefore) << "heap toString() mismatch"; + + // now update key 3 to 9 + pq.updateKey(3, 9); // testing updateKey(value, key) method + // heap: 0 1 2 9 4 + str = pq.toStringBFS(); + string strAfter = strPurge(str, "| "); + string expectedStrAfter = "01294"; + ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 3-->9"; + + // now update key 2 to -8 + pq.updateKey(n[2], -8); // testing updateKey(node, key) method + // heap: -8 1 0 9 4 + str = pq.toStringBFS(); + strAfter = strPurge(str, "| "); + expectedStrAfter = "-81094"; + ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 2-->-8"; + + // now update key 9 (which has value 3) to -9 + pq.updateKey(3, -9); // testing updateKey(value, key) method + // heap: -9 -8 0 1 4 + str = pq.toStringBFS(); + strAfter = strPurge(str, "| "); + expectedStrAfter = "-9-8014"; + ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 9-->-9"; + + } + }; + + ADD_TEST_F(MutablePriorityQueueTest, dictionary); + ADD_TEST_F(MutablePriorityQueueTest, updateKey); + } +} \ No newline at end of file diff --git a/YASI_12/ds.priorityqueue.h b/YASI_12/ds.priorityqueue.h index 0618db2..42a0749 100644 --- a/YASI_12/ds.priorityqueue.h +++ b/YASI_12/ds.priorityqueue.h @@ -1,13 +1,14 @@ #pragma once #include "common.h" -#include "gtest\gtest.h" #include "utils.h" #include "ds.list.h" #include "ds.binaryheap.h" #include "ds.aux.hastree.h" -#include "ds.BSTDictionary.h" // for mutable priority queue #include +// enable-disable testing classes in this file +#include "test.this.module.h" + using namespace std; namespace yasi{ @@ -30,7 +31,7 @@ class IPriorityQueue { template > class PriorityQueue : public virtual IPriorityQueue < E >, public ds::aux::HasTree { /////////// enable testing //////////// - friend class PriorityQueueTest; + FRIEND_TEST_CLASS( PriorityQueueTest); protected: Heap h; @@ -56,275 +57,6 @@ class PriorityQueue : public virtual IPriorityQueue < E >, public ds::aux::HasTr }; - class PriorityQueueTest :public yasi::Test{ - typedef PriorityQueue pq_t; - public: - void all(){ - //PriorityQueue< stack > pqq; - int t; - pq_t pq; - - ASSERT_EQ(0, pq.size()) << "size not zero"; - ASSERT_EQ(true, pq.empty()) << "pq not empty"; - - pq.push(t = 5); - pq.push(t = 2); - pq.push(t = 10); - pq.push(t = 8); - pq.push(t = 5); - pq.push(t = 3); - - ASSERT_EQ(6, pq.size()) << "size not 6"; - ASSERT_EQ(false, pq.empty()) << "pq empty"; - ASSERT_EQ(2, pq.top()) << "top not 2"; - - pq.pop(); - ASSERT_EQ(5, pq.size()) << "size not 5"; - ASSERT_EQ(3, pq.top()) << "top not 3"; - - pq.pop(); - ASSERT_EQ(4, pq.size()) << "size not 4"; - ASSERT_EQ(5, pq.top()) << "top not 5"; - - pq.pop(); - ASSERT_EQ(3, pq.size()) << "size not 3"; - ASSERT_EQ(5, pq.top()) << "top not 5"; - - pq.push(7); - pq.push(13); - ASSERT_EQ(5, pq.size()) << "size not 5"; - ASSERT_EQ(5, pq.top()) << "top not 5"; - - pq.pop(); - ASSERT_EQ(4, pq.size()) << "size not 4"; - ASSERT_EQ(7, pq.top()) << "top not 7"; - - pq.pop(); - ASSERT_EQ(3, pq.size()) << "size not 3"; - ASSERT_EQ(8, pq.top()) << "top not 8"; - - pq.pop(); - ASSERT_EQ(2, pq.size()) << "size not 2"; - ASSERT_EQ(10, pq.top()) << "top not 10"; - - pq.pop(); - ASSERT_EQ(1, pq.size()) << "size not 1"; - ASSERT_EQ(13, pq.top()) << "top not 13"; - - pq.pop(); - ASSERT_EQ(0, pq.size()) << "size not 0"; - ASSERT_EQ(true, pq.empty()) << "pq not empty"; - } - - void maxPriorityQueue(){ - // pq of numeric string, max-pq - PriorityQueue > pq; - - pq.push("10"); - pq.push("5"); - pq.push("20"); - pq.push("15"); - pq.push("25"); - { - /* heap: - 25 - 20 10 - 5 15 - */ - SCOPED_TRACE("max-pq #1"); - string actual = strPurge(pq.toStringBFS(), "| "); - ASSERT_EQ("252010515", actual) << "bad max pq"; - } - // add some more items - { - pq.push("12"); - pq.push("30"); - pq.push("3"); - pq.push("40"); - /* pq: - 40 - 30 25 - 20 15 10 12 - 3 5 - */ - SCOPED_TRACE("max-pq #2"); - string actual = strPurge(pq.toStringBFS(), "| "); - ASSERT_EQ("4030252015101235", actual) << "bad max pq after add"; - } - // now check by popping - int actual[9]; - for (int i = 0; !pq.empty(); i++){ - actual[i] = atoi(pq.removeTop().c_str()); - } - const int expected[] = {40, 30, 25, 20, 15, 12, 10, 5, 3}; - ASSERT_EQ(true, arrcmp(actual, expected, ARR_LENGTH(expected))) << "wrong pop sequence from max heap"; - } - }; - - ADD_TEST_F(PriorityQueueTest, all); - ADD_TEST_F(PriorityQueueTest, maxPriorityQueue); - - -/////////////////////////////////// -////// mutable priority queue ///// -/////////////////////////////////// -template -class MutablePriorityQueue { - /////////// enable testing //////////// - friend class MutablePriorityQueueTest; - - typedef MutableHeap < Key, Value > HeapType; - typedef KVPair Pair; -public: - typedef typename HeapType::HeapNode Node; - -protected: - // value-to-heapnode lookup - typedef Node* DictValue; - typedef Value DictKey; - typedef BSTDictionary Dict; - Dict d; - - // the internal priority queue - PriorityQueue < Pair, HeapType > pq; -protected: - DictValue findNode(const Value& v) const { - DictValue* pValue = d.find(v); // d.find() returns a ptr to value, and NULL if not found - return pValue ? *pValue : NULL; - } - -public: - typedef typename HeapType::HeapNode Node; - - MutablePriorityQueue(){ } - virtual ~MutablePriorityQueue(){ pq.clear(); } - - // modify existing priority queue methods to support key update - // input arg kv is an instance of the KVPair class - void push(const Key& k, const Value& v) { - insert(kv.key, kv.value); - } - void pop() { - if (!empty()){ - removeTop(); - } - } - - // on empty queue, behavior undefined - Value removeTop() { - Pair kv; - if (!empty()){ - kv = (Pair)pq.top(); - - // remove the element from dictionary - d.remove(kv.value); - - // now pop from heap - pq.pop(); - - } - // done - return kv.value; - } - - // undefined on empty queue - const Value& top() const { return pq.top(); } - int size() const { return pq.size(); } - bool empty() const { return pq.empty(); } - string toStringBFS(){ return pq.toStringBFS(); } - - - // new methods on top of PriorityQueue - Node* insert(const Key& k, const Value& v) { - Node* pNode = pq.heap().insert(Pair(k, v)); - // add the node to dictionary - // with key = kv.value - d.insert(v, pNode); - return pNode; - } - Node* insert(const Key& k) { return insert(k, k); } - //Node* insert(const Pair& e) { return h.insert(e); } - - // update the key in a HeapNode pointer - void updateKey(Node* pNode, const Key newKey){ if(pNode) pq.heap().updateKey(pNode, newKey); } - // update the key of a value; if values are not unique, behavior is undefined - void updateKey(const Value& v, const Key newKey){ - Node* pNode = findNode(v); - if(pNode) updateKey(pNode, newKey); - } -}; - -class MutablePriorityQueueTest : public yasi::Test{ - typedef MutablePriorityQueue MPQ; - typedef MPQ::Node Node; -public: - void dictionary(){ - // insert key-values and check the dictionary - MPQ pq; - Node* n[5]; - for (int i = 0; i < 5; i++){ - n[i] = pq.insert(i, i*10); // key i, value i*10 - } - ASSERT_EQ(pq.size(), pq.d.size()) << "dictionary and pq size not same"; - - // now check dictionary - string strDictBfs = pq.d.toStringBFS(); - string strDictPreorder = pq.d.toStringPreOrder(); - for (int i = 0; i < 5; i++){ - // lookup node by value - Node* pNode = pq.findNode(i*10); - ASSERT_NE(0, (int)pNode) << "pq node NULL"; - ASSERT_EQ(pNode, n[i]) << "dictionary entry mismatch"; - } - - // remove a node - int topValue = pq.removeTop(); - ASSERT_EQ(0, (int) pq.findNode(topValue)) << "removed node still in dictionary"; - ASSERT_EQ(pq.size(), pq.d.size()) << "dictionary and pq size not same"; - - } - void updateKey(){ - MPQ pq; - MPQ::Node* n[5]; - for (int i = 0; i < 5; i++){ - n[i] = pq.insert(i); // both key and value are i - } - - string str; - str = pq.toStringBFS(); // should be 0 1 2 3 4 - string strBefore = strPurge(str, "| "); - string expectedStrBefore = "01234"; - ASSERT_EQ(expectedStrBefore, strBefore) << "heap toString() mismatch"; - - // now update key 3 to 9 - pq.updateKey(3, 9); // testing updateKey(value, key) method - // heap: 0 1 2 9 4 - str = pq.toStringBFS(); - string strAfter = strPurge(str, "| "); - string expectedStrAfter = "01294"; - ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 3-->9"; - - // now update key 2 to -8 - pq.updateKey(n[2], -8); // testing updateKey(node, key) method - // heap: -8 1 0 9 4 - str = pq.toStringBFS(); - strAfter = strPurge(str, "| "); - expectedStrAfter = "-81094"; - ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 2-->-8"; - - // now update key 9 (which has value 3) to -9 - pq.updateKey(3, -9); // testing updateKey(value, key) method - // heap: -9 -8 0 1 4 - str = pq.toStringBFS(); - strAfter = strPurge(str, "| "); - expectedStrAfter = "-9-8014"; - ASSERT_EQ(expectedStrAfter, strAfter) << "bad heap after update 9-->-9"; - - } -}; - -ADD_TEST_F(MutablePriorityQueueTest, dictionary); -ADD_TEST_F(MutablePriorityQueueTest, updateKey); } // namespace ds diff --git a/YASI_12/ds.priorityqueue.test.h b/YASI_12/ds.priorityqueue.test.h new file mode 100644 index 0000000..3ff495c --- /dev/null +++ b/YASI_12/ds.priorityqueue.test.h @@ -0,0 +1,119 @@ +#pragma once + +#if YASI_TEST_THIS_MODULE != 1 +#define YASI_TEST_THIS_MODULE 1 +#endif +#include "ds.priorityqueue.h" + +namespace yasi{ + namespace ds{ + + class PriorityQueueTest :public yasi::Test{ + typedef PriorityQueue pq_t; + public: + void all(){ + //PriorityQueue< stack > pqq; + int t; + pq_t pq; + + ASSERT_EQ(0, pq.size()) << "size not zero"; + ASSERT_EQ(true, pq.empty()) << "pq not empty"; + + pq.push(t = 5); + pq.push(t = 2); + pq.push(t = 10); + pq.push(t = 8); + pq.push(t = 5); + pq.push(t = 3); + + ASSERT_EQ(6, pq.size()) << "size not 6"; + ASSERT_EQ(false, pq.empty()) << "pq empty"; + ASSERT_EQ(2, pq.top()) << "top not 2"; + + pq.pop(); + ASSERT_EQ(5, pq.size()) << "size not 5"; + ASSERT_EQ(3, pq.top()) << "top not 3"; + + pq.pop(); + ASSERT_EQ(4, pq.size()) << "size not 4"; + ASSERT_EQ(5, pq.top()) << "top not 5"; + + pq.pop(); + ASSERT_EQ(3, pq.size()) << "size not 3"; + ASSERT_EQ(5, pq.top()) << "top not 5"; + + pq.push(7); + pq.push(13); + ASSERT_EQ(5, pq.size()) << "size not 5"; + ASSERT_EQ(5, pq.top()) << "top not 5"; + + pq.pop(); + ASSERT_EQ(4, pq.size()) << "size not 4"; + ASSERT_EQ(7, pq.top()) << "top not 7"; + + pq.pop(); + ASSERT_EQ(3, pq.size()) << "size not 3"; + ASSERT_EQ(8, pq.top()) << "top not 8"; + + pq.pop(); + ASSERT_EQ(2, pq.size()) << "size not 2"; + ASSERT_EQ(10, pq.top()) << "top not 10"; + + pq.pop(); + ASSERT_EQ(1, pq.size()) << "size not 1"; + ASSERT_EQ(13, pq.top()) << "top not 13"; + + pq.pop(); + ASSERT_EQ(0, pq.size()) << "size not 0"; + ASSERT_EQ(true, pq.empty()) << "pq not empty"; + } + + void maxPriorityQueue(){ + // pq of numeric string, max-pq + PriorityQueue > pq; + + pq.push("10"); + pq.push("5"); + pq.push("20"); + pq.push("15"); + pq.push("25"); + { + /* heap: + 25 + 20 10 + 5 15 + */ + SCOPED_TRACE("max-pq #1"); + string actual = strPurge(pq.toStringBFS(), "| "); + ASSERT_EQ("252010515", actual) << "bad max pq"; + } + // add some more items + { + pq.push("12"); + pq.push("30"); + pq.push("3"); + pq.push("40"); + /* pq: + 40 + 30 25 + 20 15 10 12 + 3 5 + */ + SCOPED_TRACE("max-pq #2"); + string actual = strPurge(pq.toStringBFS(), "| "); + ASSERT_EQ("4030252015101235", actual) << "bad max pq after add"; + } + // now check by popping + int actual[9]; + for (int i = 0; !pq.empty(); i++){ + actual[i] = atoi(pq.removeTop().c_str()); + } + const int expected[] = { 40, 30, 25, 20, 15, 12, 10, 5, 3 }; + ASSERT_EQ(true, arrcmp(actual, expected, ARR_LENGTH(expected))) << "wrong pop sequence from max heap"; + } + }; + + ADD_TEST_F(PriorityQueueTest, all); + ADD_TEST_F(PriorityQueueTest, maxPriorityQueue); + } +} \ No newline at end of file diff --git a/YASI_12/main.cpp b/YASI_12/main.cpp index ac4a420..cb3186a 100644 --- a/YASI_12/main.cpp +++ b/YASI_12/main.cpp @@ -1,8 +1,6 @@ #include "common.h" -//#include "ds.arraybinarytree.h" //#include "ds.binaryheap.h" -//#include "ds.binarytree.h" //#include "ds.binarysearchtree.h" //#include "ds.priorityqueue.h" //#include "ds.BSTDictionary.h" @@ -31,6 +29,10 @@ using namespace std; #include "ds.doublylinkedlist.test.h" #include "ds.binarytree.test.h" #include "ds.arraybinarytree.test.h" +#include "ds.binaryheap.test.h" +#include "ds.mutableheap.test.h" +#include "ds.priorityqueue.test.h" +#include "ds.mutablepriorityqueue.test.h" int testAll(int* argc, char** argv){