How to design a general Node for a Binary Search Tree? - java

My design problem is that I'm trying to write a general class that would fit several possible subtypes. Specifically, I'm trying to write a Node class for a binary search tree, that would fit several implementations of search trees (Avl Tree, 2-3 Tree, Red-Black tree, etc.) My problem is: different Trees require different variables in the Node class in order to maintain efficiency. AvlTree need a height variable, RedBlackTree need a color variable (which an AvlTree have no use for), and so on. What's the best design solution:
declare many variables in the Node (color, height, balancing factor,...), and just give many constructors?
Have a a variable of type Object in Node, called metadata, which every implementation will use to contain its metadata?
Something else?

How to design a general Node for a Binary Search Tree?
ok, you asked...
First, that is a great link below there. And will certainly expose
the breadth of your question, strictly keeping to Data Structs.
Abstract_Hierarchies make everything so much easier.
At least you are thinking in the right direction. As I see some have mentioned here, at least superficially, the best approach (Language Agnostic) is always the same in OOP.
By the way, Java is an excellent language, to begin practicing OOP principles. In fact, I just deleted that paragraph...
IFace, IFaces, FullInterface. The secret to building any good abstract hierarchy is 'bare bones' implementation.
(I won't implement the generics here, but Java has robust support just for this. java.util.collection this is the root of the collections hierarchy).
However, generics are virtually built into the language for you. Everything is an Object in Java. There you go...The most abstract representation of any type you can imagine.
To your specific requirements: in pseudo...or pseudo-pseudo
that's all I was ever able to grasp. The pseudo-pseudo(whatever).
INode must have at least:
One Private DATA member or Key.
Reference to at LEAST, BUT at this point, not more than 2.
Child INodes(a minor inconvenience here. java does not
give users direct access to memory via pointers, like
C/C++) Obviously, this is exactly 2, but 'AT LEAST' is a
very important methodology when thinking about progressive
implementation. Just the absolute essence, no more.
Public accessor and mutator for private DATA.
Manager function Declarations.(short list, I don't recall
whether or not operator overloading is supported in java or not)
Can't imagine how the op equals is handled, given the case...hmmm
Since an INode is useless(not entireley) apart from its Data
structure, This is where I would set up private access keys.
(Java specific) this also means, in reference to the
Manager functions above, INode will not declare a
public CTOR. java's version of C++ friend class (ITree)
In your case.(look up class access key/Java). This also
Exhibits properties of the Singleton Pattern.
---STOP HERE. This, while appearing quite incomplete, is the
First stage Implementation of the abstract INode
Hierarchy.
This is enough for a Binary Tree Data Structure.
(extend or implement) the INode Interface for
a concrete Binary Tree Node class. So far so simple.
Next, we are looking for the design provisions that will satisfy
a BST Node class. It is conceivable, though neither convenient nor
proper, to implement our current INode Interface as a
Binary Search Tree Node class.(no...no...no...modifications!!)it is what
it is...'Closed for Modifcation && Open for Extension;
We will Extend INode from our new Interface...I think I will call it IOrderedNode Interfaces should always have hyper descriptive
naming conventions. (I know, what happened to mine). Actually, it
does reflect the primary difference between a Binary Tree, and a
Binary Search Tree. A Binary Search Tree is simply an Ordered
Binary Tree. There are implications related to this, apparently
trivial, difference. Mainly, all of the practicality of having a
Serial Data Structure. This means, that we should go back to INode
and evaluate (NOT CHANGE!!) the private Data member.
--------
Hopefully, we were thoughtful when considering the abstract extensibility
of that Data member. If I remember right, generics in java have been
augmented in versatility...I will leave that to you. To borrow a concept
from C++, I would have used a generic pointer to type of template Arg. Or
better yet a void pointer(can't use the asterisk there 'cause it formats my text) doesn't get more abstract than that! the(void)(star), I mean;
Forget for a moment that you are using java, because all types in java are
integral types, via the hash code inherited from the Object class's
ToString() method. User Defined Types (UDTs) should be well thought out
here, because of the disparate implementations across Data Structures that
will implement the series of IFace extensions. (pointers, refs: in java) are always the best initial types at the base levels. They can be
adapted to point to, or hold reference to even the most complex UDT.
Ok, back those Serial attributes we were about to exploit.
Traversals::Pre-Order, In-Order, Post-Order, Breadth-First. Since we are only exploring the INode hierarchy,
we should start considering the algorithms that will be implemented in
the associated Data Structures, and try to identify any subordinate
dependencies that will need to appear in our IOrderedNode
//I think from here on out I will just write the code...
//20 min later...this stupid #$$ message box is the worst
//dev environment I have EVER! worked in...
//......(granted it isn't that)
//40 min later in Visual Studio. Tired of working without
//a net...no KB short cts...NO TAB! no auto formatting...?
template<class T>
class IcanOnlyBeaBT;//fwd _decl
//or a doubley linked list, an Adapter, a...
//keep thinking as you go...
template<class T>
class INode
{
friend class IcanOnlyBeaBT<T>;//this takes care of access
public:
// At this level we have protected
// access for derived classes--
// EXCEPT! with TEMPLATED classes!
// in C++ this is NOT an issue WHEN.
// 1. data members are 'captured' by
// template instantiation
// 2. and 3. are the exact same answer
// as 1. only I would be forced to
// elaborate on two specific instances
// with the only advantage being a
// sufficing ward on those nit-pickers
// who love to leave comments like
//
// "Weellll...NOT exactly"
//
// I dont care. I would rather
// write my explaination for not
// explaining further...
/************************************/
// (no worries here in java - C#)
// implement now to enforce the
// design on higher level abstractions;
// protected access may become
// private in remote derived classes
// we never want to come back here!!!
// push dependencies up! up! up!
INode() : whatever_Data_I_want_Ha_Ha(nullptr) {}
virtual void SetWhatEverDataIWant(T*) = 0;
virtual T* GetWhateverDataIWant() = 0;
virtual T* GetWhateverDataIWant() const = 0;
protected:
virtual ~INode() = 0;
T* whatever_Data_I_want_Ha_Ha;
INode<T>*left_child;
INode<T>*right_child;
};
template<class T>
INode<T>::~INode() {} // don't worry about this it's cool
//...notice that
// the member is protected...and pure virtual...
// it's just a boomerang--
// Notice how adaptable this Interface has become
// after only one extension and implementation is refined.
// This is BOTTOM UP because we are BUILDING...
// ...this should be TOP DOWN as we DESIGN...
// THINK--TOP DOWN...BUILD BOTTOM UP...
// Push ALL negotiable DEPENDENCIES UP AS YOU BUILD.
// Ideally, these were identified during design.
// It rarely ever goes that way cleanly...
// at least not for me, but try...try
// As incremental implementation progresses, You
// may start to identify some of these negotiable
// dependencies...these two interfaces are still
// super lean..and rather boring, but continue towards
// the AVL, Red Black, Other Data structurs they will show.
// Nodes are, for the most part, like a drawer full
// of silverware. They CAN'T do anything unless
// they are being used.
// GO UP now!!!...BUT always JUST enough!!
// No more; GOAL...to have a DESIGN SPECIFIC
// hierarchy, that IS extensible in a MODULAR
// fasion, like LEGOS. ADAPTABLE to ANY COMPATIBLE
// Data Structure, Not just TREES. Even from here...
// there are other suitablilities coming to mind,
// such as Graphs, Doubley Linked Lists, circular queues.
// Nodes are common place in Data Structures...on...on...
// Principle Attribute: ICanBe_A_BST Data Struct now.
// fwd _decl:
template<class T>
class ICanBe_A_BST; //The BT Node was FIRST Abstraction,
// BST is SECOND.
// OR a Composite Object Structure! for the
// Composite Design Pattern...or...or...or
// BECAUSE, this IOrderedNode is more QUALIFIED
// and adaptable. LOOK HERE! Don't throw away
// the specific sutibility of lower abstractions
// This should be extended to fulfil design reqs
// IOrderedNode is not intended to be a BT,
// IT 'IS A' BT by extension, BUT, it is a BST Node.
// This abstract hierarchy, UPON DESIGN COMPLETION
// Will have pervasive extensibility # unique levels.
// think {OPEN-CLOSED} open for EXTENSION, and
// CLOSED for MODIFICATION...GOAL...DON'T...come
// BACK inside this BLACK BOX once it is CLOSED..!
template<class T>
class IOrderedNode : public INode<T>
{
// RIGHT HERE! ALL previous implementation
// Is abstracted AWAY. Look how clean it all is..
// in java you would be Extending INode Interface HERE!.
// Extending IN JAVA IS inheritance.
// ALL public and protected members.
// Closed for MOD. open for EXTENSION
public:
IOrderedNode() : height(0) { }
protected:
//NOTICE!(I Can Be A BST Node IF!)my data is INTEGRAL & comparable.
//FOR instance a bool is unqualified--how can you order a tree
//when the only value is a 1 or a 0;
//UDT is dependent upon guess...
//THE USER who defind it(integral && comparable);
// Question: is there anything missing from this level
// that would disqualify concrete instantiations from adequately
// filling the intended role? .....Seriously...
// I have been awake for two days now. This may need editing.
// Regardless the process is the
// same all the way to Red Black and beyond...
int height; //new data member; height of the tree at that node...
//this comes in handy when computing the balance factor
//on balanced trees...AVL, R&B,
};
/***********************NOTE:***********************
*
* There are several considerations that have to be made
* when you are "leaving" data and and implementation "behind".
* We know we don't EVER want to come back here...
(not a super realistic GOAL...)
* Is the implementation specific to the level of bstraction.?...
* YES? then leave it here.
IS...the DATA specific to the implementation ????
* this deserves 4 Q-marks because, IF at all POSSIBLE PUSH
* these IMPLEMENTATION DEPENDENCIES..UP This RESULTS in IoC
* Inversion of Control Inversion of CONTROL INVERSION! of Control...
* Implementation dependencies should come from higher level abs
* to lower level Implementation...repeats you are seeing all over
this now TLDR, are Cardinal principles of Object
* Oriented Design. Not because I love commenting code...
but since YOU asked...I won't leave out the 'life blood'.
* Incidentally, there is a requisite
'AHAAH moment' that either comes
* or it doesn't.
*
**************************** PERSONAL NOTE:*********************
*
* I picked up java in the late 90's, and was like.
* "...what the hell is an OBJECT..?" Two years of programming from a
* procedural paradigm, in an OOP language-LATER! It hit me......
* (I know...slow learner)...but I remember saying out loud....
* 'THAT...IS...THE...COOLEST...THING...I HAVE EVER...tripped over...
* Consensually, OOP is considered to be in its INFANCY.
* Theories (opinions) are often the cause of some rather heated
* contest. In fact, one of the most intense and persistant
"cival-war" I have ever encountered, nearly dominated an entire
forum. I didn't really know enough to have an opinion
* one way or the other on the matter, but I remember thinking,
how absurd...and laughing alot.
* The theoretical epicenter was localized on the issue of...
wait for it...
*
* INHERITANCE v.s. COMPOSITION/AGGRAGATION
*
* Hmm....Everybody knows that programming to interfaces,
adhereing to common sense, established design principles,
and proven patterns, can all be accomplished without inheriting
from a single archtype...
* "Not that there's anything wrong with that..."
I'm pretty sure, that was the vein of the row on that
forum...Super entertaining though...
*
*******************************************/

I had same problem and decided to go with this simple solution.
abstract class BSTnode<K, M> {
K key;
M meta;
BSTnode<K> left;
BSTnode<K> right;
BSTnode<K> parent;
}
This simply solves the problem for your metadata.

Related

Java: Resizable Arraylists are won't stay parallel

I have a situation where my 'agent' objects contain a vast amount of data, including graphics, physics, and now also ai.
I was previously coding components of these 'agents' in separate objects, that were parallel. Now I realize, since the agents are contained in a re-sizable ArrayList, that if one of the agents is destroyed, the indices will no longer be parallel to the ai components.
Truth be told, the agent class is already 10 pages long, and it is very sensible to contain the ai methods and data in a separate object. One issue with this, of course, is that the methods will be 'reproduced' in a way, because instead of having one ai object that will accept and process the data from the many agents, I need one ai object per every agent object.
I asked about this once before and was told that having multiple instances of methods has no effect on performance or memory bloat, so that shouldn't be an issue.
I am not sure how I can solve this problem, except by possibly storing an agent_id in the agent object as well as the ai object and then running a search on each list whenever I need to call them. Needless to say, that is terrible way of doing things performance wise.
In C++, the simple solution to this problem would be a pointer, where the pointer to the proper ai instance would be contained in the agent data. I don't know how to do this, so my best solution is to just cram more data into the agent object and have it passed as an argument to the ai object.
Is there any better way to solve this 'parallel mismatching' problem.
Edit>>>
I know I can stuff all of the data into the agent class. What I was taught, is having a 30 page class is an example of bad oop structure.
My question is, how can I create a /reference/ to store in the agent class, while keeping all of the ai data encapsulated in the ai module.
Edit>> Example
public class Agent{
//pseudo code that represents what I need (yes the class declaration order is wrong)
AI_ref = new Reference(ai_module);
Graphics_ref = new Reference(graphics_module);
int[][] physics_data; //Like I said, 10 pages of this
void method1(){}
void method2(){}
//....
}
public class graphics_module{
int[][] graphics_data; //this is also about 10 pages
void method1(){}
void method2(){}
//....
}
public class ai_module{
int[][] ai_data; //this will likely span 5ish pages
void method1(){}
void method2(){}
//....
}
}
Parallel arrays are a 1960's construct developed when Basic and Fortran were modern languages. These languages had no other data structures.
Since the 1990s with OO development, if you have several different types of data that belong together, you create an object to hold references to those bits of data such that you don't need to worry about parallel anything.
I strongly suggest you refactor your code to modern best practices and use objects. Since you've provided no explicit details, this is about the most explicit answer that can be given.
To create your references, try
public class Agent{
//pseudo code that represents what I need (yes the class declaration order is wrong)
ai_module AI_ref = new ai_module();
graphics_module Graphics_ref = new graphics_module();
int[][] physics_data; //Like I said, 10 pages of this
void method1(){}
void method2(){}
//....
}
As for your parallel arrays, your example doesn't really provide enough detail to demonstrate what you are trying to do.
//pseudo code that represents what I need (yes the class declaration order is wrong)
Do you mean defining Agent before defining ai_module and graphics_module is wrong? It's not. The java compiler will have no issue with that.
You should probably work through a basic java tutorial. I think it will address many of your issues.

