Related
I can't wrap my head around what's missing in my function to populate a binary tree vs the manual input.
Printing the head value along with its left & right node value doesn't seem to help me as well since it looks correct to me. However, printing out all the values after auto populating it produces a strange result.
The values of this binary tree will be coming from an array:
std::vector<ValueType> values = {
3,
7,4,
2,4,6,
8,5,9,3
};
Here is the tree relation:
3
(7,4)
7 4
(2,4) (4,6)
2 4 6
(8,5) (5,9) (9,3)
As you can see, the parent node is located above and its children is below enclosed in parenthesis.
row1: the root node 3 have left:7, right:4
row2: parent 7 have left:2, right:4
row2: parent 4 have left:4, right:6
...
This may seem not be a binary tree as mentioned from the comments, but look at it as a tree having null left or right node or a node having a shared children from its sibling (same row).
Below is the function to automatically populate the binary tree:
// ValueType is defined as an alias of int
void populateTree(BinaryTree* node, int rowCount, int lastIndex, std::vector<ValueType> values) {
for (int i = 0; i < rowCount; ++i) {
iterCount++;
int currentRow = (i * (i + 1)) / 2;
int x = i + 1;
int nextRow = (x * (x + 1)) / 2;
bool toggle = false;
for (int j = nextRow; j < nextRow + x; ++j) {
auto value = values[currentRow++];
node->value = node->parent != nullptr ? value : node->value;
if (j >= values.size())
continue;
auto leftValue = values[j + 0];
auto rightValue = values[j + 1];
node->left = new BinaryTree(node, leftValue);
node->right = new BinaryTree(node, rightValue);
if (j != currentRow)
std::cout << ", ";
std::cout << node->value << "(" << node->left->value << "," << node->right->value << ")";
node = toggle ? node->right : node->left;
toggle = !toggle;
}
std::cout << std::endl;
}
}
I have used the triangular number formula to map the array into row and column.
Now, to confirm if the code is working, starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom should be 23.
I've done this by traversing bottom-up and add all the adjacent node combinations. Here's the output of the result:
3(7,4)
7(2,4), 4(4,6)
2(8,5), 4(5,9), 6(9,3)
iter count: 14
============
[4, 4, 7, 3]:18
[5, 4, 2, 4, 7, 3]:25
[3, 6, 4, 2, 4, 7, 3]:29
[3, 6, 4, 2, 4, 7, 3]:29
[5, 2, 4, 7, 3]:21
[4, 7, 3]:14
[4, 3]:7
pair total sum: 54
There supposed to be a combinations of [n1, n2, n3, ...nX]:23.
However, if I build the binary tree manually, there is a correct combination:
3(7,4)
7(2,4), 4(4,6)
2(8,5), 4(5,9), 6(9,3)
iter count: 14
============
[8, 2, 7, 3]:20
[5, 2, 7, 3]:17
[5, 4, 7, 3]:19
[9, 4, 7, 3]:23 <--- this is the correct combination.
[5, 4, 4, 3]:16
[9, 4, 4, 3]:20
[9, 6, 4, 3]:22
[3, 6, 4, 3]:16
pair total sum: 83
Link to full source code: https://gist.github.com/mr5z/8249a9101e5bfdce4850602c3ea7ebf3
This is part of my solution to project euler#18
I’m not exactly sure about why your implement a tree structure an your own, but if your goal is visualisation of a certain tree structure: I would suggest you to use the boost cpp graph library in combination with graphiz
See an example here, which shows the construction of a family tree, in a more "graph orientated" way. Every graph (like a tree) has nodes and edges.
If you want to train your programming skills, please go ahead: I found the following example for a b-tree quite useful in my past.
Couldn’t you use a “normal” insertIntoTree function instead of you populateTree function ? Or is this a matter of performance for you ?
What you do here is an example of an XY problem (see here: Meta StackExchange: What is the XY problem? or there: GreyCat's Wiki: XyProblem) – you're trying to put your data into a tree structure just because they are presented in a way resembling a tree-like pyramid, but you did not check if such structure will actually help you solve the problem.
And the answer is: NO, it will not; it doesn't even fit the actual problem structure.
Your problem structure is a pyramid-like triangle of integer numbers, each of which has two nearest descendants (except those in the bottom row) and two nearest ancestors (except those on side edges, which have just one ancestor, and the top item, which has no ancestors at all). And you have already mapped that structure into a linear array by your 'triangular formula':
given a row number r in a range of 0 .. N-1 and a position in the row p in a range of 0 .. r and an array with indices 0 .. N*(N+1)/2-1,
the item (r,p) is stored in the array at index r*(r+1)/2 + p,
and its 'children' are (r+1,p) and (r+1,p+1).
That's all, the mapping allows you to access data in a 'triangular' manner, you need no tree to handle it.
I'm new to programming and C++, in my course I need to hand execute a program and show how the elements change and which ones. I'm a bit stuck on this but I think I'm on the right track. Any assistance would be really appreciated.
void data(vector<double> &data, int idx, double value)
{
data.push_back(value);
if (idx >= data.size() - 1) return;
if (idx < 0) idx = 0;
for(int i = data.size() - 1; i > idx; i--)
{
data[i] = data[i -1];
data[i - 1] = value;
}
}
The data set I'm using is:
[4, -6, 0, 8, -7]
idx: 2
value: -7
So the -7 value is what is push_back onto the end of the vector
I think I've figured out some of it, data.size() - 1 means the last element in the array and if the idx is greater or equal to the last element return that value? The for loop seems to iterate backwards to me.
If your problem is to figure out the purpose of this algorithm, read this answer.
Let's first take your example:
std::vector<double> a{ 4, -6, 0, 8, -7 };
data(a, 2, -7);
The result is: 4, -6, -7, 0, 8, -7
It should be clear that data(vec, idx, val) inserts val into the vec so that it is the idxth element and the vec increased its size by 1.
If idx is out of range, it is adjusted to 0 (if < 0) or vec.size() (if >= vec.size().)
Edit:
Visualization:
Initially:
4, -6, 0, 8, -7, -7
First iteration I = data.size() - 1 = 5:
4, -6, 0, 8, -7, -7 (data[5] = data[4])
4, -6, 0, 8, -7, -7 (data[4] = value)
(Note: here -7 = -7 so nothing changes)
Second iteration I = 4:
4, -6, 0, 8, 8, -7 (data[4] = data[3])
4, -6, 0, -7, 8, -7 (data[3] = value)
Third iteration I = 3:
4, -6, 0, 0, 8, -7 (data[3] = data[2])
4, -6, -7, 0, 8, -7 (data[2] = value)
Now I = 2, over.
if (idx >= data.size() - 1) return;
Actually you check that the index isn't outside of the array. data.size() - 1 is the last element, so idx can be the second last element at most. We will see why this.
if (idx < 0) idx = 0;
If the index is lower than 0, just set it to 0 to access the first element
for(int i = data.size() - 1; i > idx; i--)
You start with the index of the last element, and as long as it is greater than idx you continue with another iteration (and decrement it). So in your example you would have two iterations with i = 4 and i = 3. idx is like a lower exclusive bound
data[i] = data[i -1];
data[i - 1] = value;
You first copy the previous element to the current one, and then the value (-7 in your case) to the previous element. So in the last iteration i-1 will be the same as idx. And because of that idx cannot be the last element, because then the loop won't enter.
So what this actually does, is inserting value step-by-step from the end of the vector to the position idx. The last element is lost and the others slide one position up. Every iteration it gets one position more to the left and what was there before steps up.
I'm trying to find the maximum contiguous subarray with start and end index. The method I've adopted is divide-and-conquer, with O(nlogn) time complexity.
I have tested with several test cases, and the start and end index always work correctly. However, I found that if the array contains an odd-numbered of elements, the maximum sum is sometimes correct, sometimes incorrect(seemingly random). But for even cases, it is always correct. Here is my code:
int maxSubSeq(int A[], int n, int &s, int &e)
{
// s and e stands for start and end index respectively,
// and both are passed by reference
if(n == 1){
return A[0];
}
int sum = 0;
int midIndex = n / 2;
int maxLeftIndex = midIndex - 1;
int maxRightIndex = midIndex;
int leftMaxSubSeq = A[maxLeftIndex];
int rightMaxSubSeq = A[maxRightIndex];
int left = maxSubSeq(A, midIndex, s, e);
int right = maxSubSeq(A + midIndex, n - midIndex, s, e);
for(int i = midIndex - 1; i >= 0; i--){
sum += A[i];
if(sum > leftMaxSubSeq){
leftMaxSubSeq = sum;
s = i;
}
}
sum = 0;
for(int i = midIndex; i < n; i++){
sum += A[i];
if(sum > rightMaxSubSeq){
rightMaxSubSeq = sum;
e = i;
}
}
return max(max(leftMaxSubSeq + rightMaxSubSeq, left),right);
}
Below is two of the test cases I was working with, one has odd-numbered elements, one has even-numbered elements.
Array with 11 elements:
1, 3, -7, 9, 6, 3, -2, 4, -1, -9,
2,
Array with 20 elements:
1, 3, 2, -2, 4, 5, -9, -4, -8, 6,
5, 9, 7, -1, 5, -2, 6, 4, -3, -1,
Edit: The following are the 2 kinds of outputs:
// TEST 1
Test file : T2-Data-1.txt
Array with 11 elements:
1, 3, -7, 9, 6, 3, -2, 4, -1, -9,
2,
maxSubSeq : A[3..7] = 32769 // Index is correct, but sum should be 20
Test file : T2-Data-2.txt
Array with 20 elements:
1, 3, 2, -2, 4, 5, -9, -4, -8, 6,
5, 9, 7, -1, 5, -2, 6, 4, -3, -1,
maxSubSeq : A[9..17] = 39 // correct
// TEST 2
Test file : T2-Data-1.txt
Array with 11 elements:
1, 3, -7, 9, 6, 3, -2, 4, -1, -9,
2,
maxSubSeq : A[3..7] = 20
Test file : T2-Data-2.txt
Array with 20 elements:
1, 3, 2, -2, 4, 5, -9, -4, -8, 6,
5, 9, 7, -1, 5, -2, 6, 4, -3, -1,
maxSubSeq : A[9..17] = 39
Can anyone point out why this is occurring? Thanks in advance!
Assuming that n is the correct size of your array (we see it being passed in as a parameter and later used to initialize midIndexbut we do not see its actual invocation and so must assume you're doing it correctly), the issue lies here:
int midIndex = n / 2;
In the case that your array has an odd number of elements, which we can represented as
n = 2k + 1
we can find that your middle index will always equate to
(2k + 1) / 2 = k + (1/2)
which means that for every integer, k, you'll always have half of an integer number added to k.
C++ doesn't round integers that receive floating-point numbers; it truncates. So while you'd expect k + 0.5 to round to k+1, you actually get k after truncation.
This means that, for example, when your array size is 11, midIndex is defined to be 5. Therefore, you need to adjust your code accordingly.
Suppose I have some sorted lists of integers and I want to convert them to their respective regex digit ranges, like so:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] => [0-9]
[0, 1, 2, 3, 4, 6, 7, 8, 9] => [0-46-9]
[0, 1, 3, 4, 5, 8, 9] => [013-589]
[0, 2, 4, 6, 8] => [02468]
I am not trying to regex match anything here. I am trying to generate a regex range from a set of digits.
I am really just looking to see if there is already some de facto algorithm for doing something like this.
Edit: Based on #Jerry_Coffin's answer, a Java-based algorithm:
List<Integer> digits = Arrays.asList(0, 1, 3, 4, 5, 8, 9);
StringBuilder digitRange = new StringBuilder().append('[');
int consecutive = 0;
for (int i = 0; i < digits.size(); i++) {
if (i == digits.size() - 1 || digits.get(i) + 1 != digits.get(i + 1)) {
if (consecutive > 1) {
digitRange.append('-');
}
digitRange.append(digits.get(i));
consecutive = 0;
} else {
if (consecutive == 0) {
digitRange.append(digits.get(i));
}
consecutive++;
}
}
digitRange.append(']');
System.out.println(digitRange.toString());
Output: [013-589]
Feel free to find improvements or problems.
Presumably you're starting from sorted input (if not, you almost certainly want to start by sorting the input).
From there, start from the first (unprocessed) item, write it out. Walk through the numbers as long as they're consecutive. Assuming you get more than two consecutive, write out a dash then the last of the consecutive numbers. If you got two or fewer consecutive, just write them to output as-is.
Repeat until you reach the end of the input.
I can propose a different approach.
Iterate through the list identifying intervals. We keep two variables left and right (interval bounds) and each time we have two not consecutive values we write the interval to a StringBuilder.
int[] list = new[] { 0, 1, 3, 4, 5, 8, 9 };
int left = 0;
int right = 0;
for (int i = 0; i < list.Length; i++)
{
if (i == 0) // first case
{
left = right = list[i];
continue;
}
if (list[i] - list[i - 1] > 1) // not consecutive
{
builder.AppendFormat(Write(left, right));
left = list[i];
}
right = list[i];
}
builder.AppendFormat(Write(left, right));// last case
builder.Append("]");
The write method:
private static string Write(int left, int right)
{
return
left == right
? left.ToString()
: right - left == 1
? string.Format("{0}{1}", left, right)
: string.Format("{0}-{1}", left, right);
}
Nearly every OpenGL tutorial lets you implement drawing a cube. Therefore the vertices of the cube are needed. In the example code I saw a long list defining every vertex. But I would like to compute the vertices of a cube rather that using a overlong list of precomputed coordinates.
A cube is made of eight vertices and twelve triangles. Vertices are defined by x, y, and z. Triangles are defined each by the indexes of three vertices.
Is there an elegant way to compute the vertices and the element indexes of a cube?
When i was "porting" the csg.js project to Java I've found some cute code which generated cube with selected center point and radius. (I know it's JS, but anyway)
// Construct an axis-aligned solid cuboid. Optional parameters are `center` and
// `radius`, which default to `[0, 0, 0]` and `[1, 1, 1]`. The radius can be
// specified using a single number or a list of three numbers, one for each axis.
//
// Example code:
//
// var cube = CSG.cube({
// center: [0, 0, 0],
// radius: 1
// });
CSG.cube = function(options) {
options = options || {};
var c = new CSG.Vector(options.center || [0, 0, 0]);
var r = !options.radius ? [1, 1, 1] : options.radius.length ?
options.radius : [options.radius, options.radius, options.radius];
return CSG.fromPolygons([
[[0, 4, 6, 2], [-1, 0, 0]],
[[1, 3, 7, 5], [+1, 0, 0]],
[[0, 1, 5, 4], [0, -1, 0]],
[[2, 6, 7, 3], [0, +1, 0]],
[[0, 2, 3, 1], [0, 0, -1]],
[[4, 5, 7, 6], [0, 0, +1]]
].map(function(info) {
return new CSG.Polygon(info[0].map(function(i) {
var pos = new CSG.Vector(
c.x + r[0] * (2 * !!(i & 1) - 1),
c.y + r[1] * (2 * !!(i & 2) - 1),
c.z + r[2] * (2 * !!(i & 4) - 1)
);
return new CSG.Vertex(pos, new CSG.Vector(info[1]));
}));
}));
};
I solved this problem with this piece code (C#):
public CubeShape(Coord3 startPos, int size) {
int l = size / 2;
verts = new Coord3[8];
for (int i = 0; i < 8; i++) {
verts[i] = new Coord3(
(i & 4) != 0 ? l : -l,
(i & 2) != 0 ? l : -l,
(i & 1) != 0 ? l : -l) + startPos;
}
tris = new Tris[12];
int vertCount = 0;
void AddVert(int one, int two, int three) =>
tris[vertCount++] = new Tris(verts[one], verts[two], verts[three]);
for (int i = 0; i < 3; i++) {
int v1 = 1 << i;
int v2 = v1 == 4 ? 1 : v1 << 1;
AddVert(0, v1, v2);
AddVert(v1 + v2, v2, v1);
AddVert(7, 7 - v2, 7 - v1);
AddVert(7 - (v1 + v2), 7 - v1, 7 - v2);
}
}
If you want to understand more of what is going on, you can check out the github page I wrote that explains it.