I have a char buffer[1024] and a struct
typedef struct {
int record;
int key;
} leaf_entry;
What I am trying to implement is the buffer array acting like a node of a tree that holds many entries of leaf_entry.
If I want to iterate down the buffer to compare an entry in the buffer to another entry
for (i = 0; i < max_ents * entry_size; i += entry_size)
{
leaf_entry curr;
memcpy (curr, buffer[i], entry_size)
if (curr == entry_to_compare)
etc...
}
Is this correct? Is there an easier/more efficient way to accomplish this?
You should be able to do this without copying given that your struct is POD.
I believe something like this should work where offset is the correct byte offset into the char buffer:
leaf_entry & x = static_cast<leaf_entry &>(buffer + offset);
I would consider using the approach that standard sorting implementations use - namely, use a user-defined compare function that receives 2 pointers. You then use these pointers to locate the element and from there, access and compare the members you're interested in. This also avoids the unnecessary memory copying.
Consider the following func used to compare ints:
int compareIntAsc(const void *int1, const void *int2)
{
int *num1 = (int*)int1;
int *num2 = (int*)int2;
return *num1 - *num2;
}
and now consider one which will compare the count member of some structs
int compareNodeCountAsc(const void *node1, const void *node1)
{
return (pHuffmanNode)(node1))->charCount - ((pHuffmanNode)(node2))->charCount;
}
If you pass the address of two elements in your array to such a function, you can compare either the record or the key.
e.g compare element 0 to every other element
code
typedef struct {
int record;
int key;
} leaf_entry, *pLeafEntry;
int compLeafKeyAsc(void *leaf1, void *leaf2)
{
leaf_entry *p1, *p2;
p1 = (leaf_entry *)leaf1;
p2 = (leaf_entry *)leaf2;
return p1->key - p2->key;
}
void printLeaf(pLeafEntry leaf)
{
printf("----- leaf -------\n");
printf("record: %d\n", leaf->record);
printf("key: %d\n", leaf->key);
}
void demo()
{
const int nElems = 16;
leaf_entry leafArray[nElems];
pLeafEntry firstElement;
int i;
for (i=0;i<nElems;i++)
{
leafArray[i].record = (rand()%51) + 100; // record is [100..150]
leafArray[i].key = (rand()%128); // key is [0..127]
printLeaf(&leafArray[i]);
}
//e.g compare element 0 to every other element
firstElement = &leafArray[0];
for (i=1; i<nElems; i++)
{
printf("%d", firstElement->key );
int result = compLeafKeyAsc(firstElement, &leafArray[i]);
if (result < 0)
printf(" is less than ");
else if (result > 0)
printf(" is greater than ");
else
printf(" is equal to ");
printf("%d\n", leafArray[i].key);
}
}
output
----- leaf -------
record: 141
key: 35
----- leaf -------
record: 110
key: 4
----- leaf -------
record: 144
key: 108
----- leaf -------
record: 103
key: 46
----- leaf -------
record: 134
key: 16
----- leaf -------
record: 144
key: 113
----- leaf -------
record: 125
key: 59
----- leaf -------
record: 116
key: 107
----- leaf -------
record: 137
key: 38
----- leaf -------
record: 133
key: 60
----- leaf -------
record: 106
key: 12
----- leaf -------
record: 126
key: 25
----- leaf -------
record: 137
key: 94
----- leaf -------
record: 130
key: 28
----- leaf -------
record: 132
key: 55
----- leaf -------
record: 141
key: 94
35 is greater than 4
35 is less than 108
35 is less than 46
35 is greater than 16
35 is less than 113
35 is less than 59
35 is less than 107
35 is less than 38
35 is less than 60
35 is greater than 12
35 is greater than 25
35 is less than 94
35 is greater than 28
35 is less than 55
35 is less than 94
Related
Prompt:
In this country soldiers are poor but they need a certain level of secrecy for their communications so, though they do not know Caesar cypher, they reinvent it in the following way.
They use ASCII, without really knowing it, but code only letters a-z and A-Z. Other characters are kept such as.
They change the "rotate" each new message. This "rotate" is a prefix for their message once the message is coded. The prefix is built of 2 letters, the second one being shifted from the first one by the "rotate", the first one is the first letter, after being downcased, of the uncoded message.
For example if the "rotate" is 2, if the first letter of the uncoded message is 'J' the prefix should be 'jl'.
To lessen risk they cut the coded message and the prefix in five pieces since they have only five runners and each runner has only one piece.
If possible the message will be evenly split between the five runners; if not possible, parts 1, 2, 3, 4 will be longer and part 5 shorter. The fifth part can have length equal to the other ones or shorter. If there are many options of how to split, choose the option where the fifth part has the longest length, provided that the previous conditions are fulfilled. If the last part is the empty string don't put this empty string in the resulting array.
For example, if the coded message has a length of 17 the five parts will have lengths of 4, 4, 4, 4, 1. The parts 1, 2, 3, 4 are evenly split and the last part of length 1 is shorter. If the length is 16 the parts will be of lengths 4, 4, 4, 4, 0. Parts 1, 2, 3, 4 are evenly split and the fifth runner will stay at home since his part is the empty string and is not kept.
Could you ease them in programming their coding?
Example with shift = 1 :
message : "I should have known that you would have a perfect answer for me!!!"
code : => ["ijJ tipvme ibw", "f lopxo uibu z", "pv xpvme ibwf ", "b qfsgfdu botx", "fs gps nf!!!"]
By the way, maybe could you give them a hand to decode?
//Ends here
Issues faced:
Can't figure out how to divide the encoded string according to the given conditions. I understand the math behind how the division needs to be done, but can't convert it into code. I know that the num variable that I used needs to be decremented by 4 and the count variable should be incremented by 4 till the condition (num/4 > count) because the condition is such that if the string can be split in multiple ways, then we should do it such that the 5th part is of the longest length.
My code:
static vector<string> encodeStr(const string &s, int shift)
{
char pre = tolower(s[0]);
pre += shift;
string newS = "";
newS += tolower(s[0]);
newS += pre;
vector<string> ans;
for (int i = 0; i < (int)s.size(); i++)
{
if ((s[i] >= 65 && s[i] <= 90) || (s[i] >= 97 && s[i] <= 122))
{
char c = s[i];
c += shift;
newS += c;
}
else
newS.push_back(s[i]);
}
if (newS.size() % 4 == 0)
{
int parts = newS.size() / 4;
int start = 0;
while (start < (int)newS.size())
{
ans.push_back(newS.substr(start, parts));
start += parts;
}
}
else if (newS.size() % 5 == 0)
{
int parts = newS.size() / 5;
int start = 0;
while (start < (int)newS.length())
{
ans.push_back(newS.substr(start, parts));
start += parts;
}
}
else if (newS.length() % 5 != 0 && newS.length() % 4 != 0)
{
int num = newS.length();
int count = 0;
int start = 0;
while (num % 4 != 0)
{
num--;
count++;
}
while (num / 4 > count)
{
num = num - 4;
count = count + 4;
}
int x = newS.length() - count;
int parts = x / 4;
while (start < (int)newS.length() - count)
{
ans.push_back(newS.substr(start, parts));
start += parts;
}
ans.push_back(newS.substr((int)newS.size() - count, count));
}
return ans;
}
static string decode(vector<string> &s)
{
string s1 = "";
char check = ' ' - 1;
for (int i = 0; i < (int)s.size(); i++)
{
s1 += s[i];
}
char a = s1[1];
char b = s1[0];
int shift = a - b;
s1.erase(0, 2);
transform(s1.begin(), s1.end(), s1.begin(), [&](auto x)
{
if ((x >= 65 && x <= 90) || (x >= 97 && x <= 122))
return x -= shift;
else
return x;
});
for (int i = 0; i < (int)s1.size(); i++)
{
if (s1[i] == check)
{
s1[i]++;
}
}
return s1;
}
Code Output
First, we need to extract the important requirements from the story-text. An evaluation of the text leads to:
Caesar cypher
Based on ASCII
only upper and lowercase alpha letters shall be encoded ('A'-'Z', 'a'-'z')
The key (shift-information) shall be encoded and transmitted by along the message as 2 letter prefix. Taking the first letter of the text, unencrypted, as part 1 of the encrypted key and shifting this letter by the key and transmit it as part 2.
If possible the message will be evenly split between the five runners; if not possible, parts 1, 2, 3, 4 will be longer and part 5 shorter. The fifth part can have length equal to the other ones or shorter.
The 2-letter encrypted key shall be a prefix for parts of the split message.
For the following design, we can derive 3 major blocks:
We need a Caesar Cypher encryption/decryption algorithm
The key encryption/decryption must be implemented
The original message must be split according to requirements.
Let us start with the design for the Caesar Cypher encryption/decryption algorithm. We will take advantage of the ASCII code, where all characters have a defined associated numerical value. Please see the table below for the printable characters:
Hex Dec Bin Hex Dec Bin Hex Dec Bin
20 32 00100000 # 40 64 01000000 ` 60 96 01100000
! 21 33 00100001 A 41 65 01000001 a 61 97 01100001
" 22 34 00100010 B 42 66 01000010 b 62 98 01100010
# 23 35 00100011 C 43 67 01000011 c 63 99 01100011
$ 24 36 00100100 D 44 68 01000100 d 64 100 01100100
% 25 37 00100101 E 45 69 01000101 e 65 101 01100101
& 26 38 00100110 F 46 70 01000110 f 66 102 01100110
' 27 39 00100111 G 47 71 01000111 g 67 103 01100111
( 28 40 00101000 H 48 72 01001000 h 68 104 01101000
) 29 41 00101001 I 49 73 01001001 i 69 105 01101001
* 2a 42 00101010 J 4a 74 01001010 j 6a 106 01101010
+ 2b 43 00101011 K 4b 75 01001011 k 6b 107 01101011
, 2c 44 00101100 L 4c 76 01001100 l 6c 108 01101100
- 2d 45 00101101 M 4d 77 01001101 m 6d 109 01101101
. 2e 46 00101110 N 4e 78 01001110 n 6e 110 01101110
/ 2f 47 00101111 O 4f 79 01001111 o 6f 111 01101111
0 30 48 00110000 P 50 80 01010000 p 70 112 01110000
1 31 49 00110001 Q 51 81 01010001 q 71 113 01110001
2 32 50 00110010 R 52 82 01010010 r 72 114 01110010
3 33 51 00110011 S 53 83 01010011 s 73 115 01110011
4 34 52 00110100 T 54 84 01010100 t 74 116 01110100
5 35 53 00110101 U 55 85 01010101 u 75 117 01110101
6 36 54 00110110 V 56 86 01010110 v 76 118 01110110
7 37 55 00110111 W 57 87 01010111 w 77 119 01110111
8 38 56 00111000 X 58 88 01011000 x 78 120 01111000
9 39 57 00111001 Y 59 89 01011001 y 79 121 01111001
: 3a 58 00111010 Z 5a 90 01011010 z 7a 122 01111010
; 3b 59 00111011 [ 5b 91 01011011 { 7b 123 01111011
< 3c 60 00111100 \ 5c 92 01011100 | 7c 124 01111100
= 3d 61 00111101 ] 5d 93 01011101 } 7d 125 01111101
> 3e 62 00111110 ^ 5e 94 01011110 ~ 7e 126 01111110
? 3f 63 00111111 _ 5f 95 01011111 Del 7f 127 01111111
We observe that upper- and lowercase numbers only differ in one bit, which is equal to a distance of 32. We will use this property later.
Then, now, let us come to the core algorithm. Shifting letters.
The biggest problems are potential overflows. So, we need to deal with that.
Then we need to understand what encryption and decryption means. If encryption will shift everthing one to the right, decryption will shift it back to left again.
So, with "def" and key=1, the encrpyted string will be "efg".
And decrpytion with key=1, will shift it to left again. Result: "def"
We can observe that, for decryption, we simply need to shift by -1, so the negative of the key.
Important result: Encryption and decryption can be done with the same routine. We just need to invert the keys.
Let us look now at the overflow problematic. For the moment we will start with uppercase characters only. Characters have an associated code as shown in above ASCII table. For example, the letter 'A' is encoded with 65, 'B' with 66 and so on. Because we do not want to calculate with such big numbers, we normalize them. We simply subtract 'A' from each character. Then
'A' - 'A' = 0
'B' - 'A' = 1
'C' - 'A' = 2
'D' - 'A' = 3
You see the pattern. If we want to encrypt now the letter 'C' with key 3, we can do the following.
'C' - 'A' + 3 = 5 Then we add again 'A' to get back the letter and we will get 5 + 'A' = 'F'
That is the whole magic.
But what to do with an overflow, beyond 'Z'. This can be handled by a simple modulo division. Let us look at 'Z' + 1. We do 'Z' - 'A' = 25, then +1 = 26 and now, modulo 26 = 0. At the end again plus 'A' will be 'A'.
And so on and so on. The resulting formula is: (c - 'A' + key) % 26 +'A'
Next, what with negative keys? This is also simple. Assume an 'A' and key=-1.
Result will be a 'Z'. But this is the same as shifting positions 25 to the right. So, we can simply convert a negative key to a positive shift. The simple statement will be:
if (key < 0) key = (26 + (key % 26)) % 26;
With the above formular, there is even no need to check for a negative values. It will work for positive and negative values.
So, key = (26 + (key % 26)) % 26; will always work, for encrpytion and decrytion, for positive and negative keys.
Some extended information: Please have a look at any ASCII table and remeber, what we said above. We found out already, that any uppercase and lowercase character differ by 32. Or, if you look again to the binary representation:
char dec bin char dec bin
'A' 65 0100 0001 'a' 97 0110 0001
'B' 66 0100 0010 'b' 98 0110 0010
'C' 67 0100 0011 'b' 99 0110 0011
. . .
So, if you already know that a character is alpha, then the only difference between upper- and lowercase is bit number 5. If we want to know, if char is lowercase, we can get this by masking this bit. c & 0b0010 0000. Which is equal to c & 32 or c & 0x20.
If we want to operater on either uppercase or lowercase characters, then we can mask the "case" away. With c & 0b00011111 or c & 31 or c & 0x1F we will get always equivalents for uppercase charcters, already normalized to start with value 1.
char dez bin Masking char dez bin Masking
'A' 65 0100 0001 & 0x1b = 1 'a' 97 0110 0001 & 0x1b = 1
'B' 66 0100 0010 & 0x1b = 2 'b' 98 0110 0010 & 0x1b = 2
'C' 67 0100 0011 & 0x1b = 3 'b' 99 0110 0011 & 0x1b = 3
. . .
So, if we use an alpha character, mask it, and subtract 1, then we get as a result 0..25 for any upper- or lowercase character.
Again, I would like tor repeat the key handling. Positive keys will encrypt a string, negative keys will decrypt a string. But, as said above, negative keys can be transformed into positive ones. Example:
Shifting by -1 is same as shifting by +25
Shifting by -2 is same as shifting by +24
Shifting by -3 is same as shifting by +23
Shifting by -4 is same as shifting by +22
So,it is very obvious that we can calculate an always positive key by: 26 + key. For negative keys, this will give us the above offsets.
And for positve keys, we would have an overflow over 26, which we can elimiate by a modulo 26 division:
'A'--> 0 + 26 = 26 26 % 26 = 0
'B'--> 1 + 26 = 27 27 % 26 = 1
'C'--> 2 + 26 = 28 28 % 26 = 2
'D'--> 3 + 26 = 29 29 % 26 = 3
--> (c + key) % 26 will eliminate overflows and result in the correct new en/decryptd character.
And, if we combine this with the above wisdom for negative keys, we can write: ((26+(key%26))%26) which will work for all positive and negative keys.
If we now implement all above gathered wisdom in code, we can come up with bascically one C++ statement for the whole encryption and decryption, using std::transform:
std::string caesar(const std::string& in, int key) {
std::string res(in.size(), ' ');
std::transform(in.begin(), in.end(), res.begin(), [&](char c) {return std::isalpha(c) ? (char)((((c & 31) - 1 + ((26 + (key % 26)) % 26)) % 26 + 65) | (c & 32)) : c; });
return res;
}
This will do, what we described above:
(c & 31) - 1 will normalize a character. Meaning, convert to uppercase and to a range of 0-25
((26 + (key % 26)) % 26)) % 26 will do the key shift.
+ 65 will convert the nomalized value (0-25) back to a letter ('A'-'Z')
| (c & 32)) : c This will restore the lower case, if the letter was lower case before.
Now, we derived a complete algorithm and function for encryption and decryption using Caeser Cypher.
.
Next is splitting up the message in 5 parts.
The requirement was:
If possible the message will be evenly split between the five runners; if not possible, parts 1, 2, 3, 4 will be longer and part 5 shorter. The fifth part can have length equal to the other ones or shorter.
This can again be achieved with integer and modulo division. Basically, we will do an integer division to get the number of letters for each of the 5 chunks. Then we use a modulo division, to get the rest.
It is clear, but I will repeat it. If we do an integer division by 5, then the rest can be max 4. And this rest can then be distributed and added 1 by one to other chunks. Let us make an example using 23.
23 % 5 = 4 So, initially each chunk will be 4 letters long
Chunk 1: 4
Chunk 2: 4
Chunk 3: 4
Chunk 4: 4
Chunk 5: 4
------------
Sum: 20 // The rest, 3 is missing
Rest can be calculated with:
23 % 5 = 3 // So, we have a rest or remainder of 3. This we will distribute now:
Remainder = 3
Chunk 1: 4 + 1 = 5 3 - 1 = 2
Chunk 2: 4 + 1 = 5 2 - 1 = 1
Chunk 3: 4 + 1 = 5 1 - 1 = 0 Now everything was distributed
Chunk 4: 4 4
Chunk 5: 4 4
-------------------
Sum: 23
We now know, how chunksizes can be calculated.
For splitting the original strings into substrings, we can use the corresponding std::strings substr function, which is described here. You see, that we need to calculate a "start position" and a "length" value. Let us write a short piece of code for that.
#include <iostream>
#include <array>
#include <string>
constexpr std::size_t NumberOfChunks = 5u;
struct SDefs {
struct SDef {
std::size_t startPosition{}; // For substr function, we need a start position
std::size_t count{}; // and a count aof characters
};
std::array<SDef, NumberOfChunks> sDefs{}; // We have an array of 5 for this Positions and Counts
void calculate(const std::string& s) { // Calculation function
const size_t chunk = s.size() / NumberOfChunks; // Calculate the basic chunksize of all chunks
size_t remainder = s.size() % NumberOfChunks; // Calculate the rest that needs to be distributed
for (std::size_t startPos{}; SDef & sdef : sDefs) { // Calculate all positions and counts in a loop
sdef.startPosition = startPos; // Set startposition
sdef.count = chunk + (remainder ? 1 : 0); // And the chunk size, including potential distributed remainder
startPos += sdef.count; // Next startposition
if (remainder) --remainder; // And next remainder, if any
}
}
SDef& operator[](const std::size_t i) { return sDefs[i]; } // Easier accessibility
};
// Test code
int main () {
SDefs sdefs{};
std::string test{ "12345678901234567890123" };
sdefs.calculate(test);
for (std::size_t i{}; i < NumberOfChunks; ++i)
std::cout << "Chunk " << i+1 << " Start position: " << sdefs[i].startPosition << "\tCount: " << sdefs[i].count << '\n';
}
.
Finally: The transmission of the key. For encrypting, we simply take the first character of the text, or, in our case the substring. and then apply the encryption/decryption function on that to get the second letter.
And because the requirement was to use lower case characters, we set the 5th bit for the characters.
For decryption, in order to get the key, we need to subtract the second letter from the first. Thats all. Then we can invert it and use our encryption/decryption function again.
By the way. This method is dangerous and easy to hack, because you have always repeating letters at the beginning of a chunk.
For the final result, we need to add a little bit of house keeping code.
Then, lets_put everything together and create some program:
#include <iostream>
#include <array>
#include <string>
#include <algorithm>
#include <cctype>
constexpr std::size_t NumberOfChunks = 5u; // Maybe modified to whatever you need
// ---------------------------------------------------------------------------------------------------------
// Chunk calculator
struct SDefs {
struct SDef {
std::size_t startPosition{}; // For substr function, we need a start position
std::size_t count{}; // and a count aof characters
};
std::array<SDef, NumberOfChunks> sDefs{}; // We have an array of 5 for this Positions and Counts
void calculate(const std::string& s) { // Calculation function
const size_t chunk = s.size() / NumberOfChunks; // Calculate the basic chunksize of all chunks
size_t remainder = s.size() % NumberOfChunks; // Calculate the rest that needs to be distributed
for (std::size_t startPos{}; SDef & sdef : sDefs) { // Calculate all positions and counts in a loop
sdef.startPosition = startPos; // Set startposition
sdef.count = chunk + (remainder ? 1 : 0); // And the chunk size, including potential distributed remainder
startPos += sdef.count; // Next startposition
if (remainder) --remainder; // And next remainder, if any
}
}
SDef& operator[](const std::size_t i) { return sDefs[i]; } // Easier accessibility
};
// ---------------------------------------------------------------------------------------------------------
// Caesar Cypher
std::string caesar(const std::string& in, int key) {
std::string res(in.size(), ' ');
std::transform(in.begin(), in.end(), res.begin(), [&](char c) {return std::isalpha(c) ? (char)((((c & 31) - 1 + ((26 + (key % 26)) % 26)) % 26 + 65) | (c & 32)) : c; });
return res;
}
// Get a prefix, based on a given key
std::string getKeyPrefix(const std::string& s, const int key) {
std::string prefix("AA");
if (auto i = std::find_if(s.begin(), s.end(), std::isalpha); i != s.end()) {
prefix[0] = *i |32;
prefix[1] = (char)((((*i & 31) - 1 + ((26 + (key % 26)) % 26)) % 26 + 65) | 32);
}
return prefix;
}
// ---------------------------------------------------------------------------------------------------------
std::string test{"This was a major hack. What a pity that nobody will read or value it."};
int main() {
std::cout << "\nPlease enter a key: ";
if (int key{}; std::cin >> key) {
// Here we will store our encrypter and later decypted messages
std::array<std::string, NumberOfChunks> messages{};
// Here we will calculate the substrings properties
SDefs sdef{};
sdef.calculate(test);
// Encryption
for (std::size_t i{}; std::string& message : messages) {
// Get substring
const std::string sub = test.substr(sdef[i].startPosition, sdef[i].count);
// Encrypt sub string text
message = getKeyPrefix(sub, key) + caesar(sub,key);
// Debug output
std::cout << "Encrypted Message chunk " << i++ << ":\t" << message << '\n';
}
// Decryption
std::cout << "\n\nDecrypted Message:\n\n";
for (std::string& message : messages) {
// get key, inverted
int dkey = message[0] - message[1];
// Get substring
std::string sub = message.substr(2);
// Derypt sub string text
message = caesar(sub, dkey);
// Debug output
std::cout << message;
}
std::cout << "\n\n";
}
else
std::cerr << "\n\n***Error: Invalid input\n\n";
}
Have fun.
Checksum: fkems hajk eks ἀρμιν μοντιγνι qod krtd ghja
Link of the question-[Link][1]
Basically we are given an array of integers and it's size. Question is to construct a binary tree from it. Each index corresponds to data stored in a node, and the value of that index is the data of the parent. Value of the root node index would always be -1 as there is no parent for root. The Output will be the sorted level order traversal of the tree.
Now my approach is that I parse the array from 1 to n(not the 0th element/root node), and for each element, I get it's parent using the first function, and insert the child accordingly. But one particular test case is failing. Maybe the website's own output is not correct. I will post everything below:-
Example test case-
Size of array-7
Elements- -1 0 0 1 1 3 5
Output- 0 1 2 3 4 5 6
Particular test case(which is my doubt)-
Size of array- 42
Elements-
3 19 1 41 35 29 27 11 17 23 9 15 33 13 39 23 19 25 21 1 33 15 31 21 5 7 37 29 7 11 31 39 -1 27 3 9 25 17 13 41 37 35
Website's output- 32
My output - 0
Functions
void getParent(Node* root, int val, Node* &main)
{
if(root==NULL) return;
if(root->data==val){
main=root;
return;
}
getParent(root->left,val,main);
getParent(root->right,val,main);
}
Node *createTree(int parent[], int n)
{
if(n==0) return NULL;
Node * root=new Node(0);
for(int i=1;i<n;i++)
{
Node* main=NULL;
getParent(root,parent[i],main);
//main has the parent
Node* child=new Node(i);
if(main==NULL) break;
if(main->left==NULL)
{
main->left=child;
}
else if(main->right==NULL)
{
main->right=child;
}
}
return root;
}
[1]: https://www.geeksforgeeks.org/construct-a-binary-tree-from-parent-array-representation/
[2]: https://i.stack.imgur.com/0fRmn.png
Not sure what you are doing with your getParent method. Also you are initiating a root node with value 0 and not doing anywith it in the loop and then finally you return the root. I suspect your root will always have a value 0.
The solution is very simple actually. You initialize an array of nodes with each node's value as the index of the array. For example for an array of size 5, you create an array of 5 nodes with each node having a value of the index at which it is located.
Then next step is go through the parent array and see if the node located at parent[i] has either left or right "available", if yes assign the node accordingly.
the code is :
Node* createTree(int parent[], int n) {
Node** nodes = new Node*[n];
for ( int i = 0; i < n; i++ )
nodes[i] = new Node(i);
int rootIndex = 0;
for ( int i = 0; i < n; i++ ) {
if ( parent[i] == -1 ) {
rootIndex = i;
} else {
if ( nodes[parent[i]] -> left == NULL ) {
nodes[parent[i]] -> left = nodes[i];
} else if ( nodes[parent[i]] -> right == NULL ) {
nodes[parent[i]] -> right = nodes[i];
}
}
}
return nodes[rootIndex];
}
I write grid-stride loop to have High Performance Calculations, where large N, for example long long N 1<<36, or even more. From total grid I need only some indexes, which have to satisfy the define condition.
__global__ void Indexes(int *array, int N) {
int index = blockIdx.x * blockDim.x + threadIdx.x;
while( index<N)
{
if (condition)
{....//do something to save index in array}
index += blockDim.x * gridDim.x;
}
}
Of course, it is possible use the Thrust, which allows to have both host and device arrays. But in this case obviously the calculation will be extremely ineffective, because need firstly to create a lot of non-needed elements, then to delete these.
What is the most effective way to save the indexes directly in array in device to pass in CPU?
If your output is relatively dense (i.e. a lot of indices and relatively few zeros), then the stream compaction approach suggested in comments is a good solution. There are a lot of ready-to-go stream compaction implementations which you can probably adapt to your purposes.
If your output is sparse, so you need to save relatively few indices for a lot of inputs, then stream compaction isn't such a great solution because it will waste a lot of GPU memory. In that case (and you can roughly estimate an upper bound of the number of output indices) something like this:
template <typename T>
struct Array
{
T* p;
int Nmax;
int* next;
Array() = default;
__host__ __device__
Array(T* _p, int _Nmax, int* _next) : p(_p), Nmax(_Nmax), next(_next) {};
__device__
int append(T& val)
{
int pos = atomicAdd(next, 1);
if (pos > Nmax) {
atomicExch(next, Nmax);
return -1;
} else {
p[pos] = val;
return pos;
}
};
};
is probably more appropriate. Here, the idea is to use an atomically incremented position in the output array to keep track of where a thread should store its index. The code will signal if you fill the index array, and there will be information from which you can work out a restart strategy to stop the current kernel and then start from the last known index which you were able to store.
A complete example:
$ cat append.cu
#include <iostream>
#include <thrust/device_ptr.h>
#include <thrust/device_vector.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/copy.h>
namespace AppendArray
{
template <typename T>
struct Array
{
T* p;
int Nmax;
int* next;
Array() = default;
__host__ __device__
Array(T* _p, int _Nmax, int* _next) : p(_p), Nmax(_Nmax), next(_next) {};
__device__
int append(T& val)
{
int pos = atomicAdd(next, 1);
if (pos > Nmax) {
atomicExch(next, Nmax);
return -1;
} else {
p[pos] = val;
return pos;
}
};
};
}
__global__
void kernelfind(int* input, int N, AppendArray::Array<int> indices)
{
int idx = threadIdx.x + blockIdx.x * blockDim.x;
for(; idx < N; idx += gridDim.x*blockDim.x) {
if (input[idx] % 10000 == 0) {
if (indices.append(idx) < 0) return;
}
}
}
int main()
{
const int Ninputs = 1 << 20;
thrust::device_vector<int> inputs(Ninputs);
thrust::counting_iterator<int> vals(1);
thrust::copy(vals, vals + Ninputs, inputs.begin());
int* d_input = thrust::raw_pointer_cast(inputs.data());
int Nindices = Ninputs >> 12;
thrust::device_vector<int> indices(Nindices);
int* d_indices = thrust::raw_pointer_cast(indices.data());
int* pos; cudaMallocManaged(&pos, sizeof(int)); *pos = 0;
AppendArray::Array<int> index(d_indices, Nindices-1, pos);
int gridsize, blocksize;
cudaOccupancyMaxPotentialBlockSize(&gridsize, &blocksize, kernelfind, 0, 0);
kernelfind<<<gridsize, blocksize>>>(d_input, Ninputs, index);
cudaDeviceSynchronize();
for(int i = 0; i < *pos; ++i) {
int idx = indices[i];
std::cout << i << " " << idx << " " << inputs[idx] << std::endl;
}
return 0;
}
$ nvcc -std=c++11 -arch=sm_52 -o append append.cu
$ ./append
0 9999 10000
1 19999 20000
2 29999 30000
3 39999 40000
4 49999 50000
5 69999 70000
6 79999 80000
7 59999 60000
8 89999 90000
9 109999 110000
10 99999 100000
11 119999 120000
12 139999 140000
13 129999 130000
14 149999 150000
15 159999 160000
16 169999 170000
17 189999 190000
18 179999 180000
19 199999 200000
20 209999 210000
21 219999 220000
22 239999 240000
23 249999 250000
24 229999 230000
25 279999 280000
26 269999 270000
27 259999 260000
28 319999 320000
29 329999 330000
30 289999 290000
31 299999 300000
32 339999 340000
33 349999 350000
34 309999 310000
35 359999 360000
36 379999 380000
37 399999 400000
38 409999 410000
39 369999 370000
40 429999 430000
41 419999 420000
42 389999 390000
43 439999 440000
44 459999 460000
45 489999 490000
46 479999 480000
47 449999 450000
48 509999 510000
49 539999 540000
50 469999 470000
51 499999 500000
52 569999 570000
53 549999 550000
54 519999 520000
55 589999 590000
56 529999 530000
57 559999 560000
58 619999 620000
59 579999 580000
60 629999 630000
61 669999 670000
62 599999 600000
63 609999 610000
64 699999 700000
65 639999 640000
66 649999 650000
67 719999 720000
68 659999 660000
69 679999 680000
70 749999 750000
71 709999 710000
72 689999 690000
73 729999 730000
74 779999 780000
75 799999 800000
76 809999 810000
77 739999 740000
78 849999 850000
79 759999 760000
80 829999 830000
81 789999 790000
82 769999 770000
83 859999 860000
84 889999 890000
85 879999 880000
86 819999 820000
87 929999 930000
88 869999 870000
89 839999 840000
90 909999 910000
91 939999 940000
92 969999 970000
93 899999 900000
94 979999 980000
95 959999 960000
96 949999 950000
97 1019999 1020000
98 1009999 1010000
99 989999 990000
100 1029999 1030000
101 919999 920000
102 1039999 1040000
103 999999 1000000
Can a c++ object have a method that return a reference to itself?
I want multiple independent instance of the class of the object.
It is for implementing the [] operator of a multi-dimensional array.
I want something like Array[0][1][2] to work.
Thanks.
Update:
Implementation of a multi-dimensional array:
Intended usage:
A[0][1] = 4; //the element at 0th row and 1st column is now 4.
A[0] = 5; //all elements of the 0th row are now 5.
A["all"][1] = 10; //all elements of the 1st column are now 10;
Object A has pointer ptr_buffer to a chunk of memory with correct simd alignment. Constructor of A would allocate the memory. Destructor of A deallocate the memory. A[] returns object B.
Object B has a pointer ptr_A_buffer to a subsection of the memory of A. B[] modifies ptr_A_buffer and also returns reference to itself. I don't want to constantly make a bunch of object B for each [] operation.
Both A and B belong to the same abstract class. Math functions take the abstract class as argument.
I was curious about the idea. Here is a data type which seems to fit the bill. It's an array type which, when called with three integers for the dimensions, allocates contiguous memory and then allows the user to define "views" into the data which have smaller dimensions (a plane, a row, a single value).
I made use of shared pointers which I have not really used before, so I may have made mistakes. I welcome corrections.
The idea is that copying views around is shallow; they all operate on the same underlying data. This allows me to pass them around by value with, as I believe, reasonable efficiency.
#include <iostream>
#include <iomanip>
#include <memory>
using namespace std;
/// This class is a three-dimensional array of doubles.
/// It defines an index operator which returns a view into that
/// data that is of one lesser dimension, just like the standard
/// index operator on plain old arrays. The last index operation
/// yields an "array" which is a single value.
/// Converting to double and assigning from double is defined as
/// using the first double in the view.
class NDimArrT
{
/// All slices hold a shared pointer to the base data they
/// are looking into so that their view stays valid.
const shared_ptr<double> baseData;
/// The data the view is looking at. Identical to the shared
/// ptr for the original object.
double *const slice;
/// The three dimensions, in the order of indexing.
/// All three of them may be zero, indicating a single value.
const int dim1, dim2, dim3;
public:
/// A single double value view into a one-dimensional array
NDimArrT(const shared_ptr<double> base, double *sliceStart)
: baseData(base), slice(sliceStart), dim1(0), dim2(0), dim3(0) {}
/// A 1D vector/row view into a two-dimensional array.
/// #param dim1Arg is the length of the row.
NDimArrT(const shared_ptr<double> base, double *sliceStart, int dim1Arg)
: baseData(base), slice(sliceStart), dim1(dim1Arg), dim2(0), dim3(0) {}
/// A 2D matrix plane view into the cube
NDimArrT(const shared_ptr<double> base, double *sliceStart, int dim1Arg, int dim2Arg)
: baseData(base), slice(sliceStart), dim1(dim1Arg), dim2(dim2Arg), dim3(0) {}
/// A 3D cube. This actually allocates memory.
NDimArrT(int dim1Arg, int dim2Arg, int dim3Arg)
: baseData(new double[dim1Arg*dim2Arg*dim3Arg], std::default_delete<double[]>() ),
slice(baseData.get()), // the data view is the whole array
dim1(dim1Arg), dim2(dim2Arg), dim3(dim3Arg) {}
/// Perform a shallow copy. We assume that e.g. returning a slice means
/// essentially returning another view into the main base array.
NDimArrT(const NDimArrT &rhs) = default;
/// Use standard move semantics. The rhs will be invalidated, and the
/// reference count to the base array does not grow. Can be used to return results from
/// functions.
NDimArrT(NDimArrT &&rhs) = default;
/// Default destructor; destroy baseData if it's the last reference.
~NDimArrT() = default;
/// Get the value of the first element we look at. Handy for
/// single value views.
operator double() const { return *slice; }
/// Return an instance of NDimArrT representing a view
/// with one dimension less than this. If we have a single value
/// already, simply return this single value. (We should
/// perhaps throw an exception there.)
NDimArrT operator[](int ind)
{
// This could be regarded an error, because this view
// is already a single element.
if(GetDims() == 0) { return *this; }
// This view is a 1-dimensional vector. Return the element at ind.
if(dim2==0) { return NDimArrT(baseData, slice + ind); } // return a single value.
// This view is a 2D matrix. Return the row no. ind.
// The row length is dim2. (Dim 1 indicates how many rows.)
if(dim3==0) { return NDimArrT(baseData, slice + dim2*ind, dim2); } // return a 1D vector
// This view is a true 3D cube matrix. dim1 is the number of planes,
// dim2 is the number of rows in a plane, dim3 is the length of each row.
// Return the plane no. ind, which starts at ind*planesize, i.e. ind*dim2*dim3.
// The number of rows and row length are dim2 and dim3, respectively.
return NDimArrT(baseData, slice + dim2*dim3*ind, dim2, dim3); // return a 2D matrix.
}
NDimArrT &operator=(double d) { *slice = d; }
int Len() { return dim1 ? dim1 : 1; } // interestingly, length is always dim1.
int GetDims() const
{
return dim1
? dim2
? dim3
? 3
: 2
: 1
: 0;
}
};
/// An example function which initializes an NDimArr of unknown
/// dimensionality with nice numbers..
void initNDimArr(NDimArrT arr, int &startVal)
{
// Single value? Give it the start value and increment that.
if( arr.GetDims() == 0 ) { arr = startVal++; }
else
{
for(int ind=0; ind<arr.Len(); ind++) { initNDimArr(arr[ind], startVal); }
}
}
// An example function doing something with
// an unknown n-dimensional array
void printNdimArr( NDimArrT nDimArr)
{
if( nDimArr.GetDims() == 0) { cout << setw(4) << nDimArr << " "; }
else
{
for(int i=0; i<nDimArr.Len(); i++) { printNdimArr(nDimArr[i]); }
cout << endl;
}
}
int main()
{
NDimArrT arr(3,4,5);
int start = 1;
initNDimArr(arr, start);
printNdimArr(arr);
// now use the middle plane of the 3 4x5 planes
cout << "Middle plane, values starting at 100:" << endl;
auto middlePlane = arr[1];
start = 100;
initNDimArr(middlePlane, start);
printNdimArr(middlePlane);
cout << "Whole array now:" << endl;
printNdimArr(arr);
cout << "Print line 2 of the 3rd plane:" << endl;
printNdimArr(arr[2][1]);
cout << endl << "Last number in that row is " << arr[2][1][4] << endl;
}
Sample session:
$>g++ -std=c++11 -o ndimContiguousArr ndimContiguousArr.cpp && ./ndimContiguousArr
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
51 52 53 54 55
56 57 58 59 60
Middle plane, values starting at 100:
100 101 102 103 104
105 106 107 108 109
110 111 112 113 114
115 116 117 118 119
Whole array now:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
100 101 102 103 104
105 106 107 108 109
110 111 112 113 114
115 116 117 118 119
41 42 43 44 45
46 47 48 49 50
51 52 53 54 55
56 57 58 59 60
Print line 2 of the 3rd plane:
46 47 48 49 50
Last number in that row is 50
I realized converting a String into a hexarray now need to convert the new array into a new string,because the function Sha256.write needs a char, which would be the way?
char hexstring[] = "020000009ecb752aac3e6d2101163b36f3e6bd67d0c95be402918f2f00000000000000001036e4ee6f31bc9a690053320286d84fbfe4e5ee0594b4ab72339366b3ff1734270061536c89001900000000";
int i;
int n;
uint8_t bytearray[80];
Serial.println("Starting...");
char tmp[3];
tmp[2] = '\0';
int j = 0;
//GET ARRAY
for(i=0;i<strlen(hexstring);i+=2) {
tmp[0] = hexstring[i];
tmp[1] = hexstring[i+1];
bytearray[j] = strtol(tmp,0,16);
j+=1;
}
for(i=0;i<80;i+=1) {
Serial.println( bytearray[i]);
}
int _batchSize;
unsigned char hash[32];
SHA256_CTX ctx;
int idx;
Serial.println("SHA256...");
for(_batchSize = 100000; _batchSize > 0; _batchSize--){
bytearray[76] = nonce;
// Sha256.write(bytearray);
sha256_init(&ctx);
sha256_update(&ctx,bytearray,80);
sha256_final(&ctx,hash); //
sha256_init(&ctx);
sha256_update(&ctx,hash,32);
sha256_final(&ctx,hash); //are this corrent? i'm need in bytes too
// print_hash(hash);
int zeroBytes = 0;
for (int i = 31; i >= 28; i--, zeroBytes++)
if(hash[i] > 0)
break;
if(zeroBytes == 4){ // SOLUTION TRUE, NOW I'M NEED THIS IN STRING
printf("0x");
for (n = 0; n < 32; n++)
Serial.println(printf("%02x", hash[n])); //ERROR :(
}
//increase
if(++nonce == 4294967295)
nonce = 0;
}
}
}
output array on Serial port:
2
0
0
0
158
203
117
42
172
62
109
33
1
22
59
54
243
230
189
103
208
201
91
228
2
145
143
47
0
0
0
0
0
0
0
0
16
54
228
238
111
49
188
154
105
0
83
50
2
134
216
79
191
228
229
238
5
148
180
171
114
51
147
102
179
255
23
52
39
0
97
83
108
137
0
25
0
0
0
0
how to convert this to a hexstring char back?
UPDATED
this solutions works for me, thanks all!
void printHash(uint8_t* hash) {
int id;
for (id=0; id<32; id++) {
Serial.print("0123456789abcdef"[hash[id]>>4]);
Serial.print("0123456789abcdef"[hash[id]&0xf]);
}
Serial.println();
}
Skip to the section Addressing your code... at bottom for most relevant content
(this stuff up here is barely useful blither)
The purpose of your function:
Sha256.write((char *)bytearray);
I believe is to write more data to the running hash. (from this)
Therefore, I am not sure in the context of your question how to convert this to a hex-string char back? how this relates to the way you are using it.
Let me offer another approach for the sake of illustrating how you might go about returning the array of ints back into the form of a "hexadecimal string":
From Here
Here is a code fragment that will calculate the digest for the string "abc"
SHA256_CTX ctx;
u_int8_t results[SHA256_DIGEST_LENGTH];
char *buf;
int n;
buf = "abc";
n = strlen(buf);
SHA256_Init(&ctx);
SHA256_Update(&ctx, (u_int8_t *)buf, n);
SHA256_Final(results, &ctx);
/* Print the digest as one long hex value */
printf("0x");
for (n = 0; n < SHA256_DIGEST_LENGTH; n++)
printf("%02x", results[n]);
putchar('\n');
resulting in:
"0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad".
In this example The array I believe you want, is contained in u_int8_t results
There is not enough description in your post to be sure this will help, let me know in the comments, and I will try to address further questions.
Added after your edit:
Continuing from the example above, to put the array contents of results back into a string, you can do something like this:
char *newString;
newString = malloc(sizeof(char)*SHA256_DIGEST_LENGTH*2);
memset(newString, 0, sizeof(char)*SHA256_DIGEST_LENGTH*2);
strcat(newString, "0x");
for(i=0;i<SHA256_DIGEST_LENGTH;i++)
{
sprintf(newString, "%s%02x\n", newString, results[i]);
}
//use newString for stuff...
free(newString);
Addressing your code, and your question directly:
Your code block:
for(_batchSize = 100000; _batchSize > 0; _batchSize--){
bytearray[76] = _batchSize;
Sha256.write((char *)bytearray); //here are the error
}
is not necessary if all you want to do is to convert an array of int into a "hexadecimal string"
Your int array, defined as:
int bytearray[80];
Already contains all the necessary values at this point, as you illustrated with your latest edit. If you want to return this data to a "hexadecimal string" form, then this will do that for you: (replacing result with your bytearray)
char *newString;
newString = malloc(sizeof(char)*SHA256_DIGEST_LENGTH*2);//if these defines are not in your environment
memset(newString, 0, sizeof(char)*SHA256_DIGEST_LENGTH*2);//then replace them with appropriate value for length
strcat(newString, "0x");
for(i=0;i<sizeof(bytearray)/sizeof(bytearray[0]);i++)
{
sprintf(newString, "%s%02x\n", newString, bytearray[i]);
}
//use newString for stuff...
free(newString);