Why need final def in poll() method of LinkedList in Java

/**
* Retrieves and removes the head (first element) of this list.
*
* #return the head of this list, or {#code null} if this list is empty
* #since 1.5
*/
public E poll() {
final Node<E> f = first; //why final here? <<-------- ******* --------
return (f == null) ? null : unlinkFirst(f);
}
Hi there, I'm reading the source code of JDK 1.7. In above code snippet in LinkedList.java, I cannot understand why need 'final' in poll() method. Why not :
public E poll() {
return (first == null) ? null : unlinkFirst(first);
}
Can you share the insight of the implementation? Thanks.
Most of the methods in LinkedList use the final declaration on local variables.
LinkedList JDK 1.7 Source
This is likely related to the concept behind Using "final" modifier whenever applicable in java.
Adding final to all things which should not change simply narrows down the possibilities that you (or the next programmer, working on your code) will misinterpret or misuse the thought process which resulted in your code. At least it should ring some bells when they now want to change your previously immutable thing.
Technically, at the cost of 6 letters, you guarantee that something you don't ever expect to change will never change.
Does your proposed code work? Yes. I don't see any scenarios where it wouldn't. It is programmatically valid.
However, the use of final throughout the code supports sanity testing, and understandably, for all the util stuff that holds pretty much all of the things we do in Java together, it'd be nice to know that everything is working as intended.
Note: If there is a security issue that I have not seen, however, I would be interested to know about that, in a separate answer.
Martin Buchholz answered this on the concurrency-interest list in a related question:
We in jsr166-land consider our software important enough to make
optimizations we don't recommend to regular java programmers. Copying final
fields to locals generates smaller bytecode and might help the jit produce
better code (and with current hotspot, still does).
Using final on locals has no performance advantage, but it does have some
software engineering advantages. We tend to use it for locals with the same
name as a field, e.g.
final Foo foo = this.foo;
Compass answer is very reasonable, but I just want to add a further guess. I think it's a micro optimization since the access to the local variable f should, on average, be faster than access to the class field first. The final modifier is good practice but doesn't effect access latency. In this specific case the gain would likely be extremely small since you are trading two class field accesses for a single class field access and two local variable accesses.
This is not something that you should do in everyday programming, but since the collections library is used by basically every single Java program in existence these things are justifiable here.

