How to minimize visual width of (binary) search tree? - javascript

Introduction
I'm building an HTML5 web application that creates a visual representation of a binary search tree from a given list of numbers.
Currently, I have an algorithm which calculates the visual spacing between nodes on each row based on the maximum depth of the tree (which is a base-0 value):
offset = 50
offset *= pow(2, maxDepth - currentDepth)
From here, the position of the node is determined using this offset and the x-position of its parent.
The algorithm works well, because it's always able to accommodate for the widest-possible tree of any depth. However, this also makes the tree unnecessarily wide at times.
Examples
Tree branching to the left (too wide):
Tree branching to the left http://f.cl.ly/items/0c0t0L0L0o411h092G2w/left.png
Tree branching to both sides (left and right sides could be closer together).
Tree branching to both sides http://f.cl.ly/items/0r3X1j0w3r1D3v1V1V3b/left-right.png
Ideally, the above tree should be shaped like a pyramid, with a smaller width and with the sides straight, as depicted below:
Balanced tree (case where the algorithm works best):
Balanced tree http://f.cl.ly/items/203m2j2i3P1F2r2T3X02/balanced.png
Implementation
Properties
I'm using Backbone.js to create nodes from a Node model. Each node has the following properties:
parent (the parent node)
left (the left child node)
right (the right child node)
x (the x-position of the node in pixels)
y (the y-position of the node in pixels)
The x and y properties above are calculated based on the direction the node branches from:
if (parent.get('left') === node) {
x = parentX - offsetX;
y = parentY + offsetY;
} else if (parent.get('right') === node) {
x = parentX + offsetX;
y = parentY + offsetY;
}
At this point, the x and y properties are the exact values used to position the nodes (each is positioned absolute within a container element).
Methods
getDepth() (returns the base-0 depth of a node)
getMaxDepth() (returns the depth of the last row in the tree)
getRow(n) (returns an array of all nodes at depth-n)
Question
Therefore, my question is simple:
What is the best algorithm to minimize the aesthetic width of my binary tree?

It could help you if you looked at the answers given to a similar question; they contain links to software doing exactly the kind of tree visualization that you want.
Aesthetics is highly subjective, so this is just my opinion. I think my guidelines (not an algorithm) would be the following. I am assuming that the order of children is important (as these are binary search trees).
Only x coordinates are interesting; y coordinates should only be determined by the node's level. (I would find it rather ugly if this was violated but, as I said, tastes differ. However, the rest is based on this assumption.)
No nodes in the same level should be closer than some fixed minimum distance (say D).
If a node has two children at x1 and x2, I would prefer it to be placed at (x1+x2)/2. In some cases, it would be preferable to select some other coordinate in [x1..x2] (possibly one of its ends). I guess there could be unusual cases where a coordinate outside [x1..x2] would be preferable.
If a node has one child at x1 and its parent is at xp, I would prefer it to be placed at (x1+xp)/2 (so that it lies on the line connecting its parent to its child). In some cases, it would be preferable to deviate from this and select some other coordinate in [xp..x1] (or even outside).
Let's call width of a level the distance between the leftmost and the rightmost node. The width of the widest level should be minimal.
These guidelines impose constraints that cannot be satisfied all at the same time. Therefore, you should prioritize them, and this is again subjective. E.g., what's more important, #4 or #5? Your sketch for the 5-node tree implies that #4 is more important; if #5 was more important you'd get a house-like picture (vertical lines); if both were important, then your current result would be fine.
One way to tackle this is by assigning weights to the guidelines and define penalties if these are not followed. E.g., in guideline #3, you could and penalize with abs(x-(x1+x2)/2) if a parent is placed at x which is not halfway between its children; you could also assign a weight that tells you how important this is, in comparison with other guidelines. You should then try to minimize the total weighted penalty of the solution. In general, this would give you a constraint optimization problem and there are several ways to solve such problems.

You can use an AVL tree. These self-balance on insertion giving you a balanced tree after every insertion.
http://en.wikipedia.org/wiki/AVL_tree

Related

How to generate a circular nodemap in javascript?

