LinkedList findElement - java

I try to use below code to find the last k-th element in the LinkedList.
Why does it always return null?
public Node findElem(Node head, int k){
if(k < 1|| k > this.length()){
System.out.println("error");
}
Node p1=head;
Node p2 = head;
for(int i=0;i<k-1;i++) {
p1 = p1.next;
}
while(p1 != null){
p1= p1.next;
p2 = p2.next;
}
return p2;
}

What are you trying to do with that code? I guess you're trying to find t Node in the LinkedList that is the k-th Node?
But in every way your code is completely useless.
It should be something like that:
public Node findElem(Node head, int k) {
if(k < 1 || k > this.length()) {
System.out.println("Error");
return null;
}
Node position = head;
while(k > 0) {
position = position.next;
k--;
}
return position;
}
Hope this is what you were looking for. If not feel free to ask me again.

You only need one variable: reference to a k-th element on the list, which in your code is p1. Find that element as you do here:
for(int i=0; i<k-1;i++) {
p1 = p1.next;
}
and then return it. Also, looking at your previous if(k<1|| k>this.length()), you except a non-zero number, so you should init i in the for loop to 1 because head would be the 1-st node in your linked list.

Related

How do I do a time complexity analysis for my get method?

How would I do a time complexity analysis for my get() method?
private DNode find(int index)
{
DNode curr = head; // alias
// Conditional Statements - if the index is in the first half of the list, loop forward to find
if(index >= 0 && index <= size()/2)
{
// For loop - indexes the reference result to the next node
for(int skip = 0; skip < index; skip++)
{
curr = curr.getNext();
}
}
// Otherwise, loop backwards in the list
else
{
// For loop - indexes the reference result to the back node
for(int skip = 0; skip < index; skip--)
{
curr = curr.getBack();
}
}
return curr; // The item at the specified index for the node
}
public Object get(int index) throws ListIndexOutOfBoundsException
{
// Conditional Statements - checks if index is valid
if(isValid(index))
{
DNode result = find(index);
return result.getItem();
}
throw new ListIndexOutOfBoundsException("Out of bounds");
}
How do I test for the best, worst, and average cases for time complexity? I'm a little confused on how I analyze for this.
EDIT: I've added my find() method

Moving character efficiently on a row

Given input (items = 6, position = 3)
creates a row of 6 items and a character positioned on item 3 {0,1,2,[3],4,5}
A call to left() moves the character two positions to the left and the item at position 3 is removed {0,[1],2,4,5}
The next call to right() moves the character two positions to the right and the item at position 1 is removed {0,2,[4],5}
Then calling position() method now should return 4.
The character will not move to the left or right if no items are present so no need to implement that.
public class MyClass {
int position;
int[] items;
public MyClass(int n, int position) {
this.position = position;
items = new int[n];
for(int i=0; i<n; i++) {
items[i] = i;
}
}
}
public void left() {
int p = this.position;
items[p] = -1;
for(int z=0; z<2;) {
p--;
int value = arr[p];
if(value != -1) {
z++;
}
}
this.position = p;
}
public void right() {
int p = this.position;
items[p] = -1;
for(int z=0; z<2;) {
p++;
int value = arr[p];
if(value != -1) {
z++;
}
}
this.position = p;
}
public int position() {
return arr[position];
}
This code works perfectly for small inputs, but I am getting performance errors when the input is large.
How to implement this efficiently? I don't have test case details for the error related to performance errors.
As it already has been pointed outed both in the comments and the answer by #AbhinavMathur, in order to improve performance you need to implement Doubly linked list data structure.
Note that it's mandatory to create your own implementation that will maintain a reference to the current node. Attempt to utilize an implementation built-in in the JDK in place of the items array will not buy you anything because the advantage of the fast deletion will be nullified by the cost of iteration (in order to reach the element at position n, LinkedList needs to crawl through the n elements starting from the head, and this operation has a liner time complexity).
Methods left(), right() and position() will have the following outcome:
left() - in case when the previous node (denoted as prev in the code) associated with current is not null, and in tern its previous node exists, the current node will be dereferenced (i.e. next and previous nodes associated with the current node will be linked with each other), and the variable current would be assigned to the prev of the previous node, i.e. current.prev.prev. Time complexity O(1).
right() - in case when the next node (denoted as next in the code) associated with current is not null, and in tern its next node exists, the current node will be dereferenced in a way that has been described above, and the variable current would be assigned to the next of the next node, i.e. current.next.next. Time complexity O(1).
position() - will return a value of the current node. Time complexity O(1).
That's how it might look like:
public class MyClass {
private Node current; // a replacement for both position and items fields
public MyClass(int n, int position) {
Node current = new Node(0, null, null); // initialing the head node
if (position == 0) {
this.current = current;
}
for (int i = 1; i < n; i++) { // initialing the rest past of the linked list
Node nextNode = new Node(i, current, null);
current.setNext(nextNode);
current = nextNode;
if (position == i) {
this.current = current;
}
}
}
public void left() { // removes the current node and sets the current to the node 2 position to the left (`prev` of the `prev` node)
if (current.prev == null || current.prev.prev == null) {
return;
}
Node prev = current.prev;
Node next = current.next;
prev.setNext(next);
next.setPrev(prev);
this.current = prev.prev;
}
public void right() { // removes the current node and sets the current to the node 2 position to the right (`next` of the `next` node)
if (current.next == null || current.next.next == null) {
return;
}
Node prev = current.prev;
Node next = current.next;
prev.setNext(next);
next.setPrev(prev);
this.current = next.next;
}
public int position() {
return current.getValue();
}
public static class Node {
private int value;
private Node prev;
private Node next;
public Node(int value, Node prev, Node next) {
this.value = value;
this.prev = prev;
this.next = next;
}
// getters and setters
}
}
A link to Online Demo
Using an array, you're setting the "removed" elements as -1; repeatedly skipping them in each traversal causes the performance penalty.
Instead of an array, use a doubly linked list. Each removal can be easily done in O(1) time, and each left/right operation would only require shifting the current pointer by 2 nodes.