Large branching trees in java?

My question is about scalable logic branching.
Is there an elegant way to do branching logic trees in java (although I've always thought that they look more like root systems, but that's beside the point). I'm trying to develop a very simple text based adventure game as a side project to my studies, but I'm not sure what the best way to go about navigating these large logic systems is.
What I'm trying currently is an array that holds four values: stage, location, step, choice.
[EDIT - added choice variable to store user choice, changed name to reflect actual name in my code so that I don't get confused later]
int[] decisionPoint = {stage, location, step, choice};
A stage is supposed to represent a single major part of the tree.
A location is supposed to represent my location within the tree.
A step is supposed to represent my progress through a given location.
Choice is the user input
At the moment, since I'm only dealing with a single tree, stage isn't being used much. Location and step are working well, but any time I get into a decision within a step the system breaks down.
I could keep creating more and more variables to represent deeper and deeper layers into the tree, but I feel like Java probably provides a better solution somewhere.
Currently, I'm using switch statements to figure out where in the program I am based on the values stored in nextQuestion. Is there something better? Or, is there a way to extend the array beyond what I'm using here to make it a bit more polymorphic (in the methods for the individual questions/text/whatever could I just have it create a larger array from a smaller one? Could I pass a smaller array as an argument but define the parameter as a larger array?)
//Switch example
switch(LocationTracker.getLocation()) { //start location finding switch
case 1 : //Location 1
switch (LocationTracker.getStep()) {//start location1 switch
case 1 :
location1s1(graphicsStuff);
break;
case 2 :
location1s2(graphicsStuff);
break;
} break; //end location1 switch
case 2 : //Location 2
switch (LocationTracker.getStep()) {
//same stuff that happened above
} break;
Everything I find online just brings me to irrelevant pages about different online survey creators that I can use. If I could view their source-code that'd be kind of nice, but since I can't, I'm hoping you guys can help. :)
[EDIT]
Wow, what a nice response in such a short time at such an early hour!
I'll try to go into very explicit detail about how I'm solving the problem right now. It's worth mentioning that this does technically work, it's just that every time I need a branch inside a branch I have to create another variable inside a string array to keep track of my position, and really I'm just fishing for a solution that doesn't need an infinitely expanding string as the program becomes more and more complex.
Right now I have a program with 5 classes:
The Main Class which starts the GUI
The GUI class which provides three services: userInput, userOptions, and outputArea.
The DecisionTreeStage1 class which handles the logic of my problem at the moment (using switch statements).
The LocationTracker class which is designed to track my location within the DecisionTreeStage1 class
The DialogueToOutput class which changes the options that the users have, and also updates the output fields with the results of their actions.
Special point of interest:
I want to have multiple decision branches at some point, and one main tree (maybe call it Yggdrasil? :D). For now, the DecisionTreeStage1 represents a very isolated system that isn't planning to go anywhere. I hope to use the stage variable stored in my array to move from one major branch to the next (climbing the tree if you will). My current implementation for this just uses nested switch statements to decide where I'm going. This imposes an annoying limitation: every time my path gets deeper and deeper I need another variable in my array to store that data. For example:
//Switch example deeper
switch(LocationTracker.getLocation()) { //start location finding switch
case 1 : //Location 1
switch (LocationTracker.getStep()) {//start location1 switch
case 1 :
switch(LocationTracker.getChoice()) {//Make a decision at this step based on the user choice
Given this example, what if the user choice doesn't just lead to some logic? (In this case, just an update to the outputArea) What if it leads to ANOTHER branching path? And that leads to another branching path? Eventually, I would want all paths to converge on the same spot so that I could move to the next "stage."
My real hope is to make this problem infinitely scalable. I want to be able to go as deep into one branch as I need to, without having to create a static and arbitrary number of variable declarations in my decisionPoint array every time.
I haven't been able to find much information about this, like I said.
Let me try presenting this question: Are there any other branching logic statements other than:
if(something)
stuff;
else
otherStuff;
and
switch(something) {
case 1:
stuff;
break;
case 2:
otherStuff;
break;
And if so, what are they?
PS - I know about the ternary if statement in Java, but it doesn't seem useful to what I'm doing. :)
You can build normal tree structures in Java, similar to the trees that can be built in C. Regardless if object references are theoretically pointers or not, they substitute pointers nicely in the tree constructions:
class Node {
Node left;
Node right;
Node parent;
}
You can also build graphs (cyclic graphs including) and linked lists no problem. There is no any obvious reason why large structures should have problems (apart from that object reference uses some memory).
Instead of returning a value, you could return an Callable which just needs to be executed. This can then be chained (theoretically infinitely)
You can have a LocationEvaluation for example which could return a SpecificLocationEvaluator which in turns returns one of StepEvaluation or ChoiceEvaluator or somesuch. All of these would implement the Callable interface.
Depending on how you do it, you could have strict type checking so that a LocationEvaluation always returns a SpecificLocationEvaluator or it can generic and then you can chain any of then in any order.
Once you build the structure, out, you would essentially have a tree which would be traversed to solve it.
I don't understand the problem adequately to be able to provide more concrete implementation details - and apologies if I misunderstood some of the branching (i.e. the names of the classes / steps above)

How to do a non destructive queue examination in Java

I am helping my son with a college programming class, and I guess I need the class too. He has completed the assignment, but I don't believe he is doing it the best way. Unfortunately I can't get it to work with my better way. It's clearly better, because it doesn't work yet.
He is being asked to implement some methods for a class that extends another class.
He was told he must use the following class definition, and he cannot change anything in ListQueue.
public class MyListQueue <AnyType extends Comparable<AnyType>> extends ListQueue<AnyType>
Heres what is in ListQueue
// Queue interface
//
// ******************PUBLIC OPERATIONS*********************
// void enqueue( x ) --> Insert x
// AnyType getFront( ) --> Return least recently inserted item
// AnyType dequeue( ) --> Return and remove least recent item
// boolean isEmpty( ) --> Return true if empty; else false
// void makeEmpty( ) --> Remove all items
// ******************ERRORS********************************
// getFront or dequeue on empty queue
/**
* Protocol for queues.
*/
OK I feel pretty good about traversing a linked list in Pascal or C (showing my age) but have never worked in an OOP language before.
When I attempt something like this
dummyQueue = this.front.next;
I get the following error.
* front has private access in ListQueue *
Which I agree with, but other than dequeueing an item, how can I traverse the list, or otherwise get access to front, back, next and previous which are all in ListQueue.
An education would be appreciated.
Thanks,
David
If I understand you correctly, you're doing something like this:
MyListQueue<String> dummyQueue = new MyListQueue<String>();
dummyQueue = this.front.next;
If so, one of the main tenets of OOP is encapsulation, i.e. data hiding. The idea is that users outside of the class don't have access to the inner state of the class.
If you're looking to determine the size of the Queue and you can't modify either the interface or the implementation, one thing you could do is create a delegate Queue that overrides enqueue and dequeue to increment and decrement a counter.
If you decide for a queue, you usually only want to enqueue and dequeue elements. You want to know if the queue is empty and want to look at the front element if you need it or leave it for someone else. A queue is a sort of buffer that avoids blocking, if the sender is faster then the receiver. With a queue, the receiver can decide when to read the next entry. A queue may implement some (priority based) sorting and decide, which element is the front element.
If you need other operations like traversing the list, then a queue might not be the best choice. Look at other collection types, maybe at ArrayList.
Some things can be done though, you can subclass ListQueue and override some methods. So if you want an additonal size() method, this could be a solution:
public class MyListQueue <T extends Comparable<T>> extends ListQueue<T> {
private size = 0;
public void enqueue(T element) {
size++;
super.enqueue(element);
}
public T dequeue() {
if (isEmpty()) {
return null; // that's a guess...
}
size--;
super.dequeue(element);
}
public int size() {
return size;
}
}
I've replaced AnyType with T which is more common.
You asked, "Other than dequeueing an item, how can I traverse the list, or otherwise get access to front, back, next and previous which are all in ListQueue."
In the purest sense, you should not be able to.
An idealized queue promises only a few things:
Push items into the back
Pop items from the front
(Possibly) Inspect front item, if not empty
(Possibly) A definition space predicate for pop and inspect, determining whether the queue is empty
I'll assume for the moment that the queue is not meant to be used with either concurrent readers (accessing the front at the same time) or with concurrent readers and writers (accessing the back and front at the same time).
Given that definition, there's no reason to want to look "inside" the queue. You put things in one side and take things out the other side. If you take bounding of queue size into account, you may need an additional definition space predicate for the push operation to determine whether the queue is full. "Being full" only makes sense if the queue is bounded. "Being empty" is only relevant if the thread calling pop or inspect doesn't wish to block.
Beyond that, there's the pragmatic idea of a queue. We can assume it's a sequence of items that -- barring concurrency concerns -- has an observable non-negative size and may even allow visiting each item in the sequence. Some queues even go so far as to allow removal or rearrangement of items at positions other than the front of the sequence. At that point, though, we're not really discussing a queue anymore. We're discussing the sequence that underlies the queue. If we need this kind of access, we don't need a queue. We need a sequence of which we want to offer a queue-like view to other parts of the program.
That's why queues are not usually concrete types in data structure libraries. In C++, type std::queue is a decorator around some other container type. In Java, java.util.Queue is an interface. Scala take a different approach: class scala.collection.mutable.Queue is an extension of type MutableList. That's similar to the approach mandated in your son's assignment, but it's not clear whether your ListQueue ever intended to allow outsiders (including subclasses) to take advantage of its "list nature" -- penetrating the queue view to use the sequence within.
Do you have a requirement to be able to visit anything but the head of your queue? Needing to do so limits your choices as to what kinds of queues your consuming functions can accommodate. It seems like we're learning the wrong lessons with this assignment.

Tree Transformations Using Visitor Pattern

(Disclaimer: these examples are given in the context of building a compiler, but this question is all about the Visitor pattern and does not require any knowledge of compiler theory.) I'm going through Andrew Appel's Modern Compiler Implementation in Java to try to teach myself compiler theory (so no, this isn't homework) and I'm having trouble understanding how he wants to use the Visitor pattern to transform an AST to an IR tree. (Note: I'm doing this in Python so I can learn Python also, which is why the upcoming examples are not in Java.) As I understand it, the visit and accept methods in the Visitor pattern are void-typed by design, so if I have something like
class PlusExp(Exp):
def __init__(self, exp_left, exp_right):
self.exp_left = exp_left
self.exp_right = exp_right
def accept(self, v):
v.visit_plus_exp(self)
then I would like to be able to write a visitor method like
def visit_plus_exp(self, plus_exp):
return BINOP(BinOp.PLUS,
plus_exp.exp_left.accept(self),
plus_exp.exp_right.accept(self))
which would translate the two child expressions into IR and then link them up with the BINOP representing the plus expression. Of course, this isn't possible unless I modify all the accept functions to return extra info, and that is also messy because sometimes you just want a print visitor that doesn't return anything. Yet, this text insists that a visitor is the right way to go, and in Java at that, which means it can be done without the flexibility of Python. I can't think of any solutions that aren't incredibly hacky - can anyone enlighten me as to the intended design?
A SAX parser is a kind of visitor. To avoid adding a return value to the method, you can use a stack:
class Visitor {
Stack<Node> stack = new Stack<Node>();
// . . .
void visitPlus(PlusExp pe) {
pe.left.accept(this);
pe.right.accept(this);
Node b = stack.pop();
Node a = stack.pop();
stack.push(new BinOp(BinOp.PLUS, a, b));
}
Look at source code of THIS compiler. I think that the guy has used Visitor pattern.
Caveat: I haven't read that book.
The method may be void-typed, but in Java (which the book was written for) it is also part of an object. So, the visitor method can build up the structure in a local member variable, thus maintaining the necessary context between calls.
So, for instance, your print visitor would be appending to a StringBuilder that is held as a member variable (or as a final local variable in a method that created the visitor object -- this is fairly common in Java, where creating small anonymous-inner-class objects is a common habit).
In python, you could similarly let the visitor method access a non-method-local variable to maintain context and build the structure. Eg, closure, or a small object.
Update -- small bit of code added as example from comment below
result = new Node();
result.left.add(n1.accept(this));
result.right.add(n2.accept(this));
return result;
or
result = new Node();
this.nextLoc.add(result);
this.nextLoc = result.left;
n1.accept(this);
this.nextLoc = result.right;
n2.accept(this);
The first is prettier (though still crappy comment example code), but the second would let you keep the void return type if you really needed to.

Categories