How to generate a nodemap in the following manner?
The idea here is to fix the central node at the centre of the viewport and then create coordinates in a circular manner without overlapping and arrange each nodes to corresponding position. This is level 1.
Then we proceed to level two where each child nodes with children becomes level two. There also we generate coordinates in circular manner without overlapping and arrange those child nodes in level two.
Likewise we proceed to subsequent levels.
NOTE note that overlapping should be prevented and also minimum possible radius should be used for circular arrangement. (i.e. without any collision)
Each node has it's own dimensions (length and breadth)
This is what I've tried out
function getCircularAngles(points) {
return [...Array(points).keys()].map(
(num) => num * ((Math.PI * 2) / points)
);
}
function getCoorByAngle(
origin,
angle,
radius
) {
return {
x: origin.x + Math.sin(angle) * radius,
y: origin.y + Math.cos(angle) * radius,
};
}
function getCircularCoords(
origin,
points,
radius
) {
return getCircularAngles(points).map((angle) =>
getCoorByAngle(origin, angle, radius)
);
}
But this is not being able to generate the circular coordinates recursively.
(i.e. by traversing through the child nodes / connections) & also this is not preventing collisions.
SO I need a better way to permute nodes without colliding in a circular manner recursively
I cant use any graphing libraries because the boxes I create are custom svg... I don't think 3rd party libraries are going to support custom svg elements. Need an algorithm in vanilla js.
For the best end result you may want to look into force-directed graph drawing techniques. Basically you run a physics simulation on your graph and it just sorts itself out. Many libraries already do this, including the very popular d3.js (which supports SVG, btw).
Otherwise, you can try doing exactly as you say: start laying out nodes level by level, pre-calculating the minimum radius required to avoid overlap. The problem comes when you've got a big graph. Let's say you have two adjacent nodes that both have a lot of children. You can push one of them out really far from the center so the children of each node don't touch, but a more ideal solution would have those two nodes at opposite sides of your graph. If you're wanting that you'll either need to use a force-directed graph, or else try many permutations and settle on the best one.
You might like to experiment with the GraphViz open-source language tool to see how it decides to plot your diagram.
GraphViz uses a language to describe relationships, then calculates a graph layout by various algorithms which they actually discuss at some length. (Could it be that you could use GraphViz to accomplish this task entirely?)
GraphViz web site

Higher precision in JavaScript

I am trying to calculate with higher precision numbers in JavaScript to be able to zoom in more on the Mandlebrot set.
(after a certain amount of zooming the results get "pixelated", because of the low precision)
I have looked at this question, so I tried using a library such as BigNumber but it was unusably slow.
I have been trying to figure this out for a while and I think the only way is to use a slow library.
Is there a faster library?
Is there any other way to calculate with higher precision numbers?
Is there any other way to be able to zoom in more on the Mandlebrot set?
Probably unneceseary to add this code, but this is the function I use to check if a point is in the Mandlebrot set.
function mandelbrot(x, y, it) {
var z = [0, 0]
var c1 = [x, y]
for (var i = 0; i < it; i++) {
z = [z[0]*z[0] - z[1]*z[1] + c1[0], 2*z[0]*z[1] + c1[1]]
if (Math.abs(z[0]) > 2, Math.abs(z[1]) > 2) {
break
}
}
return i
}
The key is not so much the raw numeric precision of JavaScript numbers (though that of course has its effects), but the way the basic Mandelbrot "escape" test works, specifically the threshold iteration counts. To compute whether a point in the complex plane is in or out of the set, you iterate on the formula (which I don't exactly remember and don't feel like looking up) for the point over and over again until the point obviously diverges (the formula "escapes" from the origin of the complex plane by a lot) or doesn't before the iteration threshold is reached.
The iteration threshold when rendering a view of the set that covers most of it around the origin of the complex plane (about 2 units in all directions from the origin) can be as low as 500 to get a pretty good rendering of the whole set at a reasonable magnification on a modern computer. As you zoom in, however, the iteration threshold needs to increase in inverse proportion to the size of the "window" onto the complex plane. If it doesn't, then the "escape" test doesn't work with sufficient accuracy to delineate fine details at higher magnifications.
The formula I used in my JavaScript implementation is
maxIterations = 400 * Math.log(1/dz0)
where dz0 is (arbitrarily) the width of the window onto the plane. As one zooms into a view of the set (well, the "edge" of the set, where things are interesting), dz0 gets pretty small so the iteration threshold gets up into the thousands.
The iteration count, of course, for points that do "escape" (that is, points that are not part of the Mandelbrot set) can be used as a sort of "distance" measurement. A point that escapes within a few iterations is clearly not "close to" the set, while a point that escapes only after 2000 iterations is much closer. That distance quality can be used in various ways in visualizations, either to provide a color value (common) or possibly a z-axis value if the set is being rendered as a 3D view (with the set as a sort of "mesa" in three dimensions and the borders being a vertical "cliff" off the sides).

