0

I implemented a binary search tree and would like to make a subclass that is self-balancing (AVL). I was getting strange results, and so I decided, to isolate the problem, I made an exact copy of the parent class MyTreeMap, and called it dumbchild extends MyTreeMap. Again, it's exactly the same and works correctly. Then I delete one of the methods in dumbchild expecting it to inherit it from MyTreeMap, and that changed the behavior of the class.

This seems like a very straightforward application of inheritance, but it's not working. I thought maybe it could have to do with the data structure being recursive.

EDIT: it was requested that I include all of the code

import java.util.Iterator;

public class MyTreeMap<K extends Comparable<? super K>, V> implements Iterable<K>{

    public K key;
    public V value;
    public int height = 0;
    public MyTreeMap<K, V> left, right;

    protected void setHeight(){ // if key is not null, left and right should not be null
        if(key == null){
            height = 0;
        }
        else{
            height = 1 + Math.max(left.height, right.height);
        }
        System.out.println("set of " + key + " height to " + height);
    }


    public V put(K key, V value){
        if(key == null){
            throw new NullPointerException();
        }
        V ret;
        if(this.key == null){ // empty leaf, place found
            this.key = key;
            this.value = value;
            left = new MyTreeMap<>();
            right = new MyTreeMap<>();
            ret =  null;
        }
        else{
            int compare = key.compareTo(this.key);
            if(compare == 0){ //replace
                this.value = value;
                ret =  value;
            }
            else if(compare < 0){ // put to left
                ret =  left.put(key, value);
            }
            else{
                ret =  right.put(key, value);
            }
        }
        setHeight();
        return ret;
    }

    public Iterator<K> iterator(){
        return new Iterator<K>(){
            Iterator<K> l, r;
            K current = MyTreeMap.this.key;
            {
                if(left != null) l = left.iterator();
                if(right != null) r = right.iterator();
            }

            public boolean hasNext(){
                return current != null;
            }

            public K next(){
                K ret = current;
                if(l!= null && l.hasNext()){
                    current = l.next();
                }
                else if(r!= null && r.hasNext()){
                    current = r.next();
                }
                else{
                    current = null;
                }
                return ret;
            }
        };
    }

    public static void main(String[] args){
        MyTreeMap<Integer, String> t = new MyTreeMap<>();
        for(int i = 0; i<64; i++){
            t.put(i, null);
        }
        Iterator<Integer> it = t.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        System.out.println("height: " + t.height);

    }


}

and here is dumbchild's declaration:

public class dumbchild<K extends Comparable<? super K>, V> extends MyTreeMap<K, V> implements Iterable<K>{

dumbchild does not have setHeight, but it is exactly the same in every other way (copied and pasted, replace "MyTreeMap" text with "dumbchild"). They even have the same main method for testing.

The test is to add a bunch of stuff, and then iterator through it in preorder, printing out the values, and then print the height.

MyHashMap prints the correct height, dumbchild prints 0. If I remove other methods from dumbchild, other things go wrong too.

What am I missing?

Thanks

user3391564
  • 576
  • 1
  • 5
  • 16
  • I think you should add the code that does the insertions and the pre-order walk too. We can't tell why code is failing if we can't see the code. – markspace Aug 27 '14 at 06:54
  • Sure, I just thought it'd be a bit too much. Put it in there. The pre-order walk is from an iterator that shouldn't have any side-effects. – user3391564 Aug 27 '14 at 07:02

1 Answers1

1

I tested with the following code, and dumbchild correctly prints the height as 64. Was there any problem originally? All I did is to add definition of remove() in the code that returning an anonymous instance of Iterator<T>.

import java.util.Iterator;

class dumbchild<K extends Comparable<? super K>, V> extends MyTreeMap<K, V> implements Iterable<K>{
}

public class MyTreeMap<K extends Comparable<? super K>, V> implements Iterable<K>{

    public K key;
    public V value;
    public int height = 0;
    public MyTreeMap<K, V> left, right;

    protected void setHeight(){ // if key is not null, left and right should not be null
        if(key == null){
            height = 0;
        }
        else{
            height = 1 + Math.max(left.height, right.height);
        }
        System.out.println("set of " + key + " height to " + height);
    }


    public V put(K key, V value){
        if(key == null){
            throw new NullPointerException();
        }
        V ret;
        if(this.key == null){ // empty leaf, place found
            this.key = key;
            this.value = value;
            left = new MyTreeMap<>();
            right = new MyTreeMap<>();
            ret =  null;
        }
        else{
            int compare = key.compareTo(this.key);
            if(compare == 0){ //replace
                this.value = value;
                ret =  value;
            }
            else if(compare < 0){ // put to left
                ret =  left.put(key, value);
            }
            else{
                ret =  right.put(key, value);
            }
        }
        setHeight();
        return ret;
    }

    public Iterator<K> iterator(){
        return new Iterator<K>() {
            Iterator<K> l, r;
            K current = MyTreeMap.this.key;
            {
                if(left != null) l = left.iterator();
                if(right != null) r = right.iterator();
            }

            public boolean hasNext(){
                return current != null;
            }

            public K next(){
                K ret = current;
                if(l!= null && l.hasNext()){
                    current = l.next();
                }
                else if(r!= null && r.hasNext()){
                    current = r.next();
                }
                else{
                    current = null;
                }
                return ret;
            }

            @Override
            public void remove() {
                // ?
            }
        };
    }

    public static void main(String[] args){
        /*
        MyTreeMap<Integer, String> t = new MyTreeMap<>();
        for(int i = 0; i<64; i++){
            t.put(i, null);
        }
        Iterator<Integer> it = t.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        System.out.println("height: " + t.height);
        */
        dumbchild<Integer, String> c = new dumbchild<>();
        for(int i = 0; i<64; i++){
            c.put(i, null);
        }
        Iterator<Integer> ct = c.iterator();
        while(ct.hasNext()){
            System.out.println(ct.next());
        }
        System.out.println("height: " + c.height);
    }
}
Byungjoon Lee
  • 913
  • 6
  • 18
  • My dumbchild class isn't empty though, it had duplicates of all the methods but setHeight. And there's my mistake--it had duplicates of the fields too. – user3391564 Aug 27 '14 at 07:28
  • Good to here that you've found the problem. :-) – Byungjoon Lee Aug 27 '14 at 07:29
  • Though it leaves a question... is it possible to do inheritance with recursive structures? If class A has a field of class A, then what field will B have it B is to extend A? – user3391564 Aug 27 '14 at 07:32
  • Though seems recursive, fields are just fields. In the inheritance, all that matters is the access level (public, private, protected, ...) – Byungjoon Lee Aug 27 '14 at 07:36