Binary Tree branch sums without recursion - java

I am trying to calculate a sum of each branch of a binary tree without using recursion. I'm trying to use a stack and can't figure out how to fix my code to get the right sums.
public static List<Integer> branchSums(BinaryTree root) {
LinkedList<BinaryTree> toVisit = new LinkedList<>();
BinaryTree current = root;
List<Integer> sums = new ArrayList<>();
int sum = 0;
while (current != null || !toVisit.isEmpty()) {
while (current != null) {
sum += current.value;
toVisit.push(current);
current = current.left;
}
current = toVisit.pop();
// if found leaf add sum to results and decrement sum by current node
if (current.left == null && current.right == null) {
sums.add(sum);
sum -= current.value;
}
current = current.right;
}
return sums;
}
Example input:
1
/ \
2 3
/ \ / \
4 5 6 7
/ \ /
8 9 10
Example output [15, 16, 18, 10, 11]

Issue with your code is you are not keeping track of the node which
has been last popped from your stack.
Here is the updated code:
public static List<Integer> caculateSum(BinaryTree root) {
List<Integer> sums = new ArrayList<>();
int sum=0;
BinaryTree current = root, popped=null;
Stack<BinaryTree> s = new Stack<BinaryTree>();
while(current!=null ) {
//checking if last node popped from stack is not equal to left or right node of current node
if(popped==null||((current.left!=null && !current.left.equals(popped)) && (current.right!=null && !current.right.equals(popped)))) {
while(current != null) {
sum+=current.value;
s.push(current);
current = current.left;
}
}
current=s.peek();
if(current.right == null) {
//if current node is leaf node
if(current.left == null) {
sums.add(sum);
}
sum-=current.value;
popped = current;
s.pop();
} else if(current.right!=null && current.right.equals(popped)){
//if current node both left and right nodes have been processed
sum-=current.value;
popped = current;
s.pop();
}else {
//if current node right part is not processed
sum+=current.right.value;
s.push(current.right);
}
if(s.isEmpty()) {
break;
}
current=s.peek();
}
return sums;
}
Will explain this by taking an example. Suppose we have given binary tree
1,2,9,3,7,null,8,5
Here in above code apart from old variables a new variable popped is used which keeps track of last element which is popped out from stack.
So, following are the major steps :
Starting from current node first we are checking if current node left is not equal to popped (if it is equal it means that current node left part is already processed so we don't need to process it again). Same we are checking if current node right node is not equal to popped node (if it is equal it means we have already processed right node of current node which indirectly means left node is also processed).
Now for the top node of stack which is current node we check :
If its right node is null If it is true it means either current
node is leaf node or it is an already processed node whose right
node is null (like in our example node with value of 3). If it is
leaf we add it in our sums list. Also, for both cases we remove
this top node and subtract its value from current sum value
(This thing has been done in above code as well) .Along with this we
will keep track of popped element from stack in popped variable.
If its right is not null but its right node is equal to popped
node This happens when in last pass of while loop we had processed
this right node. This means for top node of stack both left and
right node have been processed and hence we pop this node and keep
track of it in popped variable.
Else we push the right node of top element of stack in stack.
At the end for above example , sums variable will store result as [11, 10, 18]

I attempted this for fun and was surprised I didn't see any actual solutions. The following is in Kotlin but can easily be transcribed into Java. The trick was to add state to the Node itself to mark it as consumed before you popped it, otherwise there was no value there to check when going down another branch.
This might be useful in super rare cases to prevent stack overflow? This will still run in O(N) but takes more space with the stacks, and will visit a node twice, once to traverse and once to pop.
open class BinaryTree(value: Int) {
var value = value
var left: BinaryTree? = null
var right: BinaryTree? = null
var consumed: Boolean = false
}
fun branchSums(root: BinaryTree): List<Int> {
var sumList = ArrayList<Int>()
var nodeStack = ArrayList<BinaryTree>()
var valueStack = ArrayList<Int>()
nodeStack.add(root)
while(!nodeStack.isEmpty()) {
val node = nodeStack.get(nodeStack.size-1)
if (node.consumed) {
valueStack.removeAt(valueStack.size - 1)
nodeStack.removeAt(nodeStack.size - 1)
continue
}
valueStack.add(node.value)
if (node.right == null && node.left == null) {
var sum = 0
for (value in valueStack) {
sum += value
}
sumList.add(sum)
}
if (node.right != null) {
nodeStack.add(node.right!!)
}
if (node.left != null) {
nodeStack.add(node.left!!)
}
node.consumed = true
}
return sumList
}

You can have this method:
public static int getBranchSum(Node root){
Queue<Node> q = new LinkedList<>();
q.add(root);
int sum=0;
while (!q.isEmpty()) {
Node curNode = q.poll();
sum+=curNode.data;
if(curNode.left==null || curNode.right==null)
curNode.visited=true;
if(curNode.left != null && curNode.left.visited)
curNode.visited=true;
if(curNode.left!=null && !curNode.left.visited)
q.add(curNode.left);
else if(curNode.right!=null && !curNode.right.visited)
q.add(curNode.right);
}
root.visited=false;
return sum;
}
Then call it below in a while loop as long as the output is not equal the root data.
boolean flag=true;
List<Integer> list = new ArrayList<>();
while(flag){
int result =getBranchSum(root);
if(result == root.data)
flag=false;
else
list.add(result);
}
System.out.println(list);
However the above the working only if we have a visited boolean in the node:
class Node{
Node left,right;
int data;
boolean visited = false;
Node(int data){
this.data=data;
left=right=null;
}

Branch sum without recursion
def branchSums(root):
cs=0
stack=[{"node":root,"cs":cs}]
sums=[]
while(len(stack)>0):
node_info=stack.pop()
node,cs=node_info["node"],node_info["cs"]
if node is None:
continue
cs=cs+node.value
if node.left is None and node.right is None:
sums.append(cs)
print(sums)
stack.append({"node":node.right,"cs":cs})
stack.append({"node":node.left,"cs":cs})
return sums

Related

Convert sorted array to binary search tree with minimal height

I want to convert a sorted integer array into a binary search tree. I have posted my code below. What I cannot picture is how the recursion actually works with the for loop as inserting.
So if my array is [1,3,4, 5,8,10] I make 4, which is the mid of the array, become the root of my BST, then loop from the start of array and insert to the tree with root just created. My question is why the order of result inserted is not as the sorted given array?
public TreeNode sortedArrayToBST(int[] A) {
if (A == null || A.length == 0){
return null;
}
TreeNode root = new TreeNode(findMid(A));
for (int i = 0; i < A.length; ++i){
insert(root, A[i]);
}
return root;
}
private int findMid(int[] A){
int left = 0;
int right = A.length -1;
int mid = A[left + (right - left)/2];
return mid;
}
private void insert (TreeNode root, int val){
if (root == null || root.val == val){
return;
}
if (val < root.val){
TreeNode left = new TreeNode(val);
root.left = left;
}
if (val > root.val){
TreeNode right = new TreeNode(val);
root.right = right;
}
insert(root.left,val);
insert(root.right,val);
}
You have a couple problems with your recursive insert method. First off, everytime the val is not equal to the root's value, you create a new node. This is faulty because by doing this, you create multiple nodes and set the root's child at each step of the recursion to these new nodes, which is redundant. Let's go through your method for each node.
Adding 4
4
Adding 1
4
/
1
Adding 3
4
/
3
At this point, we can pinpoint the error. Why was 4's left child replaced with 3? Let's go through your insert method where root is the node with value 4 and val is 3.
First if-statement condition evaluates to false, so move on
Second if-statement condition evaluates to true, so create a new node with val and set root.left equal to this new node
Third if-statement condition evaluates to false, so move on
Recursive call insert(3.left, 3) just returns since 3 == 3
Recursive call insert(null, 3) just returns since root == null
So what's the fix? STOP creating new nodes at every recursive call in the call stack. Believe it or not, you should only be creating a new node when root is null, because this signifies that you've traversed the tree down to an empty child. What about the recursive calls? There's no need to do a recursive call on each of the root's children because you only go down one traversal path in a BST. You either turn left or right at each node. So what you do is only make a recursive call depending on the value of val relative to the root's value. Here's what it should look like,
private TreeNode insert (TreeNode root, int val){
if (root == null){
return new TreeNode(val);
}
if (val == root.val){
//if you don't want to add repeats in the tree, then
//add your own code to deal with that here
//although as it stands now, this code will not add repeats
}
if (val < root.val){
root.left = insert(root.left, val);
}
if (val > root.val){
root.right = insert(root.right, val);
}
return root;
}

Reversing first K nodes of Linked List,Why recursion executing twice for last iteration

While solving the problem that reverse first K elements of linked list i have written the below recursive code but the last iteration executing twice i.e for k=1, function call reverseNode() happening twice. Can any body why it happening like that. Please correct me if i did any thing wrong in it.
Example :
If input is
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
and k = 4 then output is
4 -> 3 -> 2 -> 1 -> 5 -> 6 -> 7 -> 8
public void reverseListRecursion(int k) {
this.reverseNode(null, headNode,k);
}
public void reverseNode(Node node, Node nextNode,int k) {
while (k > 0) {
k = k-1;
this.reverseNode(node, nextNode.next,k);
}
if (k == 0) {
this.kNode = nextNode;
this.kNode.next = null;
}
if (node == null) {
nextNode.next = this.kNode;
} else {
nextNode.next = node;
}
}
Working code for my logic it is working expected. but when i try to use variable "k" in "if" condition instead of "presentCounter" then it is going wrong. Can any body tell me the reason.
public void reverseListRecursion(int count) {
this.reverseNode(null, headNode, count);
System.out.println("\n");
this.display(this.headNode);
}
/*
* Condition K <= Length of linked list.
*/
public void reverseNode(Node node, Node nextNode, int k) {
int presentCounter = k;
if (k > 1) {
k = k - 1;
this.reverseNode(nextNode, nextNode.next, k);
}
if (presentCounter == 1) {
this.kNode = nextNode.next; // Saving K's Next Node
this.headNode = nextNode; // Setting K node as head node
}
if (node == null) {
nextNode.next = this.kNode;
} else
nextNode.next = node;
}
Your recursion should be
if (k > 0) { // and not while
k = k-1;
this.reverseNode(node, nextNode.next,k);
}
...
There are several issues with this code you provided in your question:
public void reverseListRecursion(int k) {
this.reverseNode(null, headNode,k);
}
public void reverseNode(Node node, Node nextNode,int k) {
while (k > 0) {
k = k-1;
this.reverseNode(node, nextNode.next,k);
}
if (k == 0) {
this.kNode = nextNode;
this.kNode.next = null;
}
if (node == null) {
nextNode.next = this.kNode;
} else {
nextNode.next = node;
}
}
The wile loop will make the number of recursive calls grow to k!. Maybe this was your intention, but it certainly would not make an efficient algorithm. The job can be done by moving k-1 nodes, so making k! calls is not so efficient.
The first argument (node) never changes: the recursive call just passes the same argument, and so the value you pass in the initial call (null) is what this argument will be in every call. The outcome of the last if condition will therefore always be the same. This doesn't look right.
The first if condition will always be true, because it is opposite to the while condition that precedes it. So there should be no need to make the test for k == 0.
The code within the first if block makes this.kNode a synonym for nextNode and then its next property is set to null. There should be no reason at all to set any next property to null. If anything, it will break the linked list.
In the second if block the next property of nextNode is set to ... nextNode (see previous point, which shows that this.kNode was made synonymous for nextNode). So now you have a self-referencing node, which really is something you'd never want to have. This code makes the first k+1 nodes self-referencing, thereby effectively detaching them from the original linked list.
The initial call is made with headNode as second argument. This variable is apparently a private member of the class you are in. However, after execution the reversal, headNode will still reference the node it referred to before the call. The name suggests it should point to the first node in the list, but since the reversal will move another node at the front, headNode will point to the wrong node after completion. There is no other variable or property you have that will point to the first node in the list after the reversal. this.kNode could have been it, but the statements this.kNode.next = null and nextNode.next = this.kNode are not things you would do with the first node of a list.
There are too many issues with this code to get a clear view on what you actually tried to do.
I would suggest to go for this algorithm, explained by example:
list = 1 2 3 4 5 6 7 8
k = 4
Move the node that follows the original first node to the head of the list
list = 2 1 3 4 5 6 7 8
k = 3
Move the node that follows the original first node to the head of the list
list = 3 2 1 4 5 6 7 8
k = 2
Move the node that follows the original first node to the head of the list
list = 4 3 2 1 5 6 7 8
k = 1
As k = 1 no more moves have to be made.
This is how your code would look:
public void reverseListRecursion(int k) {
// The reversal returns the node that took the first position
this.headNode = this.reverseNode(this.headNode, k, this.headNode);
};
public Node reverseNode(Node origFirstNode, int k, Node currFirstNode) {
// If 1 element needs to be reversed, there is nothing to do:
if (k <= 1) return currFirstNode;
// Move the node after the original first node before the current first node
Node movingNode = origFirstNode.next;
origFirstNode.next = movingNode.next;
movingNode.next = currFirstNode;
// The moved node is now the current first node. Repeat:
return this.reverseNode(origFirstNode, k-1, movingNode);
};
The nice thing about this solution is that the reverseNode method does not need to reference this.headNode, and so it can be used to reverse elements in the middle of the list as well. You could add this method which takes a node as second argument:
public void reverseListRecursionAfter(int k, Node afterNode) {
afterNode.next = this.reverseNode(afterNode.next, k, afterNode.next);
};
This will reverse the nodes following the given node.
Here is a live snippet, with the same code translated to JavaScript (just for demo):
// Node class
function Node(val, next) {
this.val = val;
this.next = next;
this.toString = function (cascade) {
if (!cascade || this.next === null) return '(' + this.val + ')';
if (this.next === this) return '(' + this.val + ')-loop';
return '(' + this.val + ')->' + this.next.toString(true);
}
}
// List class
function List() {
this.headNode = null;
this.reverseListRecursion = function(k) {
// The reversal returns the node that took the first position
this.headNode = this.reverseNode(this.headNode, k, this.headNode);
};
this.reverseNode = function(origFirstNode, k, currFirstNode) {
// If 1 element needs to be reversed, there is nothing to do:
if (k <= 1) return currFirstNode;
// Move the node after the original first node before the current first node
var movingNode = origFirstNode.next;
origFirstNode.next = movingNode.next;
movingNode.next = currFirstNode;
// The moved node is now the current first node. Repeat:
return this.reverseNode(origFirstNode, k-1, movingNode);
};
this.insert = function (arr) {
for (var i = arr.length - 1; i >= 0; i--) {
this.headNode = new Node(arr[i], this.headNode);
}
}
this.toString = function () {
return '{' + this.headNode.toString(true) + '}';
}
}
var output = [];
// Sample data
var list = new List();
list.insert([1, 2, 3, 4, 5, 6, 7, 8]);
output.push('before: ' + list);
// Make the reversal call
list.reverseListRecursion(4);
output.push('after: ' + list);
// Show result in snippet
document.write(output.join('<br>'));

Size of a binary tree with non recursive method Java

Hello I'm trying to write a non recursive method for getting the size of a node since recursion in Java is expensive. This would include the number of child nodes + 1 (itself). I've converted an C implementation How can I get number of leaf nodes in binary tree non-recursively? in to Java but it's not correct.
Edit: algorithm for counting the size of binary tree, non recursively.
public int size(Node n) {
Stack<Node> sizeStack = new Stack();
int count = 1;//includes the n node
if(n == null) {
return 0;
}
sizeStack.push(n);
while(!sizeStack.isEmpty()){
node = sizeStack.pop();
while(node != null) {
count++;
if(node.right != null){
sizeStack.push(node.right);
}
node = node.left;
}
}
return count;
}
Your algorithm is counting leaf nodes. Your own wish was to count all the nodes. An algorithm for counting leaf nodes only adds to the counter when it pops a leaf node, and that's true both for Java and for C. So actually your program is good - but not for the problem you have defined.
In order to count all the nodes, you have to increment the counter every time you pop a node from the stack. This means you have to push all the nodes, rather than loop the way you have for the leaf nodes.
If you want to save on push operations (which is the only reason why this algorithm will be better than recursion, unless the tree is unbalanced towards the right) you should just increment the counter for every node that you are examining, but keep the basic loop as it was.
public int size(Node n) {
Stack<Node> sizeStack = new Stack();
int count = 1;//includes the n node
if(n == null) {
return 0;
}
sizeStack.push(n);
while(!sizeStack.isEmpty()){
node = sizeStack.pop();
while(node != null) {
count++;
if(node.right != null){
sizeStack.push(node.right);
}
node = node.left;
}
}
return count;
}
Here is a C implementation. RealSkeptic's method above was not that intuitive to me. I provide comments and it should be pretty easy to follow.
int sizeOfBsTree_nonRec(TreeNode *root)
{
if (root == NULL) {
return 0;
}
int size = 0;
Stack S;
initializeStack(&S);
// Push to the stack all Nodes in the (sub)tree and
// increase the counter when you pop one out
push(root, &S);
while(!isStackEmpty(&S)){
root = pop(&S);
size++;
if (root->right != NULL)
push(root->right, &S);
if (root->left != NULL)
push(root->left, &S);
}
return size;
}

Using a recursive method to find the smallest element in a subtree given the root: what am I doing wrong here?

So I have a homework question where I'm supposed to use a recursive method to "find the minimum element within a subtree rooted at the specified node"
And then I'm given this as my starting point:
public TreeNode
{
int data;
TreeNode left;
TreeNode right;
}
and
/**
Finds the minimum value for the subtree that is
rooted at a given node
#param n The root of the subtree
#return The minimum value
PRECONDITION: n is not null.
*/
int min(TreeNode n)
{
// COMPLETE THE BODY OF THIS METHOD
}
Now, I've got a very basic driver program written to insert nodes into the tree and I've written my recursive method, but it seems to be counting up instead of down, here's my method:
int min(TreeNode n){
if(n.left != null) {
n = n.left;
min(n);
System.out.println("N is now " + n.value);
}
return n.value;
}
Output of my code:
Building tree with rootvalue 25
=================================
Inserted 11 to left of node 25
Inserted 15 to right of node 11
Inserted 16 to right of node 15
Inserted 23 to right of node 16
Inserted 79 to right of node 25
Inserted 5 to left of node 11
Inserted 4 to left of node 5
Inserted 2 to left of node 4
Root is 25
N is now 2
N is now 4
N is now 5
N is now 11
The minimum integer in the given nodes subtree is: 11
Can someone please explain to me why this doesn't work?
Note: this is all assuming you're in a Binary Search Tree, so returning the minimum element means returning the left-most element.
This means your recursive call is quite simple:
min(node):
if this node has a left node:
return min(node.left)
if this node does not have a left node:
return this node's value
The logic is that if we don't have another left node then we are the left-most node, so we are the minimum value.
Now, in Java:
int min(TreeNode n){
if (n.left == null)
return n.value;
return min(n.left); // n.left cannot be null here
}
Now to explain your results, consider how this method works. It calls the method on the next node (min(n.left)) before continuing. In your case you had a println after this recursive call. Therefore the println inside the recursive call went first. So your prints started at the bottom of the tree and worked their way back up. This explains the "reverse order" printing.
Your method then returned 11 as your result because (as another answer has explained) your n = n.left didn't affect any of your recursive sub-calls, only the one in the current function call. This means you returned the left node of the root, rather than the furthest left child.
I hope this makes sense. If you need clarification on anything leave a comment or something. Recursion can be quite tricky to get your head around at first.
The issue is that Java is call-by-value, not by reference -- although references are passed by value. But what that really means in this case is that the call to min(n) does not change what the variable n refers to -- it doesn't do anything at all. What you should probably be doing is return min(n).
public static void main(String[] args) throws IOException, NoSuchMethodException, InitializationError {
Logger.getRootLogger().addAppender(new ConsoleAppender(new SimpleLayout(), "System.out"));
Logger.getRootLogger().setLevel(Level.ALL);
TreeNode n1 = new TreeNode();
TreeNode n2 = new TreeNode();
TreeNode n3 = new TreeNode();
TreeNode n4 = new TreeNode();
TreeNode n5 = new TreeNode();
TreeNode n6 = new TreeNode();
n1.data = 110;
n1.left = n2;
n1.right = n3;
n2.data = 15;
n2.left = n4;
n2.right = null;
n3.data = 3;
n3.left = null;
n3.right = null;
n4.data = 4;
n4.left = null;
n4.right = n5;
n5.data = 12;
n5.left = n6;
n5.right = null;
n6.data = 19;
n6.left = null;
n6.right = null;
System.out.print("min=" + min(n1));
}
static public class TreeNode {
int data;
TreeNode left;
TreeNode right;
}
static int min(TreeNode n) {
return min(n, n.data);
}
static int min(TreeNode n, int min) {
System.out.println("N is now " + n.data);
int currentMin = min;
if (n.left != null && n.right != null) {
final int left = min(n.left);
final int right = min(n.right);
if (left < right) {
currentMin = left;
} else {
currentMin = right;
}
} else if (n.left != null) {
currentMin = min(n.left);
} else if (n.right != null) {
currentMin = min(n.right);
}
if (currentMin < min) {
return currentMin;
} else {
return min;
}
}
OUTPUT is:
N is now 110
N is now 15
N is now 4
N is now 12
N is now 19
N is now 3
min=3
You need to use some tree traversal algoritm, for checking every node of the tree. Also you need to store current finded minimum. Pass this minimum into recursive function. It is calling "accumulator".
The last statement in your method implementation returns the node n's value. As n starts with the root and is replaced by its left child (if exists) you always get the value of the root's left child.
The following code should do it:
int min(final Tree n){
int result;
if(n == null){
result = Integer.MAX_VALUE;
} else {
result = n.value;
final int leftResult = min(n.left);
if(leftResult < result){
result = leftResult;
}
final int rightResult = min(n.right);
if(rightResult < result){
result = rightResult;
}
}
return result;
}
Or you could use the Visitor pattern (you would need to make your tree Iterable then and pass the values to the Visitor one-by-one):
interface TreeVisitor {
void accept(int value);
}
class MinTreeVisistor implements TreeVisitor {
int min = Integer.MAX_VALUE;
#Override
public void accept(int value) {
if(value < this.min) {
this.min = value;
}
}
}

Swapping adjacent elements of a linked list algorithm

I am practicing linked list programming questions in java, i have a working solution for the following question but cannot understand how it works.
I have commented beside each line what I think should be happening but obviously I haven't grasped how these are working yet, could someone please explain where my comments are wrong and how this solution is correct.(in my comments i use h for head, s for slow etc.)
Given a linked list, swap every two adjacent nodes and return its head.
Example:
Given 1->2->3->4, you should return the list as 2->1->4->3.
public Node s(Node head) {
// 1(h)-2-3-4 passed in
// if only 1 node or null node return it
if (head == null || head.next == null) {
return head;
}
Node slow = head.next; // 1h-2s-3-4
head.next = head.next.next; // 1h-3-4
slow.next = head; // 2s-1h-3-4
head = slow; // 2s/h-1-3-4
Node parent = slow.next; // 1p-3-4
slow = slow.next.next; // 3s-4
while (slow != null && slow.next != null) {
Node temp = slow.next; // 4t-null
slow.next = slow.next.next; // 3s-null
temp.next = slow; // 4t-3s-null
parent.next = temp; // 1p-4-3
parent = parent.next.next; // 3p=null
slow = slow.next; // 4-null, loop ends cause next to slow is null
}
return head; // ( head = slow from earlier) 4-null
}
Let's assume a linked list of A -> B -> C -> D.
I've numbered the lines in your code to make it easier to talk about.
1 public Node s(Node head) {
2 // if only 1 node or null node return it
3 if (head == null || head.next == null) {
4 return head;
5 }
6
7 Node slow = head.next;
8 head.next = head.next.next;
9 slow.next = head;
10 head = slow;
11 Node parent = slow.next;
12 slow = slow.next.next;
13
14 while (slow != null && slow.next != null) {
15 Node temp = slow.next;
16 slow.next = slow.next.next;
17 temp.next = slow;
18 parent.next = temp;
19 parent = parent.next.next;
20 slow = slow.next;
21 }
22 return head;
23 }
At line 7, slow is made to point to node B. head.next is set to B's successor, C on line 8. On line 9, B points to A, and on line 10, head points to B. My comments show what happened.
7 Node slow = head.next; // slow = B
8 head.next = head.next.next; // head.next = C
9 slow.next = head; // B.next = A (because head points to A)
10 head = slow; // head = B
That code swapped the first two nodes. Your list now looks like this:
B -> A -> C -> D
Now the code gets kind of confusing, largely due to poor naming. slow currently points to B.
11 Node parent = slow.next; // parent = A
12 slow = slow.next.next; // slow = C
Remember that slow now points to C. Here's what happens next:
14 while (slow != null && slow.next != null) {
15 Node temp = slow.next; // temp = D
16 slow.next = slow.next.next; // C.next = D.next (which is null)
17 temp.next = slow; // D.next = C
18 parent.next = temp; // A.next = D
At this point, nodes C and D have been swapped, and A points to D, as required. The list now looks like B -> A -> D -> C.
The final two lines in the loop just set things up for next time. Remember, that right now, parent points to A.
19 parent = parent.next.next; // parent = C
20 slow = slow.next; // slow = null
Looping back to the top, we see that slow == null, so the loop exits.
Whereas the code you posted works, it's unnecessarily confusing. There's no need to do a special swap of the first two nodes before going into the loop, and variable names could be more descriptive.
To swap two nodes, you have to make the second point to the first, and the first point to the second's successor. To do that, you have to save the second's successor before you overwrite it. For example, if you have A -> B -> C and you want B -> A -> C, then you have to do this, assuming that head points to A:
firstNode = head // firstNode points to A
secondNode = firstNode.next // secondNode points to B
secondNodeSuccessor = secondNode.next // this points to C
secondNode.next = firstNode // B now points to A
firstNode.next = secondNodeSuccessor // A now points to C
head = secondNode // and head points to B
At this point, secondNodeSuccessor is pointing to C, which is the next firstNode.
With that understanding of how to swap nodes, you can simplify the code quite a bit:
public Node s(Node head) {
// if fewer than 2 nodes, return.
if (head == null || head == null) {
return head;
}
// we know that the new head will be the second node.
Node firstNode = head;
Node parentNode = null;
while (firstNode != null && firstNode.next != null) {
Node secondNode = firstNode.next;
Node secondNodeSuccessor = secondNode.next;
// swap the nodes
secondNode.next = firstNode;
firstNode.next = secondNodeSuccessor;
if (parentNode != null) {
// This links the previous node (the one right before
// the two that we just swapped) to the swapped nodes.
parentNode.next = secondNode;
}
// the new parent node is the last swapped node.
parentNode = firstNode;
firstNode = firstNode.next; // set up for next pair
}
return head.next;
}
Note the improvements here:
I eliminated the special-case swap of the first two nodes, which simplifies things by making every swap the same.
Meaningful variable names make it plain which node I'm referencing.
Eliminating the .next.next construction makes it easier to reason about the code, and also makes it easier to determine whether the code could potentially dereference a null.
Your debugger is a very useful tool for understanding how your code is working. If you were to single-step the code in your debugger, you could examine the variables and see how each line of code affects the state. If you don't know how to use your debugger, you should take the time right now to learn. It will save you hours of debugging, and also greatly increase your understanding of how code works.
In place of swapping nodes, we can swap data only that will be easy and will get the desired output.
public Node s(Node head) {
if (head == null || head.next == null) {
return head;
}
Node temp = head;
/* Traverse only till there are atleast 2 nodes left */
while (temp != null && temp.next != null) {
/* Swap the data */
int k = temp.data;
temp.data = temp.next.data;
temp.next.data = k;
temp = temp.next.next;
}
return head;
}
The other two solutions either don't match your requirements or provide wrong results for some inputs.
I propose an alternative approach that I have tested on LeetCode (if you want to test it yourself, please be sure to rename the Node type into ListNode).
I hope the comments I added to the code are clear enough. When in doubt, I suggest trying to execute this procedure in an interactive debugger.
public ListNode s(Node head) {
// if the list is empty or it's a singleton, no node needs to be swapped
if (head == null || head.next == null) {
return head;
}
// first and second are the first and second node of the current pair to swap
Node first = head;
Node second = head.next;
// parent is the node immediately before the current pair.
// Initially, there is no such pair
Node parent = null;
// the updated list starts from the second node of the first pair
head = second;
// iterate until there is a valid pair to swap
while (first != null && second != null) {
// swap the two nodes of the current pair
first.next = second.next;
second.next = first;
if (parent != null) {
// attach the second element to the updated node of the previous pair
parent.next = second;
}
// keep the invariant of parent valid: parent precedes the new pair to swap,
// if such a pair exists
parent = first;
// advance the pointers of the first and second elements of the new pair to swap
first = first.next;
second = (first == null) ? null : first.next;
}
return head;
}

Categories

Resources