I have a binary search tree which stores objects. For inserting objects to it I am using Int value as a key. I get that value by calling method form the object like this:
public class Tree
{
// The root node of the tree which is null;
private Node root;
private double largest;
private Node insert (Node tree, Element d)
{
if (tree == null) return new Node(d);
else if (d.getPlaceInTable() < tree.data.getPlaceInTable()) tree.left = insert (tree.left, d);
else if (d.getPlaceInTable() > tree.data.getPlaceInTable()) tree.right = insert (tree.right, d);
return tree;
}
public void insert (Element d)
{
root = insert (root, d);
}
But what if I want to use Elements name as a key value which is string? How can I do it? Should I use compareTo() method? I know how to compare string1.compareTo(string2) but I really don' have any idea how I can use it in this case. If you have any suggestions, I really appreciate that.
Yes, String implements Comparable, so you can do
d.getName().compareTo(tree.data.getName()) < 0 for the left node and
d.getName().compareTo(tree.data.getName()) >= 0 for the right node
Also note, that in your original code you do not insert anything in your tree when values are equal.
Related
An implementation of a graph node is as follows (I cannot change the implementation as it is from a coding website):
class Node {
public int val;
public List<Node> neighbors;
public Node(int _val, ArrayList<Node> _neighbors) {
val = _val;
neighbors = _neighbors;
}
}
If I pass a node to my copyGraph function below, I wouldn't be able to make a copy of that node by calling the Node constructor because I get
incompatible types: List cannot be converted to ArrayList
class Solution {
public Node copyGraph(Node node) {
Node n = new Node(node.val, node.neighbors);
//do some code
}
}
How else could I make a new Node with this implementation?
Problem
That API is poorly designed, FYI. The constructor should accept a List rather than ArrayList. Ideally that code would be:
public Node ( int _val , List < Node > _neighbors ) { … }
… or perhaps even the more general Collection if order were unimportant.
public Node ( int _val , Collection < Node > _neighbors ) { … }
Workaround
Two ways to work around that poor design: cast, or copy.
If you know for sure that your List object is actually an ArrayList, cast as shown in the correct Answer by coconan.
If you are not sure of the concrete implementation of your List object, construct a new ArrayList while passing your List.
Node n = new Node ( node.val, new ArrayList < Node > ( nodesList ) );
You can cast node.neighbors to ArrayList with (ArrayList<Node>) node.neighbors
class Solution {
public Node copyGraph(Node node) {
Node n = new Node(node.val, (ArrayList<Node>) node.neighbors);
//do some code
}
}
I have a Database Table of a Tree Nodes as below. I want to make a ArrayList in Java out of these Tree Nodes. the Arraylist will recursively fetch all the Tree Nodes in a Recursive Format in Java.
Input:
Database Table
Name ID Parent_ID
Parent 1
Child-1 2 1
Child-1.1 3 2
Child-1.1.1 4 3
Child-2 5 1
Child-3 6 1
Child-1.1.1.1 7 4
Child-1.2 8 2
I want to make an ArrayList of the above table in the below Java format where Sub is list of the Child Nodes, if no Child Node then Sub is Null.
public class Node {
private String id;
private String name;
private String type;
private String value;
private List<Node> sub;
}
Output:
Parent
Child-1
Child-1.1
Child-1.1.1
Child-1.1.1.1
Child-1.2
Child-2
Child-3
Can someone please help in creating a recursive function in Java to implement the above.
Recursive function:
public void printTree(Node tree,int num)
{
if(tree==null || tree.getSub()==null)return;
for(Node n : tree.getSub())
{
System.out.println(new String(new char[num]).replace("\0", " ")+"*"+n.getName());
printTree(n,num+1);
}
}
public void callRec(Node tree)
{
System.out.println(tree.getName());
printTree(tree,1);
}
The result will be:
Parent
*Child-1
*Child-1.1
*Child-1.1.1
*Child-1.1.1.1
*Child-1.2
*Child-2
*Child-3
The problem can be solved in two steps as follows, where the notation is some Java-ish pseudocode. First, all of the database rows have to be put in a List<Node> Nodes, where Node should have an additional member ParentID and the actual tree structure has to be built. This can be done as follows in time O(n^2), which is not optimal, but makes no additional assumptions on the node indices.
for (int i = 0; i < Nodes.Count(); i++) // iterate nodes
{
for (int j = 0; j < Nodec.Count(); j++) // search parent of i-th node
{
if (Nodes[j].id.Equals(Nodes[i].ParentID)) // j-th node is parent of i-th node
{
Nodes[j].sub.add(Nodes[i]); // add i-th node to children of j-th node
}
}
}
Afterwards, the leaves can be identified easily as these are the nodes which have no children.
for (int i = 0; i < Nodes.Count(); i++)
{
if (Nodes[i].sub.Count() == 0) // i-th node is a leaf
{
// do something with a leaf
}
}
Note that I am not too familiar with Java from the top of my head, but the algorithmic idea should be understandable.
Here is a rough algo:
ArrayList<Integer> ar = new ArrayList<Integer>();
public extract(node root){
foreach(node i : root.sub)
extract(i);
ar.add(i.value);
}
For example, the BST class uses a tree structure:
public class BST<Key extends Comparable<Key>,Value> {
private Node root;
public class Node {
private int n;
private Node left;
private Node right;
private Key key;
private Value val;
}
public void put();
public Value get(Key key)
}
In this structure, nodes are connected with left and right fields and inserts and search is supported with put and get methods.
I'm interested in knowing
how are the nodes created?
why use a tree structure rather than array or some other simple structure?
The key advantage of a tree structure for searching is efficiency. It is possible to reach the node matching the key you are searching for much more quickly than iterating through an array (for example). If you have a balanced binary tree (i.e. the depth of the tree to the left and right of any node differs by no more than 1) of 1024 items then you will need step through a maximum of 10 nodes to find the key. There are special cases for arrays (such as evenly distributed values) that can be searched just as efficiently but trees are very good for a wide variety of situations which involve lots more searches than inserts.
On the other hand, inserting values into trees can be inefficient, particularly due to the need to rebalance the tree to allow efficient searching (which is their main purpose). This makes the put method relatively complicated (depending on which balancing algorithm you use).
The get method is pretty trivial:
public Value get(Key key) {
Node node = root;
while (node != null) {
int compare = key.compareTo(node.key);
if (compare > 0)
node = node.right;
else if (compare < 0)
node = node.left;
else
return node.val;
}
return null;
}
This is very well explained here and here. To summarize - this is how the nodes are created.
/**
* Inserts the key-value pair into the symbol table, overwriting the old value
* with the new value if the key is already in the symbol table.
* If the value is <tt>null</tt>, this effectively deletes the key from the symbol table.
*
* #param key the key
* #param val the value
* #throws NullPointerException if <tt>key</tt> is <tt>null</tt>
*/
public void put(Key key, Value val) {
if (val == null) {
delete(key);
return;
}
root = put(root, key, val);
assert check();
}
private Node put(Node x, Key key, Value val) {
if (x == null) return new Node(key, val, 1);
int cmp = key.compareTo(x.key);
if (cmp < 0) x.left = put(x.left, key, val);
else if (cmp > 0) x.right = put(x.right, key, val);
else x.val = val;
x.N = 1 + size(x.left) + size(x.right);
return x;
}
If the key already exists - it's replaced and if the key is new it is recursively searched till the search ends at a leaf - the leaf is then expanded with the new node. It's important to note that the final position of the node is the place where search would have ultimately found it if it were already in the tree so as to satisfy the BST properties.
Also due to properties of Binary search tree - the search operation is O(log n) or O(h) where n is number of nodes and h is height of tree.
I have the following Node Class
Class Node {
private int id;
public int getId() {
return this.id;
}
}
and then create a TreeSet with the Nodes. Next I wanted to find and return a Node object based on id matching. However, every time the findNode() function is returning the next-to-next Node not the next one. I understand it is because of calling the iterator.next() twice. How can call it only once to check with the id value as well as return the object reference. I also tried with by creating a temporary Object reference but again it was the same result.
Class NodeSet {
Set<Node> set = new TreeSet<Node>();
public Node findNode(int id) {
Iterator<Node> iterator = set.iterator();
while(iterator.hasNext()) {
if(iterator.next().getId() == id)
return iterator.next();
}
return null;
}
}
Edit: The solution proposed here is logarithmic (unlike the accepted answer) and hence is much faster when the number of nodes in a treeset is large.
There is no get method in the Set interface which the class TreeSet implements. Keeping in mind that there exists a complete ordering between the elements of a treeset, a three line hack is as follows:
Object search(TreeSet treeset, Object key) {
Object ceil = treeset.ceiling(key); // least elt >= key
Object floor = treeset.floor(key); // highest elt <= key
return ceil == floor? ceil : null;
}
Class NodeSet {
Set<Node> set = new TreeSet<Node>();
public Node findNode(int id) {
Iterator<Node> iterator = set.iterator();
while(iterator.hasNext()) {
Node node = iterator.next();
if(node.getId() == id)
return node;
}
return null;
}
}
The issue happens here:
while(iterator.hasNext()) {
if(iterator.next().getId() == id)
return iterator.next();
}
You call twice iterator.next in the same loop explaining the "next-to-next" issue.
Make a local variable to still reach the same element or better: use the for loop if you have jdk >= 5:
for(Node node: set) {
if(node.getId() == id)
return node;
}
As #JB Nizet suggests in his comment above, a simple Map already implements your code logic by essence, and thus would better fit than a TreeSet and manual check.
More precisely, a TreeMapsorted on Nodes would be relevant. (since it sounds you need the order aspect)
I use inorder to show result of search name which store in binary search tree but when i run it example i have: Employee name "abc" and "ab" and i input name ="abc" it show 2 of them.Anyone can help me what is my fault :( ty
public void searchFull(String name) {
EmployeeSLLNode p = root;
n=0;
if (p != null) {
inorder(p.left);
if(p.info.getFullname().equals(name)) {
n++;
System.out.printf("%2s %-5s %-8s %-6s %-6s%n", n, p.info.getID(), p.info.getFullname(), p.info.getAge(), p.info.getGender());
}
inorder(p.right);
}
}
In-order traversal is equivalent to iterating a TreeMap's entrySet.
final Map<String, Employee> employees = new TreeMap<String, Employee>();
...
for (final Map.Entry<String, Employee> entry : employees.entrySet()) {
/* iterating in-order */
}
TreeMap simply uses a binary search tree (in particular, according to the specification, a red-black tree). Consider using it instead of rolling your own solution ;-)
That being said, if you're intent on rolling your own, maybe try something like this...
public EmployeeSSLnode search(final EmployeeSSLnode root, final String name) {
EmployeeSSLnode left;
return root == null
? null
: (left = search(root.left, name)) == null
? root.info.getFullname().equals(name)
? root
: search(root.right, name)
: left;
}
I think this is what you can do.But ensure that your your tree doesn't have the duplicate names.
public void searchFull(EmployeeSLLnode p, String name) {
if (p == null)
return;
searchFull(p -> left, name);
if (p.info.getFullname().equals(name)) {
//This is the node do other stuff here
return;
}
searchFull(p -> right, name);
}
Also it would be better to do general search in BST instead of searching through Inorder. Inorder searcing in BST would actually ruin the whole purpose of BST. Compare the input Name with node using compareTo() method of String class and depending on whether name is alphabetically later or earlier move either to right or left.
Most of this code should be inside the inorder() method. Undoubtedly it actually is, so you have two prints, so you get two outputs. All the searchFull() method should do is call inorder(root).