Group nodes which are visually together

I am implementing force-directed graph in d3js.
I want to divide my graph into two halves and colour both the halves with different colour, after the network has been rendered and forceSimulation has completed.
What I am looking for is explained in image.
I am refering here.
I don't want to update the group field into my data as described in the link because my links are changing dynamically on several events which is also changing the orientation of the network and updating group field into the data is creating the groups of same nodes whether they are near or far from each other.
Currently, I am using the window coordinates to divide this.
const screenWidth = window.screen.availWidth;
const halfScreen = screenWidth / 2;
nodes.selectAll().attr("fill", function (d) {
return d.x < halfScreen ? "blue" : "green";
});
But this is not the good idea. I would love to know any other way that is possible to do this.
So, my, interpretation of your question: you want to divide the nodes into two groups. Preferably each with half of the nodes, in which the distances between the nodes in each group is as small as possible.
The best algorithms for this that I know of are algorithms for constructing a "minimum spanning tree", for example, Kruskal's algorithm.
Adapting the algorithm to your problem, you start with (a copy of) the graph, having no edges. You then add the edges, sorted by length, smallest first. You stop doing this as soon as you have exactly two connected components. These connected components form groups in which nodes have a small mutual distance.
However, the groups probably won't have the same number of nodes, and I don't guarantee that this gives you the smallest mutual distance.
EDIT:
If there is more than 1 connected component, you could group them by starting with two empty groups and repeatedly adding a component (largest first) to the group that has the smallest number of nodes. This will probably give you more or less equal groups.

Organizational system for moving tiles in grid-based level

