I am looking for good way to traverse a list of categories to create an hierarchy. The present algorithm I am using will not be able to take deep nesting into consideration.
I have a list of all categories (including parent and their all sub-categories), category class is like below:
class Category{
private int id;
private int parentCategoryId;
private String name;
/*Getter Setters*/
}
Here the parentCategoryId stores the id of its parent, root categories will be having parentCategoryId = 0 and their could be many root categories. Current condition requires me to extend the nesting to atleast 5-6 levels deep, and my current algo fails over that.
What could be a good way to arrange them in such an order that I can easily iterate over them in my view to build something like this:
-Root1
--Root1Sub1
--Root1Sub2
---Root1Sub2SubSub1
---Root1Sub2SubSub2
-Root2
--Root2Sub1
The algorithm you are looking for is called Depth-first search, or DFS (you can also compare it to Breadth-first search, BFS).
As written in Wikipedia:
Depth-first search (DFS) is an algorithm for traversing or searching tree or graph data structures. One starts at the root (selecting some arbitrary node as the root in the case of a graph) and explores as far as possible along each branch before backtracking.
In order to use it efficiently, your class needs to have a list of references to child categories (parent IDs is not important, but you should have actual references, not IDs, of the child categories).
The algorithm (using an explicit stack) is then something like:
static void dfs(Category root) {
Stack stack = new Stack();
// start by pushing the root node to the stack
stack.push(root);
while (!stack.isEmpty()) {
Category node = (Category)stack.pop();
// do something with this node
// e.g. System.out.print(node.name);
// push children to the stack
stack.addAll(node.children);
}
}
Recursive solution is even simpler:
static void recursiveDfs(Category node) {
// do something with this node
// e.g. System.out.print(node.name);
// recursively process all children
Iterator children = node.children.iterator();
while (children.hasNext())
recursiveDfs((Category)children.next());
}
Related
I have a Mentor class in which I have an ID for each mentor and an ArrayList of mentee IDs, like this:
public class Mentor {
int mentorId;
ArrayList<Integer> mentees = new ArrayList<>();
public Mentor(int mentorId, ArrayList<Integer> mentees) {
this.mentorId = mentorId;
this.mentees = mentees ;
}
}
The problem is that some mentees can be mentors too.
I would like to somehow get a count of all of the mentees associated to the top mentor as well as how many mentors are under the top mentor.
So, basically, if a mentor has a mentee, who is also a mentor, then this mentor's mentees are also associated to the top mentor.
So, my thinking was to loop through the mentee-list and see if any of the id's match an ID of Mentor. If true, Add this mentor's list of mentees to a list and loop again, but this will not work dynamically.
My main class looks something like this:
ArrayList<Mentor> mentors = new ArrayList<>();
ArrayList<Integer> mentees = new ArrayList<>();
ArrayList<Integer> mentees2 = new ArrayList<>();
mentees.add(2);
mentees.add(3);
mentees2.add(4);
mentees2.add(5);
//[1,{2,3}]
mentors.add(new Mentor(1, mentees));
//[2,{4,5}]
mentors.add(new Mentor(2, mentees2));
int mentorCount = 0;
int menteeCount = 0;
for (Mentor mentor : mentors) {
for (Integer mentee : mentees) {
mentorCount++;
if (mentee == mentor.mentorId){
mentorCount++;
//add each mentee to arraylist and start the process again, but is there an easier way to do this.
}
}
}
I was wondering if there is a way of solving this, maybe using streams?
I would recommend using good object oriented design, you shouldn't just use integer id's like that, because in this situation you could simply make an ArrayList of Person objects Where Mentees, and Mentors Inherit from Person. Then you can check if a Person is an instance of Mentee versus Mentor:
for (Person p : people) {
if (p instanceof Mentor)
{
// Mentor logic
}
if (p instanceof Mentee)
{
// Mentee Logic
}
}
Firstly, let's briefly recap the task.
You have a set of mentors, each mentor has a collection of mentees. Some of them might happen also to be mentors and so on.
Class design
From the perspective of class design, the solution is pretty simple: you need only one class to describe this relationship - Mentor. And each Mentor should hold a reference to a collection of Mentors (not integer ids).
In your domain model, as you described it, there's no substantial difference between a mentor and a mentee. Mentor points to other mentors - is a simplest way to model that. Mentee is just an edge case, a mentor which has an empty collection of mentors.
You don't need to include classes and features in your application that doesn't bring benefit.
Data structure
From the perspective of data structures, this problem can be described very well with an acyclic disjointed Graph.
Acyclic because if we consider the relationship between mentors when a mentor could indirectly point at themself (i.e. a mentor N has a mentee, with in tern points to another mentee that happens to be also a mentor of mentor N) the task becomes ambiguous. Therefore, I'm making an assumption that no one can be a mentor to himself.
I also depicted this data structure as disjointed because mentors in this model (as well as in real life) can form isolated groups, which in graph theory called connected components. That means that there could be several mentors with the same count of mentee, which happens to be the largest.
Depth first search
In order to find all the vertices (mentors) connected with a particular mentor, we have a classic traversal algorithm, which is called Depth first search (DFS). The core idea of DFS is to peek a single neighbor of the given vertex, then in turn peek one of its neighbors and so on until the hit the vertex that doesn't point to the other vertex (i.e. maximum depth is reached). And then it should be done with every other neighbors of the previously visited vertices.
There are two ways to implement DFS.
Iterative approach
For that, we need a stack. It will store all unvisited neighbors of the previously encountered vertexes. The last vertex from each list of neighbors in every branch will be explored first because it will be placed on the top of the stack. Then it will get removed from the stack and it's neighbors will be placed on the stack. This process repeats in a loop until the stack contains at least one element.
The most performant choice of collection for the stack is ArrayDeque.
Because this approach require continuous modification of the stack by adding and removing vertices, it isn't suitable to be implemented with Stream IPA.
Recursive approach
The overall principle is the same as described above, but we don't need to provide a stack explosively. The call stack of the JVM will be utilized for that purpose.
With this approach, there's also some room to apply streams. For that reason, I've chosen the recursive implementation. Also, its code is probably a bit easier to understand. But keep in mind that recursion has certain limitations, especially in Java, and not suitable for processing a large set of data.
Recursion
A quick recap on recursion.
Every recursive implementation consists of two parts:
Base case - that represents a simple edge-case for which the outcome is known in advance. For this task, the base case is the given vertex has no neighbors. That means menteesCount of this vertex needs to be set to 0 because it has no mentee. And the return value for the base case is 1 because this vertex, in turn, is a valid mentee of another vertex that holds a reference to it.
Recursive case - a part of a solution where recursive calls a made and where the main logic resides.
The recursive case could be implemented using streams and entails recursive invocation of the for every neighbor of the given vertex. Each of these values will contribute to the menteesCount of the given vertex.
The value returned by the method will be menteesCount + 1 because for the vertex which triggered this method call, the given vertex will be a mentee as well as its mentees.
Implementation
Class mentor basically serves as a vertex of the graph. Each vertex has a unique id and collection of adjacent vertexes.
Also, in order to reuse values obtained by performing DFS I've added a field menteesCount which is initially initialized to -1 in order to distinguish between vertices that has no adjacent vertices (i.e. menteesCount has to be 0) and vertices which value wasn't calculated. Every value will be established only ones and then reused (another approach will be to utilize a map for that purpose).
Method getTopMentors() iterates over the collection of vertices and invokes DFS for every vertex which value wasn't calculated yet. This method returns a list of mentors with the highest number of associated mentees
Method addMentor() that takes a vertex id, and id of its neighbors (if any) was added in order to interact with the graph in a convenient way.
Map mentorById contains every vertex that was added in the graph and, as its name suggests, allows retrieving it based on the vertex id.
public class MentorGraph {
private Map<Integer, Mentor> mentorById = new HashMap<>();
public void addMentor(int mentorId, int... menteeIds) {
Mentor mentor = mentorById.computeIfAbsent(mentorId, Mentor::new);
for (int menteeId: menteeIds) {
mentor.addMentee(mentorById.computeIfAbsent(menteeId, Mentor::new));
}
}
public List<Mentor> getTopMentors() {
List<Mentor> topMentors = new ArrayList<>();
for (Mentor mentor: mentorById.values()) {
if (mentor.getCount() != -1) continue;
performDFS(mentor);
if (topMentors.isEmpty() || mentor.getCount() == topMentors.get(0).getCount()) {
topMentors.add(mentor);
} else if (mentor.getCount() > topMentors.get(0).getCount()) {
topMentors.clear();
topMentors.add(mentor);
}
}
return topMentors;
}
private int performDFS(Mentor mentor) {
if (mentor.getCount() == -1 && mentor.getMentees().isEmpty()) { // base case
mentor.setCount(0);
return 1;
}
int menteeCount = // recursive case
mentor.getMentees().stream()
.mapToInt(m -> m.getCount() == -1 ? performDFS(m) : m.getCount() + 1)
.sum();
mentor.setCount(menteeCount);
return menteeCount + 1;
}
public static class Mentor {
private int id;
private Set<Mentor> mentees = new HashSet<>();
private int menteesCount = -1;
public Mentor(int id) {
this.id = id;
}
public boolean addMentee(Mentor mentee) {
return mentees.add(mentee);
}
// getters, setter for menteesCount, equeals/hashCode
}
}
An example of the graph used as a demo.
main() - the code models the graph shown above
public static void main(String[] args) {
MentorGraph graph = new MentorGraph();
graph.addMentor(1, 3, 4);
graph.addMentor(2, 5, 6, 7);
graph.addMentor(3, 8, 9);
graph.addMentor(4, 10);
graph.addMentor(5, 11, 12);
graph.addMentor(6);
graph.addMentor(7, 13, 14);
graph.addMentor(8);
graph.addMentor(9, 16, 17, 18);
graph.addMentor(10);
graph.addMentor(11, 18);
graph.addMentor(12);
graph.addMentor(13);
graph.addMentor(14, 19, 20);
graph.addMentor(15);
graph.addMentor(16, 21, 22);
graph.addMentor(17);
graph.addMentor(18);
graph.addMentor(19);
graph.addMentor(20);
graph.addMentor(21);
graph.addMentor(22);
graph.getTopMentors()
.forEach(m -> System.out.printf("mentorId: %d\tmentees: %d\n", m.getId(), m.getCount()));
}
Output
mentorId: 1 mentees: 10
mentorId: 2 mentees: 10
Use Person and Mentor and Mentee subclasses as suggested by acornTime, define mentees as a list of Person and the information you want becomes simple to get:
import java.util.*;
import java.util.stream.Stream;
public class Main{
public static void main(String[] args) {
ArrayList<Person> mentees = new ArrayList<>();
mentees.add(new Mentee(11));
mentees.add(new Mentee(12));
mentees.add(new Mentor(2, new ArrayList<>()));
mentees.add(new Mentee(13));
mentees.add(new Mentee(14));
mentees.add(new Mentor(3, new ArrayList<>()));
mentees.add(new Mentor(4, new ArrayList<>()));
mentees.add(new Mentor(5, new ArrayList<>()));
Mentor mentor = new Mentor(1, mentees);
System.out.println(mentor.menteesCount());
System.out.println(mentor.mentorsInMentees().count());
}
}
interface Person {
int getId();
}
class Mentor implements Person{
private final int mentorId;
private List<Person> mentees = new ArrayList<>();
public Mentor(int id, ArrayList<Person> mentees) {
mentorId = id;
this.mentees = mentees ;
}
#Override
public int getId() {
return mentorId;
}
public List<Person> getMentees() {
return mentees;
}
public int menteesCount() {
return mentees.size();
}
public Stream<Person> mentorsInMentees(){
return mentees.stream().filter(m -> (m instanceof Mentor));
}
}
class Mentee implements Person{
private final int menteeId;
public Mentee(int id) {
menteeId = id;
}
#Override
public int getId() {
return menteeId;
}
}
Test it online here
You should do something like a depth-first or breadth-first search (*):
Maintain a Set<Integer> containing all the people you have already seen.
Maintain a queue of some kind (e.g. an ArrayDeque), of people you are going to check.
Put the first person (or any number of people, actually) into this queue.
Then, while the queue is not empty:
Take the next person in the queue
If you've already seen them, go to the next item in the queue
If you've not already seen them, put the person into the seen set; add all of their mentees into the queue
That's it. The number of people at the end is the size of the seen set.
(*) Whether you do depth-first or breadth-first search depends on which end of the queue you add mentees to: adding them to the same end that you remove them from results in depth-first search; adding them to the other end results in breadth-first search. If you don't care which, choose either.
My method should add the associated key/value pair to the trie and if the key is already in the trie, the value should be updated. However I am not quite sure what Im doing wrong, its my first time using tries.
So I am currently working on my put method and I have the following:
public void put(TrieMapNode current, String curKey, String value){
if(current.getChildren().containsKey(curKey))
value = current.get(key);
curKey =value;
put(current.getChildren().get(curKey), curKey, value);
}
Any help would be greatly appreciated thanks!
In your current implementation, you will not benefit from the advantages of a trie. That is because at the root node, you have one child for each string you encounter.
That is not the way a trie is built. Each node of your trie can have at most one child per character (the elements that form strings).
So your method should look more like the following:
public void put(TrieMapNode current, String key, String value, int depth){
if (depth == key.length()){
current.value = value;
} else {
char curChar = key.charAt(depth);
if(!current.getChildren().containsKey(curChar)){
TrieMapNode newNode = new TrieMapNode();
current.getChildren().put(curChar, newNode);
}
put(current.getChildren().get(curChar), curKey, value, depth + 1);
}
The main mistake you did was to consider the key as a whole when inserting/updating in your trie. This would have resulted in a root node having one child node for each key in your map (so a ton of children), but with a very limited depth (the root node, its children and that's it).
In the implementation I proposed you, a node has one child per possible character (a bounded number, 26, 52, anyway a small and bounded number).
And its depth is not limited to one, because as you can see in the else block, we create a node if the one we look for did not exist (when you start you only have a root node, so you need to plan for the case where new node are created), and we also call recursively put on a child of the current node. So the value will be stored at a depth equal toi the length of its key.
Briefing:
I have implemented three search algorithms to break a lock. A lock can be broken by the actions shaking, pulling, pulling, or poking. These are 4 methods can be applied to the given lock. This lock has a length anywhere from 1 to 16, meaning that if the length was 16, 16 back to back actions in the correct order will need to be done. For example, a length two lock that can be unlocked by pulling and then poking will need to be pulled and then poked. The data structure devised to solve this is a tree where each parent has 4 children that correspond to actions. These search algorithms climb the tree in many ways to find the correct solution to break a given lock.
Set-up of Solution & Problem:
I have one class called Tree that has 3 Search algorithms: Breadth-First, Depth-Limited, and Iterative-Deepening Search. In this same class, I have 2 helper methods to help each algorithm break a lock combination (check, which checks if the sequence of actions up to the child being viewed is a solution, and depth, which determines the depth of a given child). I also have a Node class that is used by Tree to create the root and subsequent children. Now, I want to store each algorithm in an array, so that I can iterate over each algorithm, and collect data for each algorithm from a main function. I have looked a little into the Command Pattern regarding Polymorphism. It seems that it might work, but I am confused on how I would have to organize my current solution to adapt. Would I need to turn each algorithm methodintoPerhaps there is a better solution than the Command Pattern. I can create a main in the Tree and simply call each algorithm there, but that seems a bit "sloppy" to me. Any suggestions?
The code below is just to get a gist of my current format. I have would rather simplify the code to show organization to best get at how I can adapt to utilize something like the Command Pattern to store each algorithm in an array to iterate over each and collect certain data.
public class Tree {
Node root = new Node(0, null);
TheLock lock = new TheLock("Michael");
Tree()
{this.root = root;}
public int runBST(TheLock lock){
}
public int it2runIDS(TheLock lock){
}
public int runDLS(int depthlim, TheLock lock){
}
public boolean check(Node child,TheLock lock) {
}
public int depth(Node child, int currd) {
}
}
public class Node {
int action;
Node parent;
public Node(int action, Node parent) {
this.action = action;
this.parent = parent;
}
}
I would suggest the Visitor pattern, if you had to pick a specific one. Each algorithm will visit one lock and try to break it.
The following approach is not exactly an implementation of said pattern, but it shows one way you can store a list of objects with a similar method
Start with an Interface, and some model object to hold state of a Lock
public interface LockAlgorithm {
// returns true if lock is broken
boolean break(Lock lock);
}
Some implementation, repeat for other types
public class BFSLockAlgorithm implements LockAlgorithm {
#Override
public boolean break(Lock lock) {
return false; // TODO: implement
}
}
Then, you store a list of interface implementations to loop over and apply on some Lock object
// in main
List<LockAlgorithm> algos = Arrays.asList(new BFSLockAlgorithm());
Lock l = new Lock("data");
for (LockAlgorithm a : algos) {
if (l.isLocked()) {
if (a.break(l)) System.out.print("success");
}
}
if (l.isLocked()) {
System.out.print("failed");
}
The inverted way to implement the link above would be to allow for boolean Lock.unlockWith(LockAlgorithm a)
Don't forget to do adequate unit testing for each LockAlgorithm first
I need to implement a Trie (in Java) for a college project. The Trie should be able to add and remove Strings (for phase 1).
I have spent several hours each day (for the last few days) trying to figure out how to do this and FAILED miserably each time.
I require some help, the examples on the internet and my textbook (Data Structures and Algorithms in Java By Adam Drozdek) are not helping.
Information
Node classes I am working with:
class Node {
public boolean isLeaf;
}
class internalNode extends Node {
public String letters; //letter[0] = '$' always.
//See image -> if letter[1] = 'A' then children[1] refers to child node "AMMO"
//See image -> if letter[2] = 'B' then children[2] refers to internal node "#EU"
public TrieNode[] children = new TrieNode[2];
public TrieInternalNode(char ch)
{
letters = "#" + String.valueOf(ch);//letter[0] = '$' always.
isLeaf = false;
}
}
class leafNode extends Node
{
public String word;
public TrieLeafNode(String word)
{
this.word = new String(word);
isLeaf = true;
}
}
And here is the pseudo code for insert that I need to follow: (warning it is very vague)
trieInsert(String K)
{
i = 0;
p = the root;
while (not inserted)
{
if the end of word k is reached
set the end-of-word marker in p to true;
else if (p.ptrs[K[i]] == 0)
create a leaf containing K and put its address in p.ptrs[K[i]];
else if reference p.ptrs[K[i]] refers to a leaf
{
K_L = key in leaf p.ptrs[K[i]]
do
{
create a nonleaf and put its address in p.ptrs[K[i]];
p = the new nonleaf;
} while (K[i] == K_L[i++]);
}
create a leaf containing K and put its address in p.ptrs[K[--i]];
if the end of word k is reached
set the end-of-word marker in p to true;
else
create a leaf containing K_L and put its address in p.ptrs[K_L[i]];
else
p = p.ptrs[K[i++]];
}
}
I need to implement the following methods.
public boolean add(String word){...}//adds word to trie structure should return true if successful and false otherwise
public boolean remove(String word){...}//removes word from trie structure should return true if successful and false otherwise
I cant find pseudo code for remove, but if insert does not work delete wont help me.
Here is a image of how the Trie that I need to implement should look like.
I am aware that the Trie will still be inefficient if implemented like this, but at the moment I need not worry about this.
The book provides an implementation that is similar to what I need to do but doesn't use the end of word char ('$') and only stores the words without their prefixes in the child nodes http://mathcs.duq.edu/drozdek/DSinJava/SpellCheck.java
Constraints
I need to implement the trie in JAVA.
I may not import or use any of Java's built-in data structures. (ie. no Map, HashMap, ArrayList etc)
I may use Arrays, Java primitive Types and Java Strings.
The Trie must use a $ (dollar) symbol to indicate a end-of-word. (see the image below )
I may asume that now word containing the $symbol will be inserted.
I need to implement the Trie it in the same style as the book does.
Case of words doesn't matter ie. all words will be considered to be lowercase
The Trie should only store the end-of-word character and the characters applicable to a word and not the entire alphabet(like some implementations).
I do not expect anyone to do the implementation for me(unless they have one lying around :P) I just really need help.
First of all, I don't think you should make leaf nodes and internal nodes separate classes. I recommend making a universal node class with an isLeaf() method. This method would return true if a node has no children.
Here is some higher-level pseudocode for the functions you need to implement. For simplicity, I assume the existence of a method called getIndex() which returns the index corresponding to a character.
Insert(String str)
Node current = null
for each character in str
int index = getIndex(character)
if current.children[index] has not been initialized
initialize current.children[index] to be a new Node
current = current.children[index]
You can easily augment this pseudocode to fit your needs. For example, if you want to return false whenever insertion isn't successful:
Return false if the input string is null
Return false if the input string contains invalid characters
Now, here is some higher-level pseudocode for remove.
Remove(String str)
Node current = null
for each character in str
int index = getIndex(character)
current = current.children[index]
// At this point, we found the node we want to remove. However, we want to
// delete as many ancestor nodes as possible. We can delete an ancestor node
// if it is not need it any more. That is, we can delete an ancestor node
// if it has exactly one child.
Node ancestor = current
while ancestor is not null
if ancestor has 2 or more children
break out of loop
else if ancestor has less than 2 children
Node grandAncestor = ancestor.parent
if grandAncestor is not null
reinitialize grandAncestor.children // this has the effect of removing ancestor
ancestor = ancestor.parent
At a very high level, we follow the input string to the node we want to remove. After this, we traverse up the tree following parent pointers and delete every node with 1 child (since it is no longer needed). Once we reach a node with 2 children, we stop.
Like Insert, we can easily augment this pseudocode to return false whenever deletion isn't successful:
Return false if the input string is null
Return false if the input string contains invalid characters
Return false if the input string leads to a Node which doesn't exist
It is easiest to implement delete if your Node class has a parent field. However, it is possible to implement the method without parent points, but it is more difficult. You can see an example of the trickier implementation here.
I am working on assignment for school. It manly consists of a method that takes as input a binary tree and returns a double threaded tree. Eg(if left child = null then left child will be connected with preceding inorder parent and if right child = null the it will link to its inorder succesor. Now I have an idea for the implementation...
I iterate recursively trough the original BINARY tree and store into an array the inorder traversal. Now, because my teachers implementation requires that threaded trees be a different class from binary. I must traverse again trough the binary tree and convert each node from binaryNode to threadedNode thus having at the end a "duplicate" of the initial BinaryTree but as Threadedtree type. After I do this I traverse again trough this threadedTree and whenever i see a null left or right child I refer to the inorder arraylist and find the threads.
Now as you might have noticed this is extremely inefficient, i am essentially traversing the tree 3 times. My professor has stated that this could be done recursively with only one traversal, essentially converting to threadedNode and finding the threads all at once. I have tried multiple ways but i can not find one that works. Does anyone have any kind of tip or some way i can implement it? Thanks
This is the method as specified by the instructor
public static <T> ThreadedNode<T> thread(BinaryNode<T> root)
{
//threads a binary tree
}
The instructor is correct. One traversal is sufficient.
Traverse the original binary tree, creating new ThreadedNodes as you walk this tree.
public static <T> ThreadedNode<T> thread(BinaryNode<T> root) {
// We'll be keeping track of the "previous" node as we go, so use
// a recursive helper method. At first, there is no previous.
return threadHelper(root, null);
}
private static <T> ThreadedNode<T> threadHelper(BinaryNode<T> n, ThreadedNode<T> previous) {
// Create a new threaded node from the current root. Note that the threaded nodes
// are actually created in "preorder". Assume the ThreadedNode constructor sets
// the left, right, threadLeft, and threadRight fields to null.
ThreadedNode<T> t = new ThreadedNode<T>(n.getData());
// First go down the left side, if necessary.
if (n.getLeft() != null) {
// If there is a left child we have to descend. Note that as we go down the
// left side the previous doesn't change, until we start "backing up".
t.left = threadHelper(n.getLeft(), previous);
previous = t.left;
} else {
// If there is no left child, connect our left thread to the previous.
t.threadLeft = previous;
}
// Now before we go down the right side, see if the previous
// node (it will be in the left subtree) needs to point here.
if (previous != null && previous.right == null) {
previous.threadRight = t;
}
if (n.getRight() != null) {
// If there is a right child we can descend the right. As we go down we
// update previous to the current node. We do this just by passing the current
// node as the second parameter.
t.right = threadHelper(n.getRight(), t);
} else {
// No right child, no worries. We'll hook up our thread-right pointer
// later.
}
return t;
}
Consider the tree (A (B (D) ()) C). The first node you hit in an inorder traversal is D. There is no previous node. So save D as previous. Then the next node you hit is B. The previous node was D, which had no right child, so add a threaded right pointer from D to B. Then set previous to B and continue. Next you hit A. B had no right child, so add a threaded right link from B to A. A has a right child so continue, setting previous to A. The next node is C. C has no left child, so add a threaded left link from C to the current value of previous, which is A.
You could skip the second trip of traversal that you mention in your method. You could convert the nodes from BinaryNode to ThreadedNode on the fly. You'd still need to traverse twice, I think, for the inorder traversal, and for finding the threads and converting it to aThreadedTree.
For conversion on the fly, you could use the method that your instructor has given.
HTH!