Return location of first occurrence and return -1 if not found within the circular linked list

I am trying to assign -1 to the index if is not found within the circular linked list. This is the code I have currently:
public int indexOf(int value){
Node temp = tail.next;
int count = 0;
int index = 0;
while(temp != null) {
if(temp.value == value) {
index = count;
return index;
}
count++;
temp = temp.next;
}
return index -1;
}
When I test the code these are the results:
The list should be [8 12 14]: [ 8 12 14]
*** TESTING INDEXOF ***
The index of 8 should be 0: 0
The index of 14 should be 2: 2
The code stops, it is supposed to print the index of 9, which is not in the list, which would be -1. I'm not sure how to fix this. My code just runs and doesn't produce any more results (well not in a time-efficient manner anyway).
Would I have to do :
while(temp == null){
index = -1;
break;
}
I appreciate any help!
As Kaus in the comments pointed out your while loop will never end in the current state. Assuming that the tail actually points to the last element in your list the following code could be used:
public int indexOf(int value) {
Node head = tail.next; //tail should be connected to a head
Node current = head;
int index = 0;
do {
if (current.value == value) {
return index;
}
current = current.next;
++index;
} while (current != head);
return -1;
}
As it goes through all elements (starting from the head) and ends if it encounters head again (assuming that the searching value is not found).

BFS not returning a path

I am trying to implement BFS on a 2d array given the start point and end point. I tried giving my function two points on the grid, but it returns an empty array meaning that there is no path.
Can someone please point where am I going wrong and if possible help me correct my error? Thanks.
public Point[] bfs2(Point start, Point end) {
boolean[][] visited = new boolean[50][50];
for (int i = 0; i < visited.length; i++)
for(int j = 0; j < visited.length; j++)
visited[i][j] = false;
visited[start.getX()][start.getY()] = true;
LinkedList<Point> path = new LinkedList<>();
Queue<Point> q = new LinkedList<>();
q.add(start);
while (!q.isEmpty()) {
Point next = q.remove(); //i think the error is here
Point[] neighbours = next.getNeighbours();
path.add(next);
if (next.getX() == end.getX() && next.getY() == end.getY())
break;
else if (!visited[next.getX()][next.getY()]) {
for (Point neighbour : neighbours) {
if (!visited[neighbour.getX()][neighbour.getY()]) {
q.add(neighbour);
}
visited[neighbour.getX()][neighbour.getY()] = true;
}
}
}
Point current = path.removeLast();
ArrayList<Point> v = new ArrayList<>();
while (current.getX() != start.getX() || current.getY() != start.getY()) {
v.add(current);
current = path.removeLast();
}
return v.toArray(new Point[v.size()]);
}
EDIT:
Point current=q.peek();
ArrayList<Point> v=new ArrayList<>();
if(start.getX()==end.getX() && start.getY()==end.getY()) return new Point[0];
while(current.getX()!=start.getX() || current.getY()!=start.getY()){
v.add(current);
current=current.parent;
}
return v.toArray(new Point[v.size()]);
The first issue is that you're adding all the elements you remove from the queue to the path (I'm referring to the line containing path.add(next);).
Instead, you should keep track of the parent node from which you visited each node. When you find the end node, you can trace back your steps to the start node.
If you have exhausted all the nodes and you still haven't found the end node, you can then return an empty list.
Let me know if you need an MCV example, and I'll add it.
Later Edit:
You need to add a Point parent field to your class, like this:
class Point {
int x;
int y;
Point parent; // reference to the Point from which this Point was visited
// constructors, getters, setters, etc.
}
Then you can change your BFS implementation to also set the parent for the current node when iterating through its neighbors. You must change the loop to something like this:
for (Point neighbour : neighbours) {
if (!visited[neighbour.getX()][neighbour.getY()]) {
q.add(neighbour);
visited[neighbour.getX()][neighbour.getY()] = true;
neighbour.parent = next;
}
}