conceptual problem here.
I have an array which will be rendered to display tiles in a grid. Now, I want these tiles to be able to move - but not just around in the grid. Per-pixel. It does need to be a grid, because I need to shift whole rows of tiles, and be able to access tiles by their position, but it also needs to have per-pixel adjustment, while still keeping the "grid" up to date. Picture a platforming game with moving tiles.
There are a few organizational systems with which I could do this, and I'll outline a few I thought of as well as their pros and cons (XY-style) in case it helps you understand what I'm saying. I'm asking if you think one of these is best, or think of a better way.
One way would be to place objects in the array with the properties xOffset and yOffset. I would then render them in their tile position plus their offset. (x * tileWidth + tile.xOffset). Pros: maintains vanilla grid-system. Cons: Then I would have to adjust each tile to its actual grid location once it moved. Also, the "grid" position would become a bit confused as tiles are moving. (Side note: If you think this is a good way, how would I handle collisions? It wouldn't be as simple as player.x / tileWidth anymore.)
Another would be to place lots of objects with xs and ys and render them all. Pros: Simple. Cons: Then I would have to check each one to see if it's in the row I want to shift before doing so. Also, collisions could not simply check the one tile a player is on, they would have to check all entities.
Another I thought of would be a sort of combination of the two. Tiles would be in the original array and get render as x * tileWidth normal tiles. Then, when they move, they are deleted from the grid and placed in a separate array for moving tiles, where their x and y are stored. Then the collisions would check the grid the fast way and the moving tiles the slow way.
Thanks!
PS: I'm using JavaScript, but it shouldn't be relevant.
PPS: Forgive me if it's not Stack Overflow material. This was the best fit, I thought. It's not exactly code review, but it's not specific to GameDev. Also I needed a tag, so I picked one somewhat relevant. If you guys recommend something else I'll be happy to switch it right over and delete this one.
PPPS: Sorry if repost, I have no idea how to google this question. I tried to no avail.
(Side note on handling collisions: Your obstacles are moving. Therefore, comparing the player's position to grid is no longer ever sufficient. Furthermore, you will always have to draw based on the object's current position. Both of these are unavoidable, but also not very expensive.)
You want the objects to be easy to look up, while still being able to draw them efficiently and, more importantly, quickly checking for collisions. This is easy to do: store the objects in the array, and for the X and Y positions keep indexes which allow for 1) efficiently querying ranges and 2) efficiently moving elements left and right (as their x and y positions change).
If your objects are going to be moving fairly slowly (that is, on any one timestep, it is unlikely for an object to pass very many other objects), your indexes can be arrays! When an object moves past another object (in X, for instance), you just need to check its neighbor in the X index array to see if they should swap places. Keep doing this until it does not need to swap. If they're moving slowly, the amortized cost of this will be very close to O(1). Querying ranges is very easy in an array; binary search for the first greater element, and also for the last smaller element.
Summary/Implementation:
(Fiddle at https://jsfiddle.net/LsfuLo9p/3/)
Initialize (O(n) time):
Make an array of your objects called Objs.
Make an array of (x position, reference to Objs) pairs, sorted in X, called Xs.
Make an array of (y position, reference to Objs) pairs, sorted in Y, called Ys.
For every element in Xs and Ys, tell the object in Objs its index in those arrays (so that Xs has indexes to Objs, and Objs has indexes to Xs.)
When an object moves up in Y (O(1) expected time per moving object, given that they're moving slowly):
Using Objs, find its index in Ys.
Compare it to the next highest value in Ys. If it's greater, swap them in Ys (and update their Y indices in Objs).
Repeat step 2 until you don't swap.
(It's easy to apply this to the other three directions.)
When the player moves (O(log n + k2) time, where k is the maximum number of items that can fit in a row or column):
Look in Xs for small, the smallest X above Player.X, and large, the largest X+width below Player.X. If large &leq; small, return the range [large, small].
Look in Ys for small, the smallest Y above Player.Y, and large, the largest Y+height below Player.Y. If large &leq; small, return the range [large, small].
If there are any intersections between these two ranges, then the player is colliding with that object.
(You can improve the time of this to O(log n + k) by using a hashmap to check for set intersections.)

Spatial Data Structure for Games

I need to implement a spatial data structure to store rectangles then be able to find all rectangles that intersect a given rectangle. This will be implemented in JavaScript.
So far I am developing a Quad Tree to cut down the search space but because it is for a game, all objects that move will need to update its position in the tree. Back to square one.
Are there any data-structures or methods to help? It will need to process around 10,000 objects so brute force isn't good enough.
A hash table works fairly well as an approximate intersection test. Hash tables are used as part of a more sophisticated algorithm for detecting collisions in ODE.
Logically, this test divides the space into a regular grid. Each grid cell is labeled with a list of objects that intersect that cell. The grid is initialized by scanning all objects. I don't know javascript, so I'll use python-ish pseudocode.
for each ob in objects:
for each x in [floor(ob.x_min / grid_size) .. floor(ob.x_max / grid_size)]:
for each y in [floor(ob.y_min / grid_size) .. floor(ob.y_max / grid_size)]:
hashtable[hash(x, y)].append(ob)
To find collisions with a given object, look up near-collisions in the hash table and then apply an exact collision test to each one.
near_collisions = []
for each x in [floor(ob.x_min / grid_size) .. floor(ob.x_max / grid_size)]:
for each y in [floor(ob.y_min / grid_size) .. floor(ob.y_max / grid_size)]:
near_collisions = near_collisions ++ hashtable[hash(x, y)]
remove duplicates from near_collisions
for each ob2 in near_collisions:
if exact_collision_test(ob, ob2):
do_something
You can still use quadtree even if you have moving objects – just remove and reinsert an object every time it moves or every time it crosses region boundary.
But quadtrees aren't very good at storing rectangles and I would recommend using an R-tree instead.

Categories

Resources