Guest User

Untitled

a guest
Oct 21st, 2017
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.81 KB | None | 0 0
  1. /*
  2. * assign4_test.cc
  3. * Assignment 4 (BST) test runner.
  4. */
  5. #include <algorithm>
  6. #include <cassert>
  7. #include <iostream>
  8. #include <random>
  9. #include <set>
  10. #include <vector>
  11.  
  12. using std::cout;
  13.  
  14. std::vector<unsigned> make_random_permutation(
  15. std::size_t len,
  16. int seed = 1)
  17. {
  18. std::default_random_engine generator(seed);
  19. std::vector<unsigned> ret(len, 0);
  20.  
  21. // Initialize vector to 0...len-1
  22. for(std::size_t i = 0; i < len; ++i)
  23. ret.at(i) = i;
  24.  
  25. std::shuffle(ret.begin(), ret.end(), generator);
  26.  
  27. return ret;
  28.  
  29. }
  30.  
  31. // Node structure
  32. struct node {
  33. int key;
  34. node* left;
  35. node* right;
  36. node* parent;
  37. };
  38.  
  39. /*
  40. * User-implemented functions
  41. */
  42. void rotate(node* child, node* parent); // Rotation
  43. bool find(node*& root, int value); // Search
  44. node* insert(node* root, int value); // Insertion
  45. //node* remove(node* root, int value); // Deletion
  46. node* splay(node* t); // Splay
  47.  
  48. void rotate(node* child, node* parent){
  49. if(parent->left == child){
  50. parent->left = child->right;
  51. child->right->parent = parent;
  52. child->parent = parent->parent;
  53. if(parent == child->parent->left)
  54. child->parent->left = child;
  55. else
  56. child->parent->right = child;
  57. child->right = parent;
  58. parent->parent = child;
  59. }
  60. else{
  61. parent->right = child->left;
  62. child->left->parent = parent;
  63. child->parent = parent->parent;
  64. if(parent == child->parent->left)
  65. child->parent->left = child;
  66. else
  67. child->parent->right = child;
  68. child->left = parent;
  69. parent->parent = child;
  70. }
  71. }
  72.  
  73. node* insert(node* root, int value){
  74. return root;
  75. }
  76.  
  77. bool find(node*& root, int value){
  78. node* temp = root;
  79. if(temp == nullptr)
  80. return false;
  81. else if(temp->key == value){
  82. root = splay(temp);
  83. return true;
  84. }
  85. else if(value > temp->key)
  86. return find(temp->right, value);
  87. else
  88. return find(temp->left, value);
  89. }
  90.  
  91. node* splay(node* t){
  92. while(t->parent != nullptr){
  93. if(t->parent->parent == nullptr)
  94. rotate(t, t->parent);
  95. else{
  96. rotate(t,t->parent);
  97. rotate(t,t->parent);
  98. }
  99. }
  100. return t;
  101. }
  102. /******************************************************************************
  103. Tree structure checking
  104. ******************************************************************************/
  105.  
  106. // Balance measurement, returns a balance factor between 0 (not possible) and 1
  107. // (perfectly balanced).
  108. float balance(node* root) {
  109. if(!root)
  110. return 1.0; // Empty tree is perfectly balanced
  111. else if(!root->left) {
  112. // One subtree, on the right
  113. return 0.5 * balance(root->left);
  114. }
  115. else if(!root->right) {
  116. return 0.5 * balance(root->right);
  117. }
  118. else // Two subtrees
  119. return (balance(root->right) + balance(root->left)) / 2;
  120. }
  121.  
  122. // Safe find, that does not modify the tree structure
  123. bool safe_find(node* root, int value) {
  124. if(!root)
  125. return false;
  126. else if(root->key == value)
  127. return true;
  128. else if(value < root->key)
  129. return safe_find(root->left, value);
  130. else // value < root->key
  131. return safe_find(root->right, value);
  132. }
  133.  
  134. int count_nodes(node* root) {
  135. if(!root)
  136. return 0;
  137. else
  138. return 1 + count_nodes(root->left) + count_nodes(root->right);
  139. }
  140.  
  141. int tree_height(node* root) {
  142. if(!root)
  143. return 0;
  144. else
  145. return 1 + std::max(tree_height(root->left), tree_height(root->right));
  146. }
  147.  
  148. // Pretty-print a tree. This does cycle-checking at the same time, so that if
  149. // there's a cycle in the tree we won't get stuck in a loop.
  150. void print(node* root, int level, int parents, bool left_child, std::set<node*>& nodes) {
  151.  
  152. if(level == 0)
  153. cout << "--- Tree structure ---n";
  154.  
  155. // Print indent for node
  156. for(int i = 0; i < level-1; ++i)
  157. if(parents & (1 << i))
  158. cout << " │ ";
  159. else
  160. cout << " ";
  161.  
  162. if(level > 0)
  163. cout << (left_child ? " ├─" : " └─");
  164.  
  165. if(root == nullptr) {
  166. cout << "(null)" << std::endl;
  167. }
  168. else if(nodes.count(root) > 0) {
  169. // Already printed this node somewhere else
  170. cout << "CYCLE (" << root->key << ")" << std::endl;
  171. }
  172. else {
  173. nodes.insert(root); // Visit root
  174.  
  175. // Print children
  176. cout.width(3);
  177. cout << root->key;
  178. if(root->parent != nullptr)
  179. cout << " [p = " << root->parent->key << "]";
  180. cout << std::endl;
  181.  
  182. // Print children
  183. if(root->left || root->right) {
  184. // We only print both children if one of them is non-null.
  185. // If both are null we don't print anything, to avoid making a huge
  186. // mess.
  187.  
  188. // We print the children in the order right, left so that you can
  189. // turn your head (or your screen) to the left and the tree will
  190. // be correct.
  191. print(root->right, level+1, parents | (1 << level), true, nodes);
  192. print(root->left, level+1, parents, false, nodes);
  193. }
  194. }
  195. }
  196.  
  197. void print(node* root) {
  198. std::set<node*> nodes;
  199.  
  200. print(root, 0, 0, true, nodes);
  201. }
  202.  
  203.  
  204. /* check_for_cycles(n)
  205. Traverse the tree (preorder) starting at n, checking for cycles of nodes.
  206. Note that this does not check for parent-pointer cycles, only child-pointer
  207. cycles.
  208. */
  209. bool check_for_cycles(node* n, std::set<node*>& nodes) {
  210. if(nodes.count(n) > 0)
  211. return false;
  212. else {
  213. nodes.insert(n); // Mark n as seen
  214.  
  215. // Explore left and right subtrees
  216. bool ret = true;
  217. if(n->left)
  218. ret = ret && check_for_cycles(n->left, nodes);
  219. if(n->right)
  220. ret = ret && check_for_cycles(n->right, nodes);
  221.  
  222. return ret;
  223. }
  224. }
  225.  
  226. bool check_for_cycles(node* n) {
  227. std::set<node*> nodes;
  228.  
  229. if(!check_for_cycles(n, nodes)) {
  230. cout << "FAILED: tree structure contains a cycle.n";
  231. return false;
  232. }
  233. else
  234. return true;
  235. }
  236.  
  237. // Check the pointer structure of the tree (parent/child) to make sure it is
  238. // correct.
  239. bool check_tree_pointers(node* root, bool is_root = true) {
  240. if(!root)
  241. return true;
  242. else {
  243. if(is_root && root->parent != nullptr) {
  244. cout << "FAILED: root->parent should always be null.n";
  245. return false;
  246. }
  247.  
  248. // Child child nodes (if they exist) to make sure their parents
  249. // point back to root.
  250. if(root->left) {
  251. if(root->left->parent != root) {
  252. cout << "FAILED: found node " << root->left->key
  253. << " with incorrect parent pointer.n";
  254. return false;
  255. }
  256. if(root->left->key >= root->key) {
  257. cout << "FAILED: found node " << root->left->key
  258. << " which is on the wrong side of parent.n";
  259. return false;
  260. }
  261. }
  262.  
  263. if(root->right) {
  264. if(root->right->parent != root) {
  265. cout << "FAILED: found node " << root->right->key
  266. << " with incorrect parent pointer.n";
  267. return false;
  268. }
  269. if(root->right->key <= root->key) {
  270. cout << "FAILED: found node " << root->right->key
  271. << " which is on the wrong side of parent.n";
  272. return false;
  273. }
  274. }
  275.  
  276. if(root->right && root->left) {
  277. // Both children, if they exist, have valid parent pointers.
  278. // So now we check both subtrees recursively.
  279. return check_tree_pointers(root->left, false) &&
  280. check_tree_pointers(root->right, false);
  281. }
  282.  
  283. return true;
  284. }
  285. }
  286.  
  287. bool check_tree_values(node* root,
  288. int low = std::numeric_limits<int>::min(),
  289. int high = std::numeric_limits<int>::max()) {
  290. if(!root)
  291. return true;
  292. else if(root->key <= low) {
  293. cout << "FAILED: found node " << root->key << " improperly placed.n";
  294. return false;
  295. }
  296. else if(root->key >= high) {
  297. cout << "FAILED: found node " << root->key << " improperly placed.n";
  298. return false;
  299. }
  300. else { // root->key is in the correct range
  301. return check_tree_values(root->left, low, root->key) &&
  302. check_tree_values(root->right, root->key, high);
  303. }
  304.  
  305. }
  306.  
  307. bool check_tree(node* root) {
  308. if(root->parent != nullptr) {
  309. cout << "FAILED: Root of tree must have null parent pointer";
  310. cout << " (root->parent->key = " << root->parent->key << ")n";
  311. return false;
  312. }
  313.  
  314. return check_for_cycles(root) &&
  315. check_tree_pointers(root) &&
  316. check_tree_values(root);
  317. }
  318.  
  319. /******************************************************************************
  320. Tree testing
  321. ******************************************************************************/
  322.  
  323. template<typename Func>
  324. struct scope_exit {
  325. scope_exit(Func f) : exit(f)
  326. {}
  327.  
  328. ~scope_exit() {
  329. exit();
  330. }
  331.  
  332. Func exit;
  333. };
  334.  
  335. template<typename Func>
  336. scope_exit<Func> make_scope_exit(Func f) {
  337. return scope_exit<Func>(f);
  338. }
  339.  
  340. // To test the tree functions, we generate a random permutation of the integers
  341. // from -20 to 20 and insert them into the tree. Then, we generate another
  342. // permutation and find them in that order. Finally, we generate another
  343. // permutation and remove them in that order. After every operation, we perform
  344. // a full check of the tree structure. The test stops if the tree structure is
  345. // not valid at any point.
  346.  
  347. bool test_rotate() {
  348.  
  349. // This is a huge mess. I need to come up with a better way to test
  350. // left/right rotations. Maybe use member-pointers to abstract over
  351. // the orientation?
  352.  
  353. // Root of the pseudo-tree
  354. node* root = new node{10000, nullptr, nullptr, nullptr};
  355. /* Left-rotation tree:
  356. p
  357. /
  358. c Z
  359. /
  360. X Y
  361. */
  362. node* X = new node{-10, nullptr, nullptr, nullptr};
  363. node* Y = new node{-20, nullptr, nullptr, nullptr};
  364. node* Z = new node{-30, nullptr, nullptr, nullptr};
  365. node* child = new node{2, X, Y, nullptr};
  366. node* parent = new node{1, child, Z, root};
  367.  
  368. // This is to avoid memory leaks: the function will be called when this
  369. // function returns.
  370. auto exiter = make_scope_exit([&]() {
  371. delete X;
  372. delete Y;
  373. delete Z;
  374. delete child;
  375. delete parent;
  376. });
  377.  
  378. child->parent = parent;
  379. X->parent = Y->parent = child;
  380. Z->parent = parent;
  381.  
  382. rotate(child, parent);
  383. /* New structure should be
  384. c
  385. /
  386. X p
  387. /
  388. Y Z
  389. */
  390. if(child->parent != root) {
  391. cout << "FAILED: parent's parent is not preserved.n";
  392. return false;
  393. }
  394. if(child->right != parent) {
  395. cout << "FAILED: rotate did not make parent into child.n";
  396. return false;
  397. }
  398. if(child->left != X) {
  399. cout << "FAILED: left child of child should be unchangedn";
  400. return false;
  401.  
  402. } else if(parent->left != Y) {
  403. cout << "FAILED: child's right child should become right-child of parent.n";
  404. return false;
  405. } else if(parent->right != Z) {
  406. cout << "FAILED: right child of parent should be unchanged.n";
  407. return false;
  408. }
  409. else if(parent->parent != child) {
  410. cout << "FAILED: parent->parent is not original child.n";
  411. return false;
  412. }
  413. else if(!check_for_cycles(child)) {
  414. cout << "FAILED: rotation created a cyclen";
  415. print(child);
  416. return false;
  417. }
  418.  
  419. // Right-rotation
  420. delete child; delete parent;
  421. child = new node{2, Y, Z, nullptr};
  422. parent = new node{1, X, child, root};
  423. child->parent = parent;
  424. X->parent = parent;
  425. Y->parent = Z->parent = child;
  426. rotate(child, parent);
  427.  
  428. if(child->parent != root) {
  429. cout << "FAILED: parent's parent is not preserved.n";
  430. return false;
  431. }
  432. if(child->left != parent) {
  433. cout << "FAILED: rotate did not make parent into child.n";
  434. return false;
  435. }
  436. if(parent->left != X) {
  437. cout << "FAILED: left child of parent should be unchanged.n";
  438. return false;
  439. }
  440. else if(child->right != Z) {
  441. cout << "FAILED: right child of child should be unchanged.n";
  442. return false;
  443. }
  444. else if(parent->right != Y) {
  445. cout << "FAILED: left child of child should become right child of parentn";
  446. return false;
  447. }
  448. else if(parent->parent != child) {
  449. cout << "FAILED: parent->parent is not original child.n";
  450. return false;
  451. }
  452. else if(!check_for_cycles(child)) {
  453. cout << "FAILED: rotation created a cyclen";
  454. print(child);
  455. return false;
  456. }
  457.  
  458. // Do a quick test with null children and null root
  459. // If the user made a mistake here, this will most likely segfault.
  460. delete child;
  461. delete parent;
  462. child = new node{1, nullptr, nullptr, nullptr};
  463. parent = new node{0, child, nullptr, nullptr};
  464. child->parent = parent;
  465. rotate(child, parent);
  466. if(parent->parent != child) {
  467. cout << "FAILED: parent did not become the childn";
  468. return false;
  469. }
  470. else if(child->right != parent) {
  471. cout << "FAILED: parent did not become right childn";
  472. return false;
  473. }
  474.  
  475. return true;
  476. }
  477.  
  478. bool test_tree() {
  479. node* t = nullptr; // Empty tree
  480.  
  481. // Generate test data
  482. std::vector<unsigned> test = make_random_permutation(41, 12);
  483.  
  484. // Insert a random permutation
  485. cout << "Testing tree insertion...";
  486. for(unsigned u : test) {
  487. const int i = static_cast<int>(u);
  488. cout << u << " ";
  489.  
  490. t = insert(t, i);
  491. if(!check_tree(t)) {
  492. print(t);
  493. return false; // Stop if the check fails.
  494. }
  495.  
  496. if(t->key != i) {
  497. cout << "FAILED: After inserting " << i << " it should be splayed to the rootn";
  498. print(t);
  499. return false;
  500. }
  501.  
  502. }
  503. cout << std::endl;
  504.  
  505. int cn = count_nodes(t);
  506. if(cn != 41) {
  507. cout << "FAILED: tree does not have the correct number of nodes. ";
  508. cout << "(expected 41, found " << cn << ")n";
  509. print(t);
  510. return false;
  511. }
  512. else {
  513. cout << "OK so far...n";
  514. print(t);
  515. }
  516.  
  517. // Find a random permutation
  518. cout << "Testing tree find()...";
  519. for(unsigned u : test) {
  520. const int i = static_cast<int>(u);
  521. cout << i << " ";
  522.  
  523. if(!find(t, i)) {
  524. cout << "FAILED: find() couldn't find " << i << "n";
  525. return false;
  526. }
  527.  
  528. if(t->key != i) {
  529. cout << "FAILED: find() did not splay target to the root.n";
  530. print(t);
  531. return false;
  532. }
  533.  
  534. if(!check_tree(t)) {
  535. print(t);
  536. return false;
  537. }
  538. }
  539. cout << std::endl;
  540. print(t);
  541.  
  542. // We no longer test removal, because students are not required to implement
  543. // remove(). It's too fiddly to get right, too many edge cases.
  544. /*
  545. // Remove a random permutation
  546. cout << "Testing tree removal...n";
  547. for(unsigned u : test) {
  548. const int i = static_cast<int>(u);
  549.  
  550. t = remove(t, i);
  551.  
  552. if(!check_tree(t)) {
  553. print(t);
  554. return false;
  555. }
  556. if(safe_find(t,i)) {
  557. cout << "FAILED: removed element " << i << " is still present in the treen";
  558. print(t);
  559. return false;
  560. }
  561. }
  562.  
  563. if(t != nullptr) {
  564. cout << "FAILED: Tree not empty after removing all elements.n";
  565. print(t);
  566. return false;
  567. }
  568. */
  569.  
  570. return true;
  571. }
  572.  
  573. int main() {
  574. cout << "---- Beginning tree tests ----n";
  575. if(test_rotate() && test_tree())
  576. cout << "---- All tests successful ----n";
  577.  
  578. return 0;
  579. }
Add Comment
Please, Sign In to add comment