Binary tree - find position in inorder traversal

I have a binary search tree where i have to implement a method called
int valueAtPosition(int x)
The problem is, that i need the position in an in order traversal.
To find the in order traversal i have this the following code, but i don't know how i count the recursive calls, to get the right position.
public void inOrderTraverseTree(Node root){
if(root != null){
inOrderTraverseTree(root.leftChild);
System.out.println(root);
inOrderTraverseTree(root.rightChild);
}
}
I think the other solutions are O(n). All you need for this is a count of the children for each node for O(log n).
When you insert a node, for each node you traverse you increase the counter on the traversed node by one.
You need to maintain these counters when deleting, rebalancing, etc which normally isn't difficult.
With this you can get the position of the node when inserted, find the position of a node by value or find a node by position.
To find a node by position is the same kind of binary traversal as for finding by value. If you want the item at position 1000 then you start at the root. No root, not item at that position. Then you look at the left child (you can do it in the other order too and switch ascending/descending), on the left if the left child exists the number of children on the left is 0 plus the count of the children on the left node. Let say in this scenario that the left exists and has 500 children. Then you know 1000 can't be left because there aren't enough items on the left, so it must be right. You can repeat this also checking for bounds all the way down.
For simple O(n) in order traversal if you have a global counter you just increase it only after traversing the left. That should do the same as a depth first search. No need for decreasing and increasing counters or pushing and popping on a stack. You can also have your functions return a count.
public int inOrderTraverseTree(Node root){
if(root == null)
return 0;
int count = inOrderTraverseTree(root.leftChild);
count++;
count += inOrderTraverseTree(root.rightChild);
return count;
}
This approach only becomes annoying if you want to return the node as well.
You can of course replace a recursive function with your own stack but this is a rarely needed performance optimisation and you'll be far better off with the O(log n) solution if you need performance than an optimised custom stack based solution.
You can also use a counter in the recursive approach. However, you can't simply pass an int counter argument - you need all calls to see the "same" counter, so you will have to wrap it in a class (or, as in this case, an inner class):
public static class Counter {
private int value;
public Counter(int initialValue) { value = initialValue; }
public boolean decrement() { value--; return value == 0; }
public boolean expired() { return value <= 0; }
}
public Node inOrderTraverseTree(Node root, Counter counter){
if (root != null && ! counter.expired()) {
Node left = inOrderTraverseTree(root.leftChild, counter);
if (left != null) {
return left;
} else if (counter.decrement()) {
return root;
} else {
return inOrderTraverseTree(root.rightChild, counter);
}
} else {
return null;
}
}
To find the 9th node in-order (using 1-based indexing), you would call this as
Node the9th = inOrderTraverseTree(root, new Counter(9));
If there is no 9th node, it would return null. If you want to use 0-based indexing instead, change { value--; return value == 0; } to { return value-- == 0; }
The iterative in-order traversal approach makes this pretty easy. Increment a counter whenever a node is popped from the stack. When the counter is equal to x, return the value of the node.
Integer valueAtPosition(int x, Node root) {
int count = 0;
List<Node> stack = new ArrayList<>();
Node node = root;
while (!stack.isEmpty() || node != null) {
if (node != null) {
stack.add(node);
node = node.leftChild;
} else {
node = stack.pop();
if (count == x) {
return node.value;
}
count++;
node = node.rightChild;
}
}
return null;
}
Recursive version requires passing a mutable wrapper for a counter like so:
public class Counter {
int count = 0;
}
public void inOrderTraverseTree(Node root, int index, Counter counter){
if(root == null || counter.count > index) {
return;
}
inOrderTraverseTree(root.leftChild);
if (counter.count == index) {
System.out.println(root);
}
counter.count = counter.count + 1;
inOrderTraverseTree(root.rightChild);
}
Following is recursive in-order traversal approach: (in c++)
bool valueAtPositionUtil(struct treeNode *root, int &currIndex, int i, int &value) {
if(root != NULL) {
if(valueAtPositionUtil(root->left, currIndex, i, value)) {
return true;
}
if(currIndex == i) {
value = root->data;
return true;
}
currIndex++;
if(valueAtPositionUtil(root->right, currIndex, i, value)) {
return true;
}
}
return false;
}
int ValueAtPosition(int i, struct treeNode *root) {
int value = 0;
int currIndex = 0;
if(valueAtPositionUtil(root, currIndex, i, value)) {
return value;
}
//index out of bound
// you can return according your problem
return -1;
}

Categories

Resources