I need to find fast chop with similar functionality to slowChop - java

I have implemented BinarySearchTree.slowChop, but need to implement faster algorithm.
Definition:
public BinarySearchTree<Node,T> chop(T x)
that chops our sorted set into two parts at element x. The SSet this contains elements < x, and the returned SSet is a SSet that contains elements >= x. This should work for all elements regardless of whether they are in this. 
For example, suppose s={2,4,6,8}. Then s.chop(3) returns {4,6,8} and s becomes {2}. We would get the same result for s.chop(4).
slowChop method is implemented but take O(n) time, need to reduce it to at least O(h) if tree is balanced.
public BinarySearchTree<Node,T> slowChop(T x) {
Node sample = super.newNode();
BinarySearchTree<Node,T> other = new
BinarySearchTree<Node, T>(sample);
// Iterate through the n nodes in-order.
// When see value >=x, add to new BST in O(height) time, and
// remove it from this BST (on next iteration) in O(height) time.
Iterator<T> it = iterator();
T prev = null;
while( it.hasNext() ) {
T curr = (T)(it.next());
if( c.compare(curr, x) >= 0 ) { // we have our first >= x
other.add(curr);
if( prev != null ) {
this.remove(prev); // safe to remove now
}
prev = curr;
}
}
if( prev != null ) {
this.remove(prev); // edge case, get that last one!
}
return other;
}
Following drive link contains the helper classes: BinarySearchTree BinaryTree DefaultComparator SSet
https://drive.google.com/drive/folders/1Uc6pNFg8e3WyeiinVFk6yA4W0LdB6UGx?usp=sharing

Related

Java SortedSet Implementation that allows you to get smallest/largest element in O(1)

is there a sorted set implementation that allows one to get the first element in O(1)? C++'s std::set can do this, so I don't see why we can't do this in Java. Thanks!
I presume you've seen the first and last methods:
E first()
Returns the first (lowest) element currently in this set.
E last()
Returns the last (highest) element currently in this set.
The Java API docs don't say what their Big-O performance is. They could conceivably be O(1). SortedSet is an interface, so it depends on the concrete implementation you use.
Tree set
SortedSets are usually TreeSets, so in practice they are O(log n).
TreeSet leverages TreeMap, and TreeMap doesn't cache the first and last nodes. When you call first or last, or create an iterator, it starts at the root and traverses down and left (or down and right) to find the target node. That takes O(log n) time.
See the OpenJDK source:
/**
* Returns the first Entry in the TreeMap (according to the TreeMap's
* key-sort function). Returns null if the TreeMap is empty.
*/
final Entry<K,V> getFirstEntry() {
Entry<K,V> p = root;
if (p != null)
while (p.left != null)
p = p.left;
return p;
}
/**
* Returns the last Entry in the TreeMap (according to the TreeMap's
* key-sort function). Returns null if the TreeMap is empty.
*/
final Entry<K,V> getLastEntry() {
Entry<K,V> p = root;
if (p != null)
while (p.right != null)
p = p.right;
return p;
}
Practically speaking, O(log n) is pretty close to O(1). In a sorted set with a million elements it would only take 20 traversals to find the first/last node (log2 1,000,000 ≈ 20).
Heap or priority queue
If you want true O(1) performance then a heap—i.e., a PriorityQueue—is a better data structure than a tree. A heap doesn't maintain the entire set of elements in sorted order. Yet you can always get the head element in O(1) time. Removing the head takes O(log n) time, after which the new head is available for instant lookup.
Skip list
There is also a lesser used ConcurrentSkipListSet class. Per Wikipedia:
A skip list is a probabilistic data structure that allows O(log n) search complexity as well as O(log n) insertion complexity within an ordered sequence of n elements. Thus it can get the best features of a sorted array (for searching) while maintaining a linked list-like structure that allows insertion, which is not possible with a static array.
Finding the first element is O(1). There's a loop but it only loops more than once if it needs to clean up nodes that have been marked for deletion. It returns immediately when it doesn't have any deletions to process. See the OpenJDK source:
/**
* Gets first valid node, unlinking deleted nodes if encountered.
* #return first node or null if empty
*/
final Node<K,V> findFirst() {
Node<K,V> b, n;
if ((b = baseHead()) != null) {
while ((n = b.next) != null) {
if (n.val == null)
unlinkNode(b, n);
else
return n;
}
}
return null;
}
Finding the last element, on the other hand, is... um... not O(1).
/**
* Specialized version of find to get last valid node.
* #return last node or null if empty
*/
final Node<K,V> findLast() {
outer: for (;;) {
Index<K,V> q; Node<K,V> b;
VarHandle.acquireFence();
if ((q = head) == null)
break;
for (Index<K,V> r, d;;) {
while ((r = q.right) != null) {
Node<K,V> p;
if ((p = r.node) == null || p.val == null)
RIGHT.compareAndSet(q, r, r.right);
else
q = r;
}
if ((d = q.down) != null)
q = d;
else {
b = q.node;
break;
}
}
if (b != null) {
for (;;) {
Node<K,V> n;
if ((n = b.next) == null) {
if (b.key == null) // empty
break outer;
else
return b;
}
else if (n.key == null)
break;
else if (n.val == null)
unlinkNode(b, n);
else
b = n;
}
}
}
return null;
}

Implementing methods from a class to a interface as a linked list

I have these folowing methods and I want to implement this in a class called LinkedBag
void replace(T oldEntry, T newEntry){}
boolean isDuplicated(T anEntry){}
void doubleBag(){}
void replace(T oldEntry,T newEntry) replaces any entry that is equal to oldEntry with the new entry newEntry. For example,suppose that replace(A,D) is called on this bag {A,B,C,A}. The resulting bag should be {D,B,C,D}
the boolean returns true if the entry anEntry appears more than
one time in the bag and false otherwise. For example, calling isDuplicated(B) on the resulting
bag in part 1 should return false, but isDuplicated(D) should return true.
void doubleBag()adds to the bag a copy of each entry that appears in the bag. For example,
calling doubleBag() on the resulting bag in part 1 should change the bag contents to {4’D, 2’B, 2’C}.
Now so far I though of getting the frequency of a node and checking if the node is duplicated like:
public boolean isDuplicated(T anEntry){
Node currentNode =firstNode;
int counter=0;
while ((counter <numberOfEntries)&&(currentNode!=null))
if(anEntry.equals(currentNode)){
return true;
}
return false;
}
and for the replace method I tried assigning values to another variables then removing them and then reassigning them again but I don't think it's right
T entry=null;
T entry1 = null;
oldEntry=entry;
newEntry=entry1;
remove(oldEntry);
entry=newEntry;
entry1=oldEntry;
add(oldEntry);
add(newEntry);
System.out.println( oldEntry+" , "+newEntry );
}
as for the double bag I still don't know how to do it.
Excuse me for my bad programming I am learning java new, and still learning the basics.
Let's just briefly look at your replace method:
T entry = null;
T entry1 = null;
// entry and entry1 are both null
oldEntry = entry;
newEntry = entry1;
// entry, entry1, oldEntry and newEntry are all null.
remove(oldEntry); // remove null
entry = newEntry; // overwriting null with null
entry1 = oldEntry; // same as previous statement
add(oldEntry); // add null
add(newEntry); // add null again
// print "null , null"
System.out.println(oldEntry + " , " + newEntry);
It's not clear what you're trying to do, but at least what's here is just a bunch of nothing. What you probably want is a little more like this:
// assuming oldEntry and newEntry are set somewhere and are correct,
// and that remove and add work as expected:
remove(oldEntry);
add(newEntry);
// And you'll want to repeat this for as many duplicates as there are of oldEntry.
As for the doubleBag method, you'll want some way to walk over entries, and then duplicate them:
Node currentNode = head;
Node newHead = null;
Node newTail = null;
while (currentNode != null) {
Node first = new Node(currentNode.data);
Node second = new Node(currentNode.data);
first.next = second;
if (newHead != null) {
newTail.next = first;
newTail = second;
} else {
newHead = first;
newTail = second;
}
currentNode = currentNode.next;
}
return newHead;
This code traverses the input list starting at head, creates two copies of the node (named first and second), links them together and appends them to a new list, which it returns at the end.
That should get you started. Also, notice how the traversal works, and see how it differs from your isDuplicated implementation (which currently has an infinite loop). I'll leave it to you to fix your implementation.

How to make an efficient algorithm for chopping a binary search tree into two by given value?

I implemented public BinarySearchTree<Node,T> chop(T x)
that chops my tree into two parts at element x. The SSet this will contain elements < x, and the returned SSet is a SSet that contains elements >= x. This should work for all elements regardless of whether they are in this.
For example, suppose s={2,4,6,8}. Then s.chop(3) returns {4,6,8} and s becomes {2}. We would get the same result for s.chop(4).
The slowChop method is implemented, but it has a time complexity of O(n), but I need to reduce it to at least O(h) when the tree is balanced (where h is the height of the tree).
public BinarySearchTree<Node,T> slowChop(T x) {
Node sample = super.newNode();
BinarySearchTree<Node,T> other = new
BinarySearchTree<Node, T>(sample);
// Iterate through the n nodes in-order.
// When see value >=x, add to new BST in O(height) time, and
// remove it from this BST (on next iteration) in O(height) time.
Iterator<T> it = iterator();
T prev = null;
while( it.hasNext() ) {
T curr = (T)(it.next());
if( c.compare(curr, x) >= 0 ) { // we have our first >= x
other.add(curr);
if( prev != null ) {
this.remove(prev); // safe to remove now
}
prev = curr;
}
}
if( prev != null ) {
this.remove(prev); // edge case, get that last one!
}
return other;
}
public BinarySearchTree<Node,T> chop(T x) {
Node sample = super.newNode();
BinarySearchTree<Node,T> other = new
BinarySearchTree<Node, T>(sample);
// TODO: Implement this method. It should match slowChop in
// behaviour, but should be faster :-)
return other;
}
Indeed, your algorithm is not making use of the efficiency that you can get from the fact you are dealing with a binary search tree. So iterating through the tree with an in-order traversal is not the way to go.
Instead, perform a binary search and cut the edges that link two nodes which should end up in different trees. While cutting you'll also need to reattach nodes to where a previous cut was performed. The complexity is the same as a binary search towards the bottom of the tree, and so it is O(logn).
Here is an implementation that assumes you have the regular getters and setters:
on the Node class: getLeft, setLeft, getRight, setRight, getValue, and
on the BinarySearchTree class: getRoot, setRoot
public BinarySearchTree<Node,T> chop(T x) {
// Create two temporary dummy (sentinel) nodes to ease the process.
Node rightRootParent = super.newNode();
Node leftRootParent = super.newNode();
// Set "cursors" at both sides
Node rightParent = rightRootParent;
Node leftParent = leftRootParent;
// Start the binary search for x, cutting edges as we walk down
Node node = this.getRoot();
while (node != null) {
// Decide for each node in the binary search path at which side it should go
if (c.compare(node.getValue(), x) >= 0) {
// Node should belong to the right-side tree
rightParent.setLeft(node); // Establish edge
rightParent = node;
node = node.getLeft(); // Move down
rightParent.setLeft(null); // Cut next edge for now (it might get restored)
} else { // Symmetric case
leftParent.setRight(node);
leftParent = node;
node = node.getRight();
leftParent.setRight(null);
}
}
// Set the roots of both trees
this.setRoot(leftRootParent.getRight());
return BinarySearchTree<Node, T>(rightRootParent.getLeft());
}

Depth first search list paths to all end nodes

Hi I have a tree in which I would like to get paths from the initial (root) node to all leaves.
I found several algortithms that list (all) apths betwenn any given two nodes within a graph (for example this SO question:
Graph Algorithm To Find All Connections Between Two Arbitrary Vertices)
For binary tree there also exists an algorithm
http://techieme.in/print-all-paths-in-a-tree/
but I work on a tree with various branching factors.
Is there any better way of achieving what I want to do than traversing the tree once in order to get all leaves and then run the algorithm above for all leaves combined with the initial node?
I was thinking about implementing simple DFS extended by some additional stack containing all nodes alongt he path to a single leaf and then listing all sentences by looping through these stacks.
ArrayList<GrammarNode> discovered = new ArrayList<GrammarNode>();
Stack<GrammarNode> S = new Stack<GrammarNode>();
while (!S.empty()) {
node = S.pop();
if (!discovered.contains(node)) {
discovered.add(node);
System.out.println(node.getWord.getSpelling().trim());
for (GrammarArc arc : node.getSuccessors()) {
S.push(arc.getGrammarNode());
}
}
}
UPDATE:
The problem of this is that one has alyways go back to the root in order to generate full sentences. So I guess the question is: How to remember the node which was already fully visited (this means where all children nodes were already explored)?
Printing all paths from the root to every leaf would mean to print the entire tree so I'd just use a simple DFS and do the following for each node:
add it to the list/stack
if the node has children, repeat for the children
if the node is a leaf, print the list/stack
pop the node from the list/stack
Example:
A
/ \
B E
/ \ / \
C D F G
The first steps would look like this:
put A on the list -> {A}
put B on the list -> {A,B}
put C on the list -> {A,B,C}
since C is a leaf, print the list (A,B,C)
remove C from the list -> {A,B}
put D on the list -> {A,B,D}
since D is a leaf, print the list (A,B,D)
...
if you know that the graph is indeed a tree (there is only one path to each node), them yes, a simple DFS would be more efficient (at least from a memory usage point of view). Otherwise, you can also use the iterative deepening DFS.
So here's a sample approach. Note that you need an extra visited field in your node structure:
public class TreeNodeExtra {
int val;
TreeNodeExtra left;
TreeNodeExtra right;
boolean visited;
TreeNodeExtra (int v) {
val = v;
visited = false;
}
}
private ArrayList<ArrayList<TreeNodeExtra>> all_path_from_root_to_leaf(TreeNodeExtra root) {
Stack<TreeNodeExtra> st = new Stack<>();
ArrayList<ArrayList<TreeNodeExtra>> res = new ArrayList<>();
st.push(root);
root.visited = true;
while (!st.isEmpty()) {
TreeNodeExtra top = st.peek();
if (top.left != null && !top.left.visited) {
st.push(top.left);
top.left.visited = true;
}
// if left node is null
else {
if (top.right == null && top.left == null) {
// we have a leaf
ArrayList<TreeNodeExtra> tmpList = new ArrayList<>();
for (TreeNodeExtra t : st) {
tmpList.add(t);
}
res.add(tmpList);
st.pop();
}
else if (top.right != null && !top.right.visited) {
st.push(top.right);
top.right.visited = true;
}
else {
st.pop();
}
}
}
return res;
}
A slight modification of DFS (which includes back-tracking) prints all the paths from a given source. In the below example the graph is represented in adjacency list format.
public void mDFS(ArrayList<node> v,int ind,ArrayList<Boolean> visit,ArrayList<node> tillNow){
visit.set(ind,true);
node n = v.get(ind);
int len = n.adj.size();
tillNow.add(n);
int count = 0;
for(node tmp: n.adj){
if( !visit.get(tmp.id) ){
count++;
tmp.pre = ind;
mDFS(v,tmp.id,visit,tillNow); // id gives index of node in v
}
}
if(count == 0){
for(node tmp: tillNow){
System.out.print((tmp.id + 1) + " - ");
}System.out.print("\n");
}
visit.set(ind,false);
tillNow.remove(tillNow.size() - 1);
return;
}

Arraylist mapping to linkedlist nodes

I want to be able to access a certain node in my Doubly Linked List in O(1) time. I know that if i traverse the list to find a certain node it would take O(n) time so I want to map the nodes to an array list where I can access the nodes in O(1) time.
I'm really unsure how I would do this mapping. I would like to see an example of how this can be done.
Edit:
I would like to be able to access any node in the linked list so I can move the nodes around in O(1) time.
Example: Move node with ID 5 to end of list in O(1) time.
Edit 2: I uploaded a picture example of what I'm trying to accomplish
You can't do this with the built-in data structures ArrayList and LinkedList.
In general, it is not possible at all to have both of
O(1) indexing (by position in the list)
O(1) removing/adding/moving anywhere in the list.
The possibilities:
You can get to O(log(N)) for both these if you use a tree-based structure.
You can get to O(1) for indexing with a array-based structure, but then removing/adding in the middle takes O(n).
You can use a Hash-Map like-structure with adding/removing in O(1), but it only allows O(1) access by key, not access by index (other than iterating, i.e. O(n)). (This means, if you add/remove something in the middle, the indexes after it won't change.)
Even if you try to combine a linked list with an array, you'll have O(n) for removing/adding (since you still have to update the array).
Okay, with your added image to show what you want, it is doable. You are in fact reimplementing something like LinkedHashMap, but only with consecutive integer keys and with ability to manipulate the "Linked" part.
If your linked list consists of Node objects, you would have an ArrayList<Node>.
You would only add elements to the ArrayList when adding new nodes to the linked list, else use the ArrayList only for lookup.
Here is an example:
class FastIndexLinkedIntList<X> {
class Node {
Node next;
Node prev;
int key;
X value;
Node(int key, X val) { this.key = key; this.value = val; }
}
ArrayList<Node> indexedNodes = new ArrayList<Node>();
Node head;
Node tail;
public void add(X value) {
int key = indexedNodes.size();
Node node = new Node(key, value);
insertAtEnd(node);
indexedNodes.add(node);
}
private void insertAtEnd(Node n) {
if(tail == null) {
assert head == null;
head = n;
tail = n;
return;
}
n.prev = tail;
n.next = null;
tail.next = n;
tail = n;
}
private void removeNode(Node n) {
if(n.next == null) {
assert n == tail; // last node
tail = n.prev;
tail.next = null;
}
else {
n.next.prev = n.prev;
}
if(n.prev == null) {
assert n == head; // first node
head = n.next;
head.prev = null;
}
else {
n.prev.next = n.next;
}
}
public void moveNodeToEnd(int key) {
Node n = indexedNodes.get(key);
removeNode(n);
insertAtEnd(n);
}
}
You might want to add more operations here, but these are enough for the example in the question:
FastIndexedLinkedList<String> ll = new FastIndexedLinkedList<String>();
ll.add("0");
ll.add("1");
ll.add("2");
ll.add("3");
ll.moveNodeToEnd(2);
I'm not entirely sure of your purpose, do you simply wish to retrieve the object's index in O(1)?
This is how it would look:
LinkedList<Object> aList; // your LinkedList
Map<Object, Integer> mapper = new HashMap<Object, Integer>();
Object[] arr = aList.toArray();
for( int i = 0; i < arr.length; i++ ){
mapper.put( arr[i], i );
}
Now, if you want to find an object in your list, what you do is get its index from the mapper object with
mapper.get( o );
================================
Re: your edit
You can't (or there's none that I am aware of). You are essentially demanding the best of both worlds (linked lists and arrays).
LinkedHashMap: provides O(1) time and keys are doubly-linked list ordered.
Use the toArray() method to convert your LinkedList to an array for constant-time retrieval:
LinkedList.toArray(arr)

Categories