简体   繁体   中英

Changing complexity from O(n) to o(logn)

We have a linkedlist called ratings that contains 3 integers userId, ItemId and value of the actual rating (example from 0 to 10) this method actually returns rating of User i and item j that the programs reads it from a File and returns -1 if there is no rating

the method that is BigOh(n) :

public int getRating(int i, int j){
    ratings.findFirst();
    while(!ratings.empty()){
        if(ratings.retrieve().getUserId() == i && ratings.retrieve().getItemId() == j)
            return ratings.retrieve().getValue();
        else 
            ratings.findNext();
    }
    return -1;  
}

How can I do this in BigOh(logn)?
Or is there anyway I can solve it using Binary Search tree?

You can use hashing to achieve your task in O(1) . Please read this article to gain a deeper understanding about hashing.

Since you are using Java, you can use HashMap to accomplish your task. Note that, worst case time complexity for hashing technique is O(log n) but on average it is O(1) . If you are more interested to know about hash tables and amortized analysis, please go through this article .

Code Example : You can create a Class with the required attributes and implement equals and hashCode method as follows. [read Java collections - hashCode() and equals() ]

class Rating {

    public int user_id; // id of the user who rated
    public int item_id; // id of the item being rated

    public Rating(int user_id, int item_id) {
        this.user_id = user_id;
        this.item_id = item_id;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (!(o instanceof Rating)) {
            return false;
        }
        Rating ratingObj = (Rating) o;
        return ratingObj.user_id == user_id
                && ratingObj.item_id == item_id;
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + user_id;
        result = 31 * result + item_id;
        return result;
    }
}

Then store values in HashMap as follows:

public static void main(String[] args) {
    HashMap<Rating, Integer> ratingMap = new HashMap<>();
    Rating rt = new Rating(1, 5); // user id = 1, item id = 5
    ratingMap.put(rt, 3);
    rt = new Rating(1, 2); // user id = 1, item id = 2
    ratingMap.put(rt, 4);
    rt = new Rating(1, 3); // user id = 1, item id = 3
    ratingMap.put(rt, 5);

    // now search in HashMap
    System.out.println(ratingMap.get(new Rating(1, 3))); // prints 5
}

As presented, this could hardly be done in O(log n). You're looking through elements until you find the one you need. In the worst case, you won't find the element you want until the end of the loop, thus making it O(n).

Of course, if ratings were a dictionary you'd retrieve the value in almost O(1): user ids as keys and for example a list of ratings as value. Insertion would be a bit slower but not much.

The short answer is: use a different data structure. Linked lists aren't capable of doing searches in anything other than linear time, since each element is linked together without any real semblance or order (and even if the list were sorted, you'd still have to do some kind of timed traversal).

One data structure that you could use would be a Table from Guava. With this data structure, you'd have to do more work to add an element in...

Table<Integer, Integer, Rating> ratings = HashBasedTable.create();
ratings.put(rating.getUserId(), rating.getItemId(), rating);

...but you can retrieve very quickly - in roughly O(1) time since HashBasedTable is backed by LinkedHashSet<Integer, LinkedHashSet<Integer, Rating>> .

ratings.get(i, j);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM