Sunteți pe pagina 1din 16

Tree Traversals (Inorder, Preorder and Postorder)

Unlike linear data structures (Array, Linked List, Queues, Stacks, etc) which have only one
Object 1

logical way to traverse them, trees can be traversed in different ways. Following are the

generally used ways for traversing trees.

Example Tree

Depth First Traversals:

(a) Inorder (Left, Root, Right) : 4 2 5 1 3

(b) Preorder (Root, Left, Right) : 1 2 4 5 3

(c) Postorder (Left, Right, Root) : 4 5 2 3 1

Breadth First or Level Order Traversal : 1 2 3 4 5

Please see this post for Breadth First Traversal.

Inorder Traversal:

Algorithm Inorder(tree)
1. Traverse the left subtree, i.e., call Inorder(left-subtree)
2. Visit the root.
3. Traverse the right subtree, i.e., call Inorder(right-subtree)

Uses of Inorder

In case of binary search trees (BST), Inorder traversal gives nodes in non-decreasing order. To

get nodes of BST in non-increasing order, a variation of Inorder traversal where Inorder

traversal s reversed can be used.

Example: Inorder traversal for the above-given figure is 4 2 5 1 3.

Practice Inorder Traversal


Preorder Traversal:

Algorithm Preorder(tree)
1. Visit the root.
2. Traverse the left subtree, i.e., call Preorder(left-subtree)
3. Traverse the right subtree, i.e., call Preorder(right-subtree)

Uses of Preorder

Preorder traversal is used to create a copy of the tree. Preorder traversal is also used to get

prefix expression on of an expression tree. Please

see http://en.wikipedia.org/wiki/Polish_notation to know why prefix expressions are useful.

Example: Preorder traversal for the above given figure is 1 2 4 5 3.

https://practice.geeksforgeeks.org/problems/preorder-traversal/1Practice Preorder Traversal

Postorder Traversal:

Algorithm Postorder(tree)
1. Traverse the left subtree, i.e., call Postorder(left-subtree)
2. Traverse the right subtree, i.e., call Postorder(right-subtree)
3. Visit the root.

Uses of Postorder

Postorder traversal is used to delete the tree. Please see the question for deletion of tree for

details. Postorder traversal is also useful to get the postfix expression of an expression tree.

Please see http://en.wikipedia.org/wiki/Reverse_Polish_notation to for the usage of postfix

expression.

https://practice.geeksforgeeks.org/problems/postorder-traversal/1Practice Postorder

Traversal

Example: Postorder traversal for the above given figure is 4 5 2 3 1.


• C++
• C
• Python
• Java

// C program for different tree traversals


#include <iostream>
using namespace std;

/* A binary tree node has data, pointer to left child


and a pointer to right child */
struct Node
{
int data;
struct Node* left, *right;
Node(int data)
{
this->data = data;
left = right = NULL;
}
};

/* Given a binary tree, print its nodes according to the


"bottom-up" postorder traversal. */
void printPostorder(struct Node* node)
{
if (node == NULL)
return;

// first recur on left subtree


printPostorder(node->left);

// then recur on right subtree


printPostorder(node->right);

// now deal with the node


cout << node->data << " ";
}

/* Given a binary tree, print its nodes in inorder*/


void printInorder(struct Node* node)
{
if (node == NULL)
return;
/* first recur on left child */
printInorder(node->left);

/* then print the data of node */


cout << node->data << " ";

/* now recur on right child */


printInorder(node->right);
}

/* Given a binary tree, print its nodes in preorder*/


void printPreorder(struct Node* node)
{
if (node == NULL)
return;

/* first print data of node */


cout << node->data << " ";

/* then recur on left sutree */


printPreorder(node->left);

/* now recur on right subtree */


printPreorder(node->right);
}

/* Driver program to test above functions*/


int main()
{
struct Node *root = new Node(1);
root->left = new Node(2);
root->right = new Node(3);
root->left->left = new Node(4);
root->left->right = new Node(5);

cout << "\nPreorder traversal of binary tree is \n";


printPreorder(root);

cout << "\nInorder traversal of binary tree is \n";


printInorder(root);

cout << "\nPostorder traversal of binary tree is \n";


printPostorder(root);

return 0;
}
Output:

Preorder traversal of binary tree is


1 2 4 5 3
Inorder traversal of binary tree is
4 2 5 1 3
Postorder traversal of binary tree is
4 5 2 3 1

One more example:

Image Source : https://www.cs.swarthmore.edu/~newhall/unixhelp/Java_bst.pdf

Time Complexity: O(n)

Let us see different corner cases.

Complexity function T(n) — for all problem where tree traversal is involved — can be defined

as:

T(n) = T(k) + T(n – k – 1) + c

Where k is the number of nodes on one side of root and n-k-1 on the other side.

Let’s do an analysis of boundary conditions


Case 1: Skewed tree (One of the subtrees is empty and other subtree is non-empty )

k is 0 in this case.

T(n) = T(0) + T(n-1) + c

T(n) = 2T(0) + T(n-2) + 2c

T(n) = 3T(0) + T(n-3) + 3c

T(n) = 4T(0) + T(n-4) + 4c

…………………………………………

………………………………………….

T(n) = (n-1)T(0) + T(1) + (n-1)c

T(n) = nT(0) + (n)c

Value of T(0) will be some constant say d. (traversing a empty tree will take some constants

time)

T(n) = n(c+d)

T(n) = Θ(n) (Theta of n)

Case 2: Both left and right subtrees have equal number of nodes.

T(n) = 2T(|_n/2_|) + c

This recursive function is in the standard form (T(n) = aT(n/b) + (-)(n) ) for master

method http://en.wikipedia.org/wiki/Master_theorem. If we solve it by master method we get

(-)(n)

Auxiliary Space : If we don’t consider size of stack for function calls then O(1) otherwise O(n).
Part 5: Hashing with SHA-
256
An overview of SHA-256, a standard secure hash
function, as described in official document FIPS 180–4.
This continues a series on bitwise operations and their applications, written by a non-expert, for non-
experts. Follow Biffures for future updates.
Hash functions transform arbitrary large bit strings called messages, into small, fixed-length bit strings
called message digests, such that digestsidentify the messages that produced them with a very high
probability. Digests are in that sense fingerprints: a function of the message, simple, yet complex
enough that they allow identification of their message, with a very low probability that different
messages will share the same digests.
In SHA-256, messages up to 2⁶⁴ bit (2.3 exabytes, or 2.3 billion gigabytes) are transformed into digests
of size 256 bits (32 bytes). For perspective, this means that an object 7 times the size of Facebook’s
data warehouse in 2014passed to SHA-256 would produce a chunk of data the size of a 32-letter string
of ASCII characters, and that string would the object’s very special fingerprint.
A prominent use case of hashing is data integrity verification of large files, which relies on the
comparison of actual and expected message digests, orchecksums. Another is hashing as part of the
encryption/decryption journey. Before a message can be encrypted with an algorithm like RSA, it needs
to be hashed. In the rest of this article, we explore what hashing does to a message, with a view to later
develop a better understanding of RSA.
Step by step hashing with SHA-256
This article now draws heavily from FIPS 180–4 all the while trying to offer some simplifications, but
for the full details you may want to refer to the source material instead. With this in mind:
Pre-processing
1. Padding. If we note M the message to be hashed, and l its length in bits where l < 2⁶⁴, then as a first
step we create the padded message M’, which is message M plus a right padding, such that M’ is of
length l’, a multiple of 512. Specifically, we use a padding P such that M’ is:
l’, a multiple of 512. The inclusion of L in padding P helps avoid trivial collisions (i.e. messages “00”
and “000” would produce identical padded messages in the absence of L). The original message can be
extracted by reading the last 64 for bits for length, and then fetching the message from left to right, of
length l.
2. Blocks. M’ is parsed into N blocks of size 512 bits, M¹ to Mᴺ, and each block is expressed as
16 input blocks of size 32 bits, M₀ to M₁₅.
3. Hash initialization. The initial hash value H⁰ of length 256 bits (8 input blocks of
32 bits) is set by taking the first 32 bits of the fractional parts of the square roots of the
first eight prime numbers:
Those values can be reproduced with the below snippet in most browsers and Node
≥8.2.1 (ECMAScript 2017):
Algorithm
The hash is produced by processing each message block Mⁱ of M’ in order. For each of
message block Mⁱ:
1. Message schedule. We create a message schedule Wⁱ, consisting of four 512-bit
message blocks (each made of 16 input blocks). The first block of Wⁱ is message
block Mⁱ, and the next three blocks are variations of Mⁱ, obtained through the formulas
in the illustration below:
a previous article on Bitwise Patterns.
A detail: note that if we align all message schedules Wⁱ vertically, the first column
reads from top to bottom as the complete message M’ = M¹‖..‖Mᴺ.
2. The big shuffle. The input blocks of message schedule W are fed, one after the
other, to a function represented below as a graph. The graph takes as inputs a
hash ωⁱ(t) and a message schedule input block Wⁱ(t), and outputs a hash ωⁱ(t+1). The
initial hash ωⁱ(0) fed to the graph is the intermediate hash Hⁱ⁻¹: in the case of W¹,
it’s H⁰ defined in the pre-processing step. ωⁱ(0) and Wⁱ(0) produce ωⁱ(1); in
turn ωⁱ(1) and Wⁱ(1)produce ωⁱ(2), etc., until ωⁱ(63) is produced.
⁰ using input blocks from the message schedule W. The operation must be repeated 64
times until ω(63) is produced.
a, .., h are initialized as Hi⁻¹(0), .., Hi⁻¹(7). Sigma0, Sigma1, Ch, and Maj are
functions using AND, XOR and negations; K is a bit word with 64 input blocks.
3. New hash. After all input blocks from Wⁱ have been used and we ω(63) has been
created, we can create the new hash Hⁱ such that each input block of Hⁱ is the sum of
the corresponding input block of Hⁱ⁻¹ plus the corresponding input block of ωⁱ(63):
Hⁱ(j) = Hⁱ⁻¹(j) + ωⁱ(63)(j) where + is the addition modulo 2ⁿ
If other message blocks Mⁱ remain, repeat the process (message schedule, big shuffle,
creation of the new hash Hⁱ)
If Wⁱ was the last message schedule, then Hⁱ = H is message M’s final hash or digest—    
its so very special fingerprint.
This concludes the overview of SHA-256 as described in FIPS 180–4. A few closing thoughts:
• SHA-256 projects into B²⁵⁶, a space of ~1e77 possible values, which is lots of potential digests: a
good thing that provides the intuition that collisions are unlikely
• That being said, we do not prove here that collisions are unlikely, we even know they
exist given the surjective nature of the hashing function. We know however that (i) given a limited
amount of things to hash, we’re unlikely to find collisions (ii) no collisions have been found to
date for SHA-256.
• Finally, coding your own SHA-256 for production use is probably not a good idea…

…but just for fun and education purposes, here is a version I wrote in JavaScript. Thanks for reading,
hope you enjoyed, and see you next time for a review of RSA.
'use strict';

(function (shs) {
const H0 = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
0x5be0cd19,
];
const K = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,
0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc,
0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351,
0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e,
0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585,
0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
0xc67178f2,
];
/**
* Rotate to right
* @param {number} x - An integer to be shifted right
* @param {number} n - The number of bits by which to shift
* @param {string} [w] - The bit notation width. Defaults to x.toString(2).length
* @return {number} The shifted number
*/
function rotr(x, n, w) {
if (!w) { var w = x.toString(2).length; }
n = n % w;
return ((x >>> n) | (x << w - n)) >>> 0 % Math.pow(2, w);
};
/**
* Rotate to left
* @param {number} x - An integer to be shifted right
* @param {number} n - The number of bits by which to shift
* @return {number} The shifted number
*/
function rotl(x, n) {
let w = x.toString(2).length;
n = n % w;
return ((x << n) | (x >>> w - n)) >>> 0 % Math.pow(2, w);
};
/**
* SHA-256 logical functions
*/
function Ch(x, y, z) { return (x & y) ^ (~x & z); };
function Maj(x, y, z) { return (x & y) ^ (x & z) ^ (y & z); };
function Σ0(x) { return rotr(x, 2, 32) ^ rotr(x, 13, 32) ^ rotr(x, 22, 32); };
function Σ1(x) { return rotr(x, 6, 32) ^ rotr(x, 11, 32) ^ rotr(x, 25, 32); };
function σ0(x) { return rotr(x, 7, 32) ^ rotr(x, 18, 32) ^ (x >>> 3); };
function σ1(x) { return rotr(x, 17, 32) ^ rotr(x, 19, 32) ^ (x >>> 10); };
/**
* Padding
* @param {string} m - The message, a binary string (e.g., 011010)
* @return {string} A padded message
*/
function pad(m) {
if (m.length > Math.pow(2, 64)) {
return console.error('Message out of range.');
}
let padding1 = '0'.repeat(512 - ((m.length + 1 + 64) % 512));
let padding2 = '0'.repeat(64 - m.length.toString(2).length);
return `${m}1${padding1}${padding2}${m.length.toString(2)}`;
}
/**
* Parse
* @param {string} paddedMessage - A padded message of length N x 512
* @return {array} An array containing 512 segments, further split in 32-bit segments
* expressed as numbers
*/
function parse(m) {
let M = m.match(/[0-1]{512}/g);
return M.map((x) => {
let arr = x.match(/[0-1]{32}/g);
return arr.map((x) => {
return parseInt(x, 2);
});
});
};
/**
* Hash
* @param {string} m - A binary string to be hashed
* @return {string} A SHA-256 digest
*/
shs.hash = function (m) {
// Pre-processing
let M = parse(pad(m));
// Initialize the hash
let H = [H0];
// Hash computation
for (let i = 0, N = M.length; i < N; i++) {
// Prepare the message schedule
let W = [];
for (let t = 0; t < 64; t++) {
if (t <= 15) {
W[t] = M[i][t];
} else {
W[t] = (σ1(W[t - 2]) + W[t - 7] + σ0(W[t - 15]) + W[t - 16]) % Math.pow(2, 32);
}
}
// Initialize the working variables
let a = H[i][0];
let b = H[i][1];
let c = H[i][2];
let d = H[i][3];
let e = H[i][4];
let f = H[i][5];
let g = H[i][6];
let h = H[i][7];
let T1;
let T2;
// Do stuff
for (let t = 0; t < 64; t++) {
T1 = (h + Σ1(e) + Ch(e, f, g) + K[t] + W[t]) % Math.pow(2, 32);
T2 = (Σ0(a) + Maj(a, b, c)) % Math.pow(2, 32);
h = g;
g = f;
f = e;
e = (d + T1) % Math.pow(2, 32);
d = c;
c = b;
b = a;
a = (T1 + T2) % Math.pow(2, 32);
}
// Compute the i-th intermediate hash
H[i + 1] = [];
H[i + 1][0] = (a + H[i][0]) % Math.pow(2, 32);
H[i + 1][1] = (b + H[i][1]) % Math.pow(2, 32);
H[i + 1][2] = (c + H[i][2]) % Math.pow(2, 32);
H[i + 1][3] = (d + H[i][3]) % Math.pow(2, 32);
H[i + 1][4] = (e + H[i][4]) % Math.pow(2, 32);
H[i + 1][5] = (f + H[i][5]) % Math.pow(2, 32);
H[i + 1][6] = (g + H[i][6]) % Math.pow(2, 32);
H[i + 1][7] = (h + H[i][7]) % Math.pow(2, 32);
}
let digestWords = H[M.length];
let digestTemp = digestWords.map((x) => {
let hex = (x >>> 0).toString(16);
return `${'0'.repeat(8 - hex.length)}${hex}`;
});
let digest = digestTemp.join('');
return digest;
};
/**
* Hash a UTF-8 string
* @param {string} string - A string, encoded using UTF-8
* @return {string} A SHA-256 digest
*/
shs.hashString = function (str) {
return shs.hash(helpers.toUTF8OctetString(str).replace(/ /g, '')); // remove whitespqces
}
}(window.shs = window.shs || {}));
view raw_sha256.js hosted with ❤ by GitHub

'use strict';
(function (helpers) {
/**
* Converts binary code point into a UTF-8 binary string
* @param {number} codepoint - A Unicode codepoint as a number
* @return {string} The UTF-8 binary string for that codepoint
*/
function codePointToUtf8BinaryNotation(codePoint) {
const str = codePoint.toString(2);
const len = str.length;
// 0xxxxxxx
if (len <= 7) {
let padding = '0'.repeat(7 - len);
return `0${padding}${str}`;
}
// 110xxxxx 10xxxxxx
else if (len <= 11) {
let padding = '0'.repeat(11 - len);
return `110${padding}${str.slice(0, -6)} 10${str.slice(-6)}`;
}
// 1110xxxx 10xxxxxx 10xxxxxx
else if (len <= 16) {
let padding = '0'.repeat(16 - len);
return `1110${padding}${str.slice(0, -12)} 10${str.slice(-12, -6)} 10${str.slice(-6)}`;
}
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
else if (len <= 21) {
// Special case where bits can still fit in the last 3 octets
if (len == 17) {
return `11110000 100${str.slice(0, -12)} 10${str.slice(-12, -6)} 10${str.slice(-6)}`;
}
let padding = '0'.repeat(21 - len);
return `11110${padding}${str.slice(0, -18)} 10${str.slice(-18, -12)} 10${str.slice(-12, -6)} 10${str.slice(-
6)}`;
}
// Error
else {
console.error('Did not receive a valid Unicode binaryNotation');
}
};
/**
* Converts a human-readble string into a UTF-8 binary string
* @param {string} str - A human-readable string
* @return {string} An octet string
*/
helpers.toUTF8OctetString = function (str) {
let octetStringArray = [];
// Use for..of to avoid counting of surrogate pairs
// see: https://mathiasbynens.be/notes/javascript-unicode
for (let symbol of str) {
let codePoint = symbol.codePointAt(0);
let utf8BinaryNotation = codePointToUtf8BinaryNotation(codePoint);
octetStringArray.push(utf8BinaryNotation);
};
return octetStringArray.join(' ');
};
/**
* Converts a UTF-8 octet string in human-readable formate
* @param {string} str - A UTF-8 octet string in binary format
* @return {string} A human-readable string
*/
helpers.fromUTF8OctetString = function (str) {
let octetStringArray = str.split(' ');
let i = 0;
let output = [];
while (i < octetStringArray.length) {
// 0xxxxxxx
if (octetStringArray[i].slice(0, 1) == '0') {
let codeUnit = octetStringArray.slice(i, i + 1).join(' ');
let codePointBin = codeUnit.slice(1);
let codePoint = parseInt(codePointBin, 2);
output.push(String.fromCodePoint(codePoint));
i += 1;
}
// 110xxxxx 10xxxxxx
else if (octetStringArray[i].slice(0, 3) == '110') {
let codeUnit = octetStringArray.slice(i, i + 2).join(' ');
let codePointBin = `${codeUnit.slice(3, 8)}${codeUnit.slice(11)}`;
let codePoint = parseInt(codePointBin, 2);
output.push(String.fromCodePoint(codePoint));
i += 2;
}
// 1110xxxx 10xxxxxx 10xxxxxx
else if (octetStringArray[i].slice(0, 4) == '1110') {
let codeUnit = octetStringArray.slice(i, i + 3).join(' ');
let codePointBin = `${codeUnit.slice(4, 8)}${codeUnit.slice(11, 17)}${codeUnit.slice(20)}`;
let codePoint = parseInt(codePointBin, 2);
output.push(String.fromCodePoint(codePoint));
i += 3;
}
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
else if (octetStringArray[i].slice(0, 5) == '11110') {
let codeUnit = octetStringArray.slice(i, i + 4).join(' ');
let codePointBin = `${codeUnit.slice(4, 8)}${codeUnit.slice(11, 17)}${codeUnit.slice(20, 26)}$
{codeUnit.slice(29)}`;
let codePoint = parseInt(codePointBin, 2);
output.push(String.fromCodePoint(codePoint));
i += 4;
}
// Else, there is an error
else {
return console.error('Unexpected UTF-8 octet');
}
}
return output.join('');
};

}(window.helpers = window.helpers || {}));


view rawhelpers.js hosted with ❤ by GitHub
down vote

In SHA-512 the size of the blocks is 1024 bit. The last block must contain:
• the rest of data in message (mod 1024).
• some filling (padding)
• the last 128 bits as length

If the message is 1919 bit length:


1. Calculate the size of the data in the last block: 1919mod1024=895
2. Add the size of length field(128 bit) to the last block size(895 bit), 128+895=1023
3. See that we have to add 1 bit as padding to the last block to became 1024 bit
The answer will be:
• size of padding field = 1 bit
• data of padding field = 1
• data of length field = 1919 as an unsigned 128-bit big
endian integer 0x0000000000000000000000000000077F

S-ar putea să vă placă și