I'm trying to do a level order traversal on the following BST.
BST bst = new BST();
int [] arr = {12, 15, 7, 3, 81, 9, 36, 23, 33, 41, 4};
for (int i = 0; i <arr.length; i++) {
bst.add(arr[i]);
}
This is my code.
public static void levelOrderTraversal(Node root){
if(root == null) return;
Queue<Node> queue = new ArrayDeque<Node>();
queue.add(root);
while(!queue.isEmpty()){
Node current = queue.peek();
System.out.print(current.getData() + " ");
if (current.left != null)
queue.add(current.left);
if (current.right != null){
queue.add(current.right);
}
queue.poll();
}
}
The output that I get is
12 7 15 3 9 81 4 36 23 41 33
This clearly is not the correct BFS. Where am I going wrong.
Your traversal function is correct. You may want to check this online tool
https://www.cs.usfca.edu/~galles/visualization/BST.html
It provides visualization of the insert, delete and find process as well. This is the resulting tree:
I don't see why, given the list of elements you provide the tree will look like:
12
|- 7 (L)
|- 3 (L)
|- 4 (R)
|- 9 (R)
|- 15 (R)
|- 81 (R)
|- 36 (L)
|- 23 (L)
|- 33 (R)
|- 41 (R)
Or a better visual:
12
/ \
7 15
/ \ \
3 9 81
\ /
4 36
/ \
23 41
\
33
Note this is not a balanced binary search tree. A BST will simply create first a node 12 (first element you provide). And 12 will remain the root. All elements less than are sorted left (and start growing their own roots etc.)
Related
Thanks to all that answered my previous query, I have to be honest I really cannot get on with Google Apps Script :-(
What I am trying to do is relatively simple and for VBA on excel would be a doddle, but sheets is it's own beast I guess.
What I'd like to do is...
read in the form responses from a google form on the tab "Comments" Cells B2:H
Compare the unique key responses in column B on "Comments" with a unique key in A1 on tab "DashBoard"
If there are match I would like to add them onto the dashboard tab in Cells G3:M20
This would ultimately refresh everytime the dropdown in A1 on "Dashboard" is changed
The Data on responses is always 7 columns worth, varying from strings to dates. Sometimes G & H columns will be blank
Seriously any help is appreciated here, once I've got this done I don't have to touch Google Sheets anymore lol
function bnbm() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = SpreadsheetApp.getActive().getSheetByName("Comments");
var range = sheet.getRange("Comments!B2:H");
var values = range.getValues();
var values2 = values.filter(String);
var range2 = sheet.getRange("Dashboard!A1")
var rowd = range2.getValues();
var rowd2 = rowd.filter(String);
var result = sheet.getRange("Dashboard!G3:M20")
for (var i = 0; i < values2.length; i++) {
if (values2[i][0] == rowd2[0][0]) {
result.setValues(values2[i][1])
}
}
}
I don't think that your result array can be a fixed length since you Comment goes down sh.getLastRow() so this is what I think you want:
Using ranges like B2:H is not a good idea in Apps Script because they generate a lots of null data at the end of the range which has to be filtered out.
function bnbm() {
const ss = SpreadsheetApp.getActive();
const csh = ss.getSheetByName("Comments");
const dsh = ss.getSheetByName('Dashboard');
const vs = csh.getRange(2, 2, csh.getLastRow() - 1, 7).getValues();
const A1 = dsh.getRange("A1").getValue();
let oA = [];//matches array
for (let i = 0; i < vs.length; i++) {
//if column B Comments = Dashboard A1
if (vs[i][0] == A1) {
oA.push(vs[i]);//save current row in matches array
}
}
if ((dsh.getLastRow() - 2) > 0) {
dsh.getRange(3, 7, dsh.getLastRow() - 2, 7).clearContent();//clear contents if any
}
if (oA.length > 0) {
dsh.getRange(3, 7, oA.length, oA[0].length).setValues(oA);//move matches to dashboard
ss.toast(`${oA.length}`, 'Matches');//number of matches
} else {
ss.toast('No Matches', 'Matches', 10);//no matches
}
}
Sample Comment Data Set:
COL1
COL2
COL3
COL4
COL5
COL6
COL7
COL8
24
21
9
24
16
7
12
13
12
19
9
19
20
7
11
18
19
18
6
1
19
16
1
16
2
0
4
19
8
12
8
20
19
19
8
24
8
0
1
18
22
6
9
2
17
18
5
20
22
13
7
1
9
15
24
14
20
7
8
21
11
2
10
22
4
11
12
21
13
6
9
22
12
19
23
6
8
9
5
12
3
18
11
17
7
12
3
22
19
19
11
3
13
15
4
12
23
1
10
16
20
11
5
20
17
20
14
13
4
13
15
1
Results for Dashboard A1 = 19;
19
19
9
19
20
7
11
18
19
8
24
8
0
1
18
19
23
6
8
9
5
12
19
11
3
13
15
4
12
19
24
13
11
9
19
9
With the addition of this function bnbm will run every time you make an edit in A1 of sheet Dashboard.
function onEdit(e) {
//e.source.toast('entry');
const sh = e.range.getSheet();
if(sh.getName() == 'Dashboard' && e.range.rowStart == 1 && e.range.columnStart == 1 && e.value) {
bnbm();
}
if(sh.getName() == "Dashboard" && e.range.rowStart == 1 && e.range.columnStart == 1 && e.value == null) {
e.source.toast('Invalid Input','Error Message');
}
}
The easiest way I've found to run this is to enter data into A1 (user edits only) and then click on another cell. Hitting enter will not data just forces the focus back into the empty cell and does not complete the edit.
I'm trying to recursively populate a tree with integers (as shown in the link below). But I don't understand how to solve the inductive step using recursion.
PS. I have already created the recursive function to calculate the binomial coefficient
Thank you in advance!
The math notation in the picture at the link is a little obscure. But you want to implement that almost exactly. It's saying this:
Node buildTree(n) {
Let tree be a new Node (with no children)
For i from 0 to n - 1
Let b = binomial(n, i)
for b times:
Add buildTree(i) as a child of tree
return tree
}
The obscure part is that multiplication by some integer k in this "tree math" means "repeat the graph k times," and the summation means "add all as children" to an implicit parent node. This parent is the value of the expression.
Here's a development hint. Store a unique integer in each node as a label. Once you get that working, then write a little tree walker that prints out DOT language. When I did that for n=3, I got:
graph {
0 -- 1
2 -- 3
0 -- 2
4 -- 5
0 -- 4
6 -- 7
0 -- 6
8 -- 9
10 -- 11
8 -- 10
12 -- 13
8 -- 12
0 -- 8
14 -- 15
16 -- 17
14 -- 16
18 -- 19
14 -- 18
0 -- 14
20 -- 21
22 -- 23
20 -- 22
24 -- 25
20 -- 24
0 -- 20
}
You can see what that looks like by using online GraphViz here.
Pseudocode to illustrate recursive step
TreeNode getRootOfSomeFancyTree(n)
TreeNode root = new TreeNode()
if(n == 1) return root
else for(i = 0; i < n; i++)
//not sure of correct way to multiply an integer by a tree in your application
int x = binomialCoefficient(n, i) * i
//anyway, recurring is easy and safe provided x < n
TreeNode subTree = getRootOfSomeFancyTree(x)
//build the tree
root.addChild(subTree)
endfor return root
I have a binary tree
as a function input I have tree root and 2 nodes
I need to calculate the sum along the path between the two given nodes.
A tree example:
4
/ \
8 13
/ \
24 45
Code:
List<Node> findPath(root, target):
if (root !=null)
return
if root == node{
return nodes.add(target)
}
path = findPath(root.left, target)
if (path !=null){
return nodes.add(root).addAll(path)
}
path = findPath(root.right, target)
if (path!=null)
return nodes.add(root).addAll(path)
I don't know what is the next step if I have paths to target nodes how should I calculate optimal way?
Input: sumTree(4, 24, 45)
Output: 8 + 24 + 45 = 77
Input: sumTree(4, 24, 13)
Output: 13 + 4 + 8 + 24 = 49
Input: sumTree(4, 4, 13)
Output: 4 + 13 = 17
Input: sumTree(4, 45, 45)
Output: 45
Language is JAVA but language doesn't matter unless I understand the syntax
I just want to have optimal solution.
Is it possible to provide some pseudocode?
Your two paths will have the same prefix (at least the root should be there).
You need to remove the common prefix and add only the last (deepest) common node (once). For the parts that are different you need to add all the values. This should be O(N) complexity, and in-line with the rest of the solution.
Your search algorithm is not efficient because you keep copying the values from one list to the other (O(N^2) if you don't have any constraints on the tree). If you modify it to build the response in place it should become O(N).
The program has an input a list of doubles and the output needs to be a string containing the list values grouped by their value. The list values will be grouped if they are equal.
Something like:
input 9,77,5,5,31 => output 9 77 2*5 31
I created an algorithm in C# (in Java I think that is almost the same) for this but I am not sure if it can be improved regarding its speed or code quaility, or if it has some bugs that I could not see. The algorithm having also some more input, output examples is below.
List<double> input = new List<double> { 11, 32, 32, 43}; // output 11 2*32 43
//List<double> input = new List<double> { 11, 11, 43, 43 }; // output 2*11 2*43
//List<double> input = new List<double> { 10, 11, 12, 13, 14, 15, 16 }; // output 10 11 12 13 14 15 16
//List<double> input = new List<double> { 11, 11, 11, 11, 11 }; // output 5 * 11
//List<double> input = new List<double> { 11, 11, 32, 22, 22, 22, 4, 10, 10 }; // output 2*11 32 3*22 4 2*10
string listAsString = string.Empty;
double nextElem = double.MinValue;
for (int i = 0; i < input.Count; i++)
{
double currentElem = input[i];
if (i + 1 < input.Count)
{
nextElem = input[i + 1];
}
int equalCount = 0;
while (currentElem.Equals(nextElem) && i < input.Count)
{
equalCount++;
i++;
currentElem = nextElem;
if (i < input.Count)
{
nextElem = input[i];
}
}
if (equalCount < 2)
{
listAsString += currentElem + " ";
}
else
{
listAsString += equalCount + "*" + currentElem + " ";
i--;
}
}
Console.WriteLine(listAsString);
Please let me know if you noticed some bugs or see some improvements that can be done.
Also if you know another implementation of this requirement please add it so that a comparation regarding results, speed, code quality between the algorithms can be done... and find the best way to handle this.
Since the requirement is to group only consecutive equal values, the Dictionary and LINQ GroupBy approaches mentioned in another answer do not apply because they will produce incorrect result for input sequence like 1,2,1. Also there is no standard LINQ method for doing such grouping (except eventually Aggregate method, but it's no more than inefficient for / foreach loop equivalent).
Shortly, your algorithm is the best for such task. But implementation is not.
The main bottleneck is the string concatenation as mentioned by Peroxy, which (also mentioned in the other answer) is easily fixable by utilizing the StringBuilder class. Once you do that, the performance will be just fine.
The other issue I see in the implementation is usage of special values (double.MinValue), duplicate corner case checks, decrementing for loop variable inside the body etc. So although it probably works and I don't see directly a bug, it's kind of hard to follow the algorithm logic and spot a potential bug just reading the implementation. The algorithm itself is quite simple, I would implement it this way:
static string ListAsString(List<double> input)
{
var sb = new StringBuilder();
for (int i = 0; i < input.Count; )
{
var value = input[i];
int count = 1;
while (++i < input.Count && input[i] == value)
count++;
if (sb.Length > 0) sb.Append(' ');
if (count > 1) sb.Append(count).Append('*');
sb.Append(value);
}
return sb.ToString();
}
which IMO is quite easier to follow. Note that there is no duplicate code, no special values and the loop variable i advancing is done only in one place inside the outer loop body. Again, this has nothing to do with performance (which is provided by the StringBuilder usage), but simply readability, redundancy elimination and less error prone.
Personally, I see great potential with Dictionary usage here, here is a quick solution I made with a dictionary implementation:
var input = new List<double> { 9, 77, 5, 5, 31 };
var dict = new Dictionary<double, int>();
var listAsString = new StringBuilder();
foreach (var item in input)
{
if (dict.ContainsKey(item))
dict[item]++;
else
dict[item] = 1;
}
foreach (var item in dict)
{
listAsString.Append(item.Value > 1 ? $"{item.Value}*{item.Key} " : $"{item.Key} ");
}
Console.WriteLine(listAsString);
If you ever wanted a non efficient LINQ one liner solution:
string result = string.Join(" ", input.GroupBy(i => i)
.Select(x =>
x.Count() > 1 ?
$"{x.Count()}*{x.Key} " :
$"{x.Key} "));
However, I believe your method is written nicely, albeit a bit less readable than the dictionary one, but the main flaw with your solution is that you are using a string when building the final string, you should definitely be using a StringBuilder, I have introduced the StringBuilder in your method and made comparisons between these three methods:
Dictionary | Your method | GroupBy method
------------------------------------------------
2 ms | 0 ms | 5 ms n=3
0 ms | 0 ms | 0 ms n=6
0 ms | 0 ms | 0 ms n=12
0 ms | 0 ms | 0 ms n=24
0 ms | 0 ms | 0 ms n=48
0 ms | 0 ms | 0 ms n=96
0 ms | 0 ms | 0 ms n=192
0 ms | 0 ms | 0 ms n=384
0 ms | 0 ms | 0 ms n=768
0 ms | 0 ms | 0 ms n=1536
1 ms | 0 ms | 1 ms n=3072
3 ms | 2 ms | 3 ms n=6144
5 ms | 4 ms | 6 ms n=12288
8 ms | 7 ms | 14 ms n=24576
14 ms | 13 ms | 25 ms n=49152
31 ms | 32 ms | 66 ms n=98304
80 ms | 59 ms | 146 ms n=196608
149 ms | 123 ms | 294 ms n=393216
246 ms | 218 ms | 504 ms n=786432
483 ms | 428 ms | 1040 ms n=1572864
999 ms | 873 ms | 2070 ms n=3145728
1995 ms | 1784 ms | 3950 ms n=6291456
Your solution is always the fastest, if you want to go for speed, keep your solution, but change it to use StringBuilder, use listAsString.Append(currentElem + " ") instead of listAsString += currentElem + " ".
GroupBy could be used if you will only operate with collections that have n < 1000, use the Dictionary solution if you would rather settle with readability over speed.
I am working on writing red-black tree myself. But when I test the rotation that involves root to be rotated, somewhat it loses reference.
Tree structure:
45
/ \
40x 70
/ \ /
7 41 50
/ \
6 39
The rotate logic says:
"Rotate with 45(root) as top, in the direction that raises X (i.e. 40)"
So this means right rotate and result should look like:
40x
/ \
7 45
/ \ / \
6 39 41 70
/
50
Assuming that node 45 is grandparent and 7 is parent and 41 is current. (I know the order doesn't make sense but please ignore, this is because I've rotated once already)
Code:
//current is node 45
//parent is node 7
//grandparent is node 45 (root)
//first detach cross node (i.e. 41)
Node crossNode2 = grandparent.left.right;
grandparent.left.right = null; //detach
45
/ \
40x 70
/ \ /
7 null 50
/ \
6 39
grandparent.left = null;
45
/ \
null 70
/
50
current.right = grandparent;
40
/ \
7 45
/ \ / \
6 39 null 70
/
50
grandparent.left = crossNode2; //attach
40
/ \
7 45
/ \ / \
6 39 41 70
/
50
But somehow this code does not work. When I tested:
preorder
45, 39, 70, 50
breadth-first
45, 39, 70, 50
So I think the result is actually:
45
/ \
39 70
/
50
Could anyone give me tips what's wrong with my rotation code?
Step to do a right rotation on node Q:
Let P = Q's left child.
Q's left child = P's right child
P replaces Q as its parent's child
P's right child = Q
You're missing the bolded step in your supplied code. I think your problem is you're treating rotations involving the root node as a special case. Obviously you can't do this if Q is the root and its parent is null. Try creating a "head" node who's right node is the root. This allows rotations involving the root to work using normal algorithms.
public static void rotateRight(Node node) {
assert(!node.isLeaf() && !node.left.isLeaf());
final Node child = node.left;
node.setLeft(child.right);
if (node.isRightChild())
node.parent.setRight(child);
else node.parent.setLeft(child);
child.setRight(node);
}
Node that setRight and setLeft keep the parent reference updated as well as updating right and left. The node.isRightNode() call can be just (node.parent.right == node).
Based on Gunslinger47's answer, I've tested left rotation version too.
The code works fine. (please do let me know if not..)
Also documented on my website :)
http://masatosan.com/btree.jsp
public static void rotateLeft(Node node) {
assert(!node.isLeaf() && !node.right != null);
final Node child = node.right;
node.setRight(child.left);
if(node.isLeftChild()) {
node.parent.setLeft(child);
}
else {
node.parent.setRight(child);
}
chlid.setLeft(node);
}