Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement exercise binary-search-tree #773

Merged
merged 31 commits into from
Nov 13, 2017
Merged

Implement exercise binary-search-tree #773

merged 31 commits into from
Nov 13, 2017

Conversation

rodrigocam
Copy link
Contributor

Resolved #740

@ilya-khadykin
Copy link
Contributor

You've created two PRs #773 and #768
Could you please close one to avoid confusion

inserted = True
return inserted

def search(self, searched_number):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend changing searched_number to either number or search_number, searched is in past tense which means you've already searched for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, changed!

return inserted

def search(self, searched_number):
cur_node = self.root

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add a check for if(self.root is None): return false which does an early exit if the tree hasn't been constructed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, checked!


def print_postorder(self, node):
if(node is not None):
self.print_preorder(node.left_node)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Post order should be

self.print_postorder(node.right_node) # Right comes first
self.print_postorder(node.left_node)
print(node.value)

Also you're calling print_preorder() .

found = False
while not found:
if(cur_node is None):
raise ValueError("Element not found")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You won't need to raise an exception if you do an early return false

config.json Outdated
@@ -888,9 +888,22 @@
"uuid": "6b7f7b1f-c388-4f4c-b924-84535cc5e1a0",
"slug": "hexadecimal",
"deprecated": true
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably be best to move the config.json entry for this exercise before all deprecated exercises.

Copy link
Contributor

@N-Parsons N-Parsons left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall, but there are a couple of issues that need to be resolved.

@@ -0,0 +1,52 @@
Insert and search for numbers in a binary tree.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs the title of the exercise as a heading: # Binary Search Tree

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


class BinarySearchTree(object):
def __init__(self):
pass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also include skeletons for the add and search methods here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -0,0 +1,8 @@
class TreeNode(object):
def __init__(self, value):
pass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add self.value = value here? I feel like if we assume that something exists in the tests, then we should make it clear in the solution template.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

config.json Outdated
@@ -1169,6 +1183,5 @@
}
],
"foregone": [

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add this blank line back in?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looks like you've got some unnecessary white-space here now (see below) - can you please remove it?

/ \
2 6
/ \ / \
1 3 5 7
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should also be some other stuff that goes here. Check another exercise and copy it over, or regenerate this README with the configlet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

bst = BinarySearchTree()

def test_add_integer_number1(self):
self.assertTrue(self.bst.add(7))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use assertIs(actual, True) and assertIs(actual, False) rather than assertTrue(actual) or assertFalse(actual) (#419).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

else:
cur_node.right_node = TreeNode(value)
inserted = True
return inserted
Copy link
Contributor

@N-Parsons N-Parsons Nov 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this again, I just noticed that this method is returning True/False to indicate success/failure. Under what condition is failure expected to occur? From what I can see, this code will never return False, and would actually just enter an infinite loop if value == cur_node.value. I don't think that we should use booleans in this way - exceptions are a better method for handling errors in Python, but I don't think that any exceptions should be expected to occur here.

I think it would be worth adding a BinarySearchTree.list method to this exercise that returns a sorted list of values in the tree. A collections.deque would be most efficient for this, but I don't think that the tests should enforce its use, so the tests should probably convert the actual output to a list (eg. assertEqual(list(self.bst.list()), [1, 2, 3])).

Doing this would allow us to check that values are placed in the right order - each test for adding a number should contain a second assert for the current list of stored values. We should also test duplicate values, because the README specifies a way for these to be handled.

From the README:

All data in the left subtree is less than or equal to the current node's data, and all data in the right subtree is greater than the current node's data.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@N-Parsons Returning True from an add or insert method is a common practice for container classes. I agree that it doesn't make the most sense, but that is likely why @rodrigocam did this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cmccandless is right, I thought this could be good to give more safety. I made the list method that @N-Parsons asked and change the tests to use this new method. I fix the infinite loop condition that you point but I keep the bool return, if it was a problem I can remove (:

Copy link
Contributor

@N-Parsons N-Parsons Nov 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that there's no way that False can be returned, and there is no test for this method returning False, I think it's unnecessary and likely to cause some confusion/frustration. I think it's fine for this example code to return True/False, but I don't think that it should be tested for.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! I take out the return of the method.

Copy link
Contributor

@cmccandless cmccandless left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rodrigocam Travis-CI build failed due to flake8 violations:

$ flake8
./exercises/binary-search-tree/binary_search_tree_test.py:15:46: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:15:48: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:15:50: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:15:52: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:24:48: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:24:52: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:24:56: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:24:60: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:32:46: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:32:50: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:32:54: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:40:46: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:40:48: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:40:52: E231 missing whitespace after ','
./exercises/binary-search-tree/binary_search_tree_test.py:48:1: W293 blank line contains whitespace
./exercises/binary-search-tree/example.py:3:1: E302 expected 2 blank lines, found 1
./exercises/binary-search-tree/example.py:82:30: W292 no newline at end of file
The command "flake8" failed and exited with 1 during .

bst.add(1)
bst.add(7.5)
self.assertIs(bst.search(6), False)
self.assertIs(bst.search(8.8), False)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like that search will sometimes return a bool and sometimes return a TreeNode. I think that this should either be TreeNode/None, or True/False - the former is perhaps more generally useful, since nodes are truthy and None is falsey, and returning the actual node could be useful in some instances.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! I change to return None when the node is not found.

def add(self, value):
pass

def search(self, search_number):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should use value rather than search_number as an argument, since we put values in and then search for them, and search_ is probably redundant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rodrigocam, it looks like you've updated this in example.py but not here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, done!

"binary_search_tree_test.py::BinarySearchTreeTests::test_search_valid_number1": true,
"binary_search_tree_test.py::BinarySearchTreeTests::test_search_valid_number2": true,
"binary_search_tree_test.py::BinarySearchTreeTests::test_search_valid_number3": true
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to remove the .cache directory.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@N-Parsons
Copy link
Contributor

Hi @rodrigocam, sorry for taking a while to get back to this - I've had a really busy couple of weeks!

There are a couple of minor issues remaining that need to be dealt with, and then this can be merged.

@N-Parsons N-Parsons self-assigned this Nov 12, 2017
config.json Outdated
@@ -1185,6 +1199,6 @@
}
],
"foregone": [

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rodrigocam, the extra spaces here also need to be removed. There should be a blank line, but there should be nothing in it.

@N-Parsons
Copy link
Contributor

@cmccandless, can you review this again? There are a couple of minor changes pending and then I think this will be ready to merge.

elements.append(node.value)
self.trav_inorder(node.right_node, elements)

def print_inorder(self, node):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably remove all print* methods, as they are not used by the tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@N-Parsons
Copy link
Contributor

Looks good. Thanks @rodrigocam!

@N-Parsons N-Parsons merged commit f236ea1 into exercism:master Nov 13, 2017
@cmccandless cmccandless mentioned this pull request Feb 15, 2018
77 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants