How to encode 3 integer values into an uint16_t using bitwise operations? - c++11

I want to store 3 unsigned integer values into an uint16_t variable by doing bitwise operations and read them back using bitwise operations. Following is my program to do that:
Code:
#include <iostream>
uint16_t Write(unsigned int iVal1, unsigned int iVal2, unsigned int iVal3) {
// iVal1 should go into the first 8 bits [iVal1 value ranges from 0 to 173]
// iVal2 should go into the 6 bits after that [iVal2 value ranges from 0 to 63]
// iVal3 should go into the 2 bits after that [iVal3 value ranges from 0 to 3]
// Is the below way of writing the bits correct?
return (static_cast<uint16_t>(iVal1)<<8) + (static_cast<uint16_t>(iVal2)<<6) + (static_cast<uint16_t>(iVal3)<<2);
}
unsigned int ReadVal1(const uint16_t theNumber) {
// ival1 is the first 8 bits
uint16_t check1 = 255;
return (theNumber>>8)&check1;
}
unsigned int ReadVal2(const uint16_t theNumber) {
// ival2 is the 6 bits after that
uint16_t check2 = 63;
return (theNumber>>3)&check2;
}
unsigned int ReadVal3(const uint16_t theNumber) {
// ival3 is the last 2 bits
uint16_t check3 = 3;
return (theNumber>>1)&check3;
}
int main() {
std::cout << "Main started" << std::endl;
unsigned int iVal1 = 191;
unsigned int iVal2 = 28;
unsigned int iVal3 = 3;
const uint16_t theNumber = Write(iVal1, iVal2, iVal3);
std::cout << "The first 8 bits contain the number: " << ReadVal1(theNumber) << std::endl;
std::cout << "Then after 6 bits contain the number: " << ReadVal2(theNumber) << std::endl;
std::cout << "Then after 2 bits contain the number: " << ReadVal3(theNumber) << std::endl;
}
In above program following are the ranges of the 3 unsigned integers that need to be encoded.
`iVal1` ranges from `0 to 173`. So its well within 8 bits.
`iVal2` ranges from `0 to 63`. So its well within 6 bits.
`iVal3` ranges from `0 to 3`. So its well within 2 bits.
Question:
I think that the way I am writing the values inside the function Write is wrong. What is the correct way?
Primarily, I am looking for a good explanation of how the encoding using bitwise operation works especially in the context of the goal of my program above.
I believe that my way of reading the values in the functions ReadVal1, ReadVal2 and ReadVal3 is correct. I have figured out the trick of how to read back the values which seems easy. But, I could not well understand the logic of how to encode the values correctly using bitwise operations.
C++ compiler:
I am using a C++11 compiler

The number of bits to shift an integer should not depend on the size of the integer being shifted, but on the size of all the integers that come after it (to the right). Here's some ASCII art to illustrate the principle:
+---+---+---+---+---+---+---+---+
‖i1 |i1 |i1 |i1 |i1 |i1 |i1 |i1 ‖ 8 bit
‖ 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 ‖
+---+---+---+---+---+---+---+---+
_______________________________/
/
| +---+---+---+---+---+---+
| ‖i2 |i2 |i2 |i2 |i2 |i2 ‖ 6 bit
| ‖ 5 | 4 | 3 | 2 | 1 | 0 ‖
| +---+---+---+---+---+---+
| ________/
| /
| |+---+---+
| |‖i3 |i3 ‖ 2 bit
| |‖ 1 | 0 ‖
| |+---+---+
| \ |
|<<(6+2) |<<2 |<<0
v v v
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
‖ F | E | D | C | B | A | 9 | 8 ‖ 7 | 6 | 5 | 4 | 3 | 2 ‖ 1 | 0 ‖
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
‖i1 |i1 |i1 |i1 |i1 |i1 |i1 |i1 ‖i2 |i2 |i2 |i2 |i2 |i2 ‖i3 |i3 ‖
‖ 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 ‖ 5 | 4 | 3 | 2 | 1 | 0 ‖ 1 | 0 ‖
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

Related

How can I modify bit in position in Go?

I tried to modify bit at a certain position, but ran into a problem.
For example I have 1000000001, how can I modify it to 0000000001?
You can apply a bitmask to only keep the bits you are interested in.
In this case if you only want the last bit, you apply the bitmask 0b0000000001
https://go.dev/play/p/RNQEcON7sw1
// 'x' is your value
x := 0b1000000001
// Make the bitmask
mask := 0b0000000001
// Apply the bitmask with bitwise AND
output := x&mask
fmt.Println("This value == 1: ", output)
Explaination
& is a bitwise operator for "AND". Which means it goes through both values bit by bit and sets the resulting bit to 1 if and only if both input bits are 1. I included a truth table for the AND operator below.
+-----------+----------+--------------+
| Input Bit | Mask Bit | Input & Mask |
+-----------+----------+--------------+
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
+-----------+----------+--------------+
Because my mask function only has a 1 in the last position, only the last position of the original input is kept. All preceding bits will always be 0.
Construct a mask that has a one in every place you want to manipulate
Use bitwise OR to set bits.
Use bitwise AND with the inverse mask to clear bits.
Use XOR to toggle a bits
package main
import "fmt"
func main() {
k := 3 // manipulate the 3rd bit ...
mask := uint8(1) << (k - 1) // ... using 0b00000100 as a mask
var n uint8 = 0b10101010
fmt.Printf("0b%08b\n", n) // 0b10101010
// set kth bit
n |= mask
fmt.Printf("0b%08b\n", n) // 0b10101110
// clear kth bit
n &^= mask // &^ is Go's AND NOT operator
fmt.Printf("0b%08b\n", n) // 0b10101010
// toggle kth bit
n ^= mask
fmt.Printf("0b%08b\n", n) // 0b10101110
}
func test() {
i := 1 << 9 //1000000000
i = i | (1 << 8) //1000000000 | 0100000000 == 1100000000
i = i | (1 << 7) //1100000000 | 0010000000 == 1110000000
i = i | (1 << 0) //1110000000 | 0000000001 == 1110000001
fmt.Printf("BEFORE: %010b\n", i) // 1110000001
i = i & ((1 << 9) - 1) // 1110000001 & ((1000000000) - 1) == 1110000001 & (0111111111) == 0110000001
fmt.Printf("AFTER: %010b\n", i) // 0110000001
}

What is the meaning of `x & -x`? [duplicate]

What is the meaning of (number) & (-number)? I have searched it but was unable to find the meaning
I want to use i & (-i) in for loop like:
for (i = 0; i <= n; i += i & (-i))
Assuming 2's complement (or that i is unsigned), -i is equal to ~i+1.
i & (~i + 1) is a trick to extract the lowest set bit of i.
It works because what +1 actually does is to set the lowest clear bit, and clear all bits lower than that. So the only bit that is set in both i and ~i+1 is the lowest set bit from i (that is, the lowest clear bit in ~i). The bits lower than that are clear in ~i+1, and the bits higher than that are non-equal between i and ~i.
Using it in a loop seems odd unless the loop body modifies i, because i = i & (-i) is an idempotent operation: doing it twice gives the same result again.
[Edit: in a comment elsewhere you point out that the code is actually i += i & (-i). So what that does for non-zero i is to clear the lowest group of set bits of i, and set the next clear bit above that, for example 101100 -> 110000. For i with no clear bit higher than the lowest set bit (including i = 0), it sets i to 0. So if it weren't for the fact that i starts at 0, each loop would increase i by at least twice as much as the previous loop, sometimes more, until eventually it exceeds n and breaks or goes to 0 and loops forever.
It would normally be inexcusable to write code like this without a comment, but depending on the domain of the problem maybe this is an "obvious" sequence of values to loop over.]
I thought I'd just take a moment to show how this works. This code gives you the lowest set bit's value:
int i = 0xFFFFFFFF; //Last byte is 1111(base 2), -1(base 10)
int j = -i; //-(-1) == 1
int k = i&j; // 1111(2) = -1(10)
// & 0001(2) = 1(10)
// ------------------
// 0001(2) = 1(10). So the lowest set bit here is the 1's bit
int i = 0x80; //Last 2 bytes are 1000 0000(base 2), 128(base 10)
int j = -i; //-(128) == -128
int k = i&j; // ...0000 0000 1000 0000(2) = 128(10)
// & ...1111 1111 1000 0000(2) = -128(10)
// ---------------------------
// 1000 0000(2) = 128(10). So the lowest set bit here is the 128's bit
int i = 0xFFFFFFC0; //Last 2 bytes are 1100 0000(base 2), -64(base 10)
int j = -i; //-(-64) == 64
int k = i&j; // 1100 0000(2) = -64(10)
// & 0100 0000(2) = 64(10)
// ------------------
// 0100 0000(2) = 64(10). So the lowest set bit here is the 64's bit
It works the same for unsigned values, the result is always the lowest set bit's value.
Given your loop:
for(i=0;i<=n;i=i&(-i))
There are no bits set (i=0) so you're going to get back a 0 for the increment step of this operation. So this loop will go on forever unless n=0 or i is modified.
Assuming that negative values are using two's complement. Then -number can be calculated as (~number)+1, flip the bits and add 1.
For example if number = 92. Then this is what it would look like in binary:
number 0000 0000 0000 0000 0000 0000 0101 1100
~number 1111 1111 1111 1111 1111 1111 1010 0011
(~number) + 1 1111 1111 1111 1111 1111 1111 1010 0100
-number 1111 1111 1111 1111 1111 1111 1010 0100
(number) & (-number) 0000 0000 0000 0000 0000 0000 0000 0100
You can see from the example above that (number) & (-number) gives you the least bit.
You can see the code run online on IDE One: http://ideone.com/WzpxSD
Here is some C code:
#include <iostream>
#include <bitset>
#include <stdio.h>
using namespace std;
void printIntBits(int num);
void printExpression(char *text, int value);
int main() {
int number = 92;
printExpression("number", number);
printExpression("~number", ~number);
printExpression("(~number) + 1", (~number) + 1);
printExpression("-number", -number);
printExpression("(number) & (-number)", (number) & (-number));
return 0;
}
void printExpression(char *text, int value) {
printf("%-20s", text);
printIntBits(value);
printf("\n");
}
void printIntBits(int num) {
for(int i = 0; i < 8; i++) {
int mask = (0xF0000000 >> (i * 4));
int portion = (num & mask) >> ((7 - i) * 4);
cout << " " << std::bitset<4>(portion);
}
}
Also here is a version in C# .NET: https://dotnetfiddle.net/ai7Eq6
The operation i & -i is used for isolating the least significant non-zero bit of the corresponding integer.
In binary notation num can be represented as a1b, where a represents binary digits before the last bit and b represents zeroes after the last bit.
-num is equal to (a1b)¯ + 1 = a¯0b¯ + 1. b consists of all zeroes, so b¯ consists of all ones.
-num = (a1b)¯ + 1 => a¯0b¯ + 1 => a¯0(0…0)¯ + 1 => ¯0(1…1) + 1 => a¯1(0…0) => a¯1b
Now, num & -num => a1b & a¯1b => (0..0)1(0..0)
For e.g. if i = 5
| iteration | i | last bit position | i & -i|
|-------- |--------|-------- |-----|
| 1 | 5 = 101 | 0 | 1 (2^0)|
| 2 | 6 = 110 | 1 | 2 (2^1)|
| 3 | 8 = 1000 | 3 | 8 (2^3)|
| 4 | 16 = 10000 | 4 | 16 (2^4)|
| 5 | 32 = 100000 | 5 | 32 (2^5)|
This operation in mainly used in Binary Indexed Trees to move up and down the tree
PS: For some reason stackoverflow is treating table as code :(

the data method of vector has some wrong

I use the data method of vector in C++, but I have some problems, the code is in belows:
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector (5);
int* p = myvector.data();
*p = 10;
++p;
*p = 20;
p[2] = 100;
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i];
std::cout << '\n';
return 0;
}
the result is myvector contains: 10 20 0 100 0, but why the result is not myvector contains: 10 20 100 0 0, the first one *p = 10; is 10, the second one ++p;*p = 20; is 20, that's all right, but the third one p[2] = 100; should be 100, but it is 0, why?
With visuals:
std::vector<int> myvector (5);
// ---------------------
// | 0 | 0 | 0 | 0 | 0 |
// ---------------------
int* p = myvector.data();
// ---------------------
// | 0 | 0 | 0 | 0 | 0 |
// ---------------------
// ^
// p
*p = 10;
// ----------------------
// | 10 | 0 | 0 | 0 | 0 |
// ----------------------
// ^
// p
++p;
// ----------------------
// | 10 | 0 | 0 | 0 | 0 |
// ----------------------
// ^
// p
*p = 20;
// ----------------------
// | 10 | 20 | 0 | 0 | 0 |
// ----------------------
// ^
// p
p[2] = 100;
// -------------------------
// | 10 | 20 | 0 | 100 | 0 |
// -------------------------
// ^ ^
// p p[2]
It's helpful to remember that p[2] is a shorter way to say *(p + 2).
Because you are modifying p itself.
After ++p (which I remember you it's equivalent to p = p + 1), p points to the element at index 1, so p[2] points at element at index 3 from the beginning of the vector which is why the fourth element is changed instead.
After ++p, pointer p is pointing to myvector[1].
Then we have:
p[0] pointing to myvector[1]
p[1] pointing to myvector[2]
p[2] pointing to myvector[3]

Understanding the Recursion of mergesort

Most of the mergesort implementations I see are similar to this. intro to algorithms book along with online implentations I search for. My recursion chops don't go much further than messing with Fibonacci generation (which was simple enough) so maybe it's the multiple recursions blowing my mind, but I can't even step through the code and understand whats going on even before I even hit the merge function.
How is it stepping through this? Is there some strategy or reading I should undergo to better understand the process here?
void mergesort(int *a, int*b, int low, int high)
{
int pivot;
if(low<high)
{
pivot=(low+high)/2;
mergesort(a,b,low,pivot);
mergesort(a,b,pivot+1,high);
merge(a,b,low,pivot,high);
}
}
and the merge(although frankly I'm mentally stuck before I even get to this part)
void merge(int *a, int *b, int low, int pivot, int high)
{
int h,i,j,k;
h=low;
i=low;
j=pivot+1;
while((h<=pivot)&&(j<=high))
{
if(a[h]<=a[j])
{
b[i]=a[h];
h++;
}
else
{
b[i]=a[j];
j++;
}
i++;
}
if(h>pivot)
{
for(k=j; k<=high; k++)
{
b[i]=a[k];
i++;
}
}
else
{
for(k=h; k<=pivot; k++)
{
b[i]=a[k];
i++;
}
}
for(k=low; k<=high; k++) a[k]=b[k];
}
MERGE SORT:
1) Split the array in half
2) Sort the left half
3) Sort the right half
4) Merge the two halves together
I think the "sort" function name in MergeSort is a bit of a misnomer, it should really be called "divide".
Here is a visualization of the algorithm in process.
Each time the function recurses, it's working on a smaller and smaller subdivision of the input array, starting with the left half of it. Each time the function returns from recursion, it will continue on and either start working on the right half, or recurse up again and work on a larger half.
Like this
[************************]mergesort
[************]mergesort(lo,mid)
[******]mergesort(lo,mid)
[***]mergesort(lo,mid)
[**]mergesort(lo,mid)
[**]mergesort(mid+1,hi)
[***]merge
[***]mergesort(mid+1,hi)
[**]mergesort*(lo,mid)
[**]mergesort(mid+1,hi)
[***]merge
[******]merge
[******]mergesort(mid+1,hi)
[***]mergesort(lo,mid)
[**]mergesort(lo,mid)
[**]mergesort(mid+1,hi)
[***]merge
[***]mergesort(mid+1,hi)
[**]mergesort(lo,mid)
[**]mergesort(mid+1,hi)
[***]merge
[******]merge
[************]merge
[************]mergesort(mid+1,hi)
[******]mergesort(lo,mid)
[***]mergesort(lo,mid)
[**]mergesort(lo,mid)
[**]mergesort(mid+1,hi)
[***]merge
[***]mergesort(mid+1,hi)
[**]mergesort(lo,mid)
[**]mergesort(mid+1,hi)
[***]merge
[******]merge
[******]mergesort(mid+1,hi)
[***]mergesort(lo,mid)
[**]mergesort*(lo,mid)
[**]mergesort(mid+1,hi)
[***]merge
[***]mergesort(mid+1,hi)
[**]mergesort(lo,mid)
[**]mergesort(mid+1,hi)
[***]merge
[******]merge
[************]merge
[************************]merge
An obvious thing to do would be to try this merge sort on a small array, say size 8 (power of 2 is convenient here), on paper. Pretend you are a computer executing the code, and see if it starts to become a bit clearer.
Your question is a bit ambiguous because you don't explain what you find confusing, but it sounds like you are trying to unroll the recursive calls in your head. Which may or may not be a good thing, but I think it can easily lead to having too much in your head at once. Instead of trying to trace the code from start to end, see if you can understand the concept abstractly. Merge sort:
Splits the array in half
Sorts the left half
Sorts the right half
Merges the two halves together
(1) should be fairly obvious and intuitive to you. For step (2) the key insight is this, the left half of an array... is an array. Assuming your merge sort works, it should be able to sort the left half of the array. Right? Step (4) is actually a pretty intuitive part of the algorithm. An example should make it trivial:
at the start
left: [1, 3, 5], right: [2, 4, 6, 7], out: []
after step 1
left: [3, 5], right: [2, 4, 6, 7], out: [1]
after step 2
left: [3, 5], right: [4, 6, 7], out: [1, 2]
after step 3
left: [5], right: [4, 6, 7], out: [1, 2, 3]
after step 4
left: [5], right: [6, 7], out: [1, 2, 3, 4]
after step 5
left: [], right: [6, 7], out: [1, 2, 3, 4, 5]
after step 6
left: [], right: [7], out: [1, 2, 3, 4, 5, 6]
at the end
left: [], right: [], out: [1, 2, 3, 4, 5, 6, 7]
So assuming that you understand (1) and (4), another way to think of merge sort would be this. Imagine someone else wrote mergesort() and you're confident that it works. Then you could use that implementation of mergesort() to write:
sort(myArray)
{
leftHalf = myArray.subArray(0, myArray.Length/2);
rightHalf = myArray.subArray(myArray.Length/2 + 1, myArray.Length - 1);
sortedLeftHalf = mergesort(leftHalf);
sortedRightHalf = mergesort(rightHalf);
sortedArray = merge(sortedLeftHalf, sortedRightHalf);
}
Note that sort doesn't use recursion. It just says "sort both halves and then merge them". If you understood the merge example above then hopefully you see intuitively that this sort function seems to do what it says... sort.
Now, if you look at it more carefully... sort() looks pretty much exactly like mergesort()! That's because it is mergesort() (except it doesn't have base cases because it's not recursive!).
But that's how I like thinking of recursive functions--assume that the function works when you call it. Treat it as a black box that does what you need it to. When you make that assumption, figuring out how to fill in that black box is often easy. For a given input, can you break it down into smaller inputs to feed to your black box? After you solve that, the only thing that's left is handling the base cases at the start of your function (which are the cases where you don't need to make any recursive calls. For example, mergesort([]) just returns an empty array; it doesn't make a recursive call to mergesort()).
Finally, this is a bit abstract, but a good way to understand recursion is actually to write mathematical proofs using induction. The same strategy used to write an proof by induction is used to write a recursive function:
Math proof:
Show the claim is true for the base cases
Assume it is true for inputs smaller than some n
Use that assumption to show that it is still true for an input of size n
Recursive function:
Handle the base cases
Assume that your recursive function works on inputs smaller than some n
Use that assumption to handle an input of size n
Concerning the recursion part of the merge sort, I've found this page to be very very helpful. You can follow the code as it's being executed. It shows you what gets executed first, and what follows next.
Tom
the mergesort() simply divides the array in two halves until the if condition fails that is low < high. As you are calling mergesort() twice : one with low to pivot and second with pivot+1 to high, this will divide the sub arrays even more further.
Lets take an example :
a[] = {9,7,2,5,6,3,4}
pivot = 0+6/2 (which will be 3)
=> first mergesort will recurse with array {9,7,2} : Left Array
=> second will pass the array {5,6,3,4} : Right Array
It will repeat until you have 1 element in each left as well as right array.
In the end you'll have something similar to this :
L : {9} {7} {2} R : {5} {6} {3} {4} (each L and R will have further sub L and R)
=> which on call to merge will become
L(L{7,9} R{2}) : R(L{5,6} R{3,4})
As you can see that each sub array are getting sorted in the merge function.
=> on next call to merge the next L and R sub arrays will get in order
L{2,7,9} : R{3,4,5,6}
Now both L and R sub array are sorted within
On last call to merge they'll be merged in order
Final Array would be sorted => {2,3,4,5,6,7,9}
See the merging steps in answer given by #roliu
My apologies if this has been answered this way. I acknowledge that this is just a sketch, rather than a deep explanation.
While it is not obvious to see how the actual code maps to the recursion, I was able to understand the recursion in a general sense this way.
Take a the example unsorted set {2,9,7,5} as input. The merge_sort algorithm is denoted by "ms" for brevity below. Then we can sketch the operation as:
step 1: ms( ms( ms(2),ms(9) ), ms( ms(7),ms(5) ) )
step 2: ms( ms({2},{9}), ms({7},{5}) )
step 3: ms( {2,9}, {5,7} )
step 4: {2,5,7,9}
It is important to note that merge_sort of a singlet (like {2}) is simply the singlet (ms(2) = {2}), so that at the deepest level of recursion we get our first answer. The remaining answers then tumble like dominoes as the interior recursions finish and are merged together.
Part of the genius of the algorithm is the way it builds the recursive formula of step 1 automatically through its construction. What helped me was the exercise of thinking how to turn step 1 above from a static formula to a general recursion.
Trying to work out each and every step of a recursion is often not an ideal approach, but for beginners, it definitely helps to understand the basic idea behind recursion, and also to get better at writing recursive functions.
Here's a C solution to Merge Sort :-
#include <stdio.h>
#include <stdlib.h>
void merge_sort(int *, unsigned);
void merge(int *, int *, int *, unsigned, unsigned);
int main(void)
{
unsigned size;
printf("Enter the no. of integers to be sorted: ");
scanf("%u", &size);
int * arr = (int *) malloc(size * sizeof(int));
if (arr == NULL)
exit(EXIT_FAILURE);
printf("Enter %u integers: ", size);
for (unsigned i = 0; i < size; i++)
scanf("%d", &arr[i]);
merge_sort(arr, size);
printf("\nSorted array: ");
for (unsigned i = 0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
free(arr);
return EXIT_SUCCESS;
}
void merge_sort(int * arr, unsigned size)
{
if (size > 1)
{
unsigned left_size = size / 2;
int * left = (int *) malloc(left_size * sizeof(int));
if (left == NULL)
exit(EXIT_FAILURE);
for (unsigned i = 0; i < left_size; i++)
left[i] = arr[i];
unsigned right_size = size - left_size;
int * right = (int *) malloc(right_size * sizeof(int));
if (right == NULL)
exit(EXIT_FAILURE);
for (unsigned i = 0; i < right_size; i++)
right[i] = arr[i + left_size];
merge_sort(left, left_size);
merge_sort(right, right_size);
merge(arr, left, right, left_size, right_size);
free(left);
free(right);
}
}
/*
This merge() function takes a target array (arr) and two sorted arrays (left and right),
all three of them allocated beforehand in some other function(s).
It then merges the two sorted arrays (left and right) into a single sorted array (arr).
It should be ensured that the size of arr is equal to the size of left plus the size of right.
*/
void merge(int * arr, int * left, int * right, unsigned left_size, unsigned right_size)
{
unsigned i = 0, j = 0, k = 0;
while ((i < left_size) && (j < right_size))
{
if (left[i] <= right[j])
arr[k++] = left[i++];
else
arr[k++] = right[j++];
}
while (i < left_size)
arr[k++] = left[i++];
while (j < right_size)
arr[k++] = right[j++];
}
Here's the step-by-step explanation of the recursion :-
Let arr be [1,4,0,3,7,9,8], having the address 0x0000.
In main(), merge_sort(arr, 7) is called, which is the same as merge_sort(0x0000, 7).
After all of the recursions are completed, arr (0x0000) becomes [0,1,3,4,7,8,9].
| | |
| | |
| | |
| | |
| | |
arr - 0x0000 - [1,4,0,3,7,9,8] | | |
size - 7 | | |
| | |
left = malloc() - 0x1000a (say) - [1,4,0] | | |
left_size - 3 | | |
| | |
right = malloc() - 0x1000b (say) - [3,7,9,8] | | |
right_size - 4 | | |
| | |
merge_sort(left, left_size) -------------------> | arr - 0x1000a - [1,4,0] | |
| size - 3 | |
| | |
| left = malloc() - 0x2000a (say) - [1] | |
| left_size = 1 | |
| | |
| right = malloc() - 0x2000b (say) - [4,0] | |
| right_size = 2 | |
| | |
| merge_sort(left, left_size) -------------------> | arr - 0x2000a - [1] |
| | size - 1 |
| left - 0x2000a - [1] <-------------------------- | (0x2000a has only 1 element) |
| | |
| | |
| merge_sort(right, right_size) -----------------> | arr - 0x2000b - [4,0] |
| | size - 2 |
| | |
| | left = malloc() - 0x3000a (say) - [4] |
| | left_size = 1 |
| | |
| | right = malloc() - 0x3000b (say) - [0] |
| | right_size = 1 |
| | |
| | merge_sort(left, left_size) -------------------> | arr - 0x3000a - [4]
| | | size - 1
| | left - 0x3000a - [4] <-------------------------- | (0x3000a has only 1 element)
| | |
| | |
| | merge_sort(right, right_size) -----------------> | arr - 0x3000b - [0]
| | | size - 1
| | right - 0x3000b - [0] <------------------------- | (0x3000b has only 1 element)
| | |
| | |
| | merge(arr, left, right, left_size, right_size) |
| | i.e. merge(0x2000b, 0x3000a, 0x3000b, 1, 1) |
| right - 0x2000b - [0,4] <----------------------- | (0x2000b is now sorted) |
| | |
| | free(left) (0x3000a is now freed) |
| | free(right) (0x3000b is now freed) |
| | |
| | |
| merge(arr, left, right, left_size, right_size) | |
| i.e. merge(0x1000a, 0x2000a, 0x2000b, 1, 2) | |
left - 0x1000a - [0,1,4] <---------------------- | (0x1000a is now sorted) | |
| | |
| free(left) (0x2000a is now freed) | |
| free(right) (0x2000b is now freed) | |
| | |
| | |
merge_sort(right, right_size) -----------------> | arr - 0x1000b - [3,7,9,8] | |
| size - 4 | |
| | |
| left = malloc() - 0x2000c (say) - [3,7] | |
| left_size = 2 | |
| | |
| right = malloc() - 0x2000d (say) - [9,8] | |
| right_size = 2 | |
| | |
| merge_sort(left, left_size) -------------------> | arr - 0x2000c - [3,7] |
| | size - 2 |
| | |
| | left = malloc() - 0x3000c (say) - [3] |
| | left_size = 1 |
| | |
| | right = malloc() - 0x3000d (say) - [7] |
| | right_size = 1 |
| | |
| | merge_sort(left, left_size) -------------------> | arr - 0x3000c - [3]
| left - [3,7] was already sorted, but | | size - 1
| that doesn't matter to this program. | left - 0x3000c - [3] <-------------------------- | (0x3000c has only 1 element)
| | |
| | |
| | merge_sort(right, right_size) -----------------> | arr - 0x3000d - [7]
| | | size - 1
| | right - 0x3000d - [7] <------------------------- | (0x3000d has only 1 element)
| | |
| | |
| | merge(arr, left, right, left_size, right_size) |
| | i.e. merge(0x2000c, 0x3000c, 0x3000d, 1, 1) |
| left - 0x2000c - [3,7] <------------------------ | (0x2000c is now sorted) |
| | |
| | free(left) (0x3000c is now freed) |
| | free(right) (0x3000d is now freed) |
| | |
| | |
| merge_sort(right, right_size) -----------------> | arr - 0x2000d - [9,8] |
| | size - 2 |
| | |
| | left = malloc() - 0x3000e (say) - [9] |
| | left_size = 1 |
| | |
| | right = malloc() - 0x3000f (say) - [8] |
| | right_size = 1 |
| | |
| | merge_sort(left, left_size) -------------------> | arr - 0x3000e - [9]
| | | size - 1
| | left - 0x3000e - [9] <-------------------------- | (0x3000e has only 1 element)
| | |
| | |
| | merge_sort(right, right_size) -----------------> | arr - 0x3000f - [8]
| | | size - 1
| | right - 0x3000f - [8] <------------------------- | (0x3000f has only 1 element)
| | |
| | |
| | merge(arr, left, right, left_size, right_size) |
| | i.e. merge(0x2000d, 0x3000e, 0x3000f, 1, 1) |
| right - 0x2000d - [8,9] <----------------------- | (0x2000d is now sorted) |
| | |
| | free(left) (0x3000e is now freed) |
| | free(right) (0x3000f is now freed) |
| | |
| | |
| merge(arr, left, right, left_size, right_size) | |
| i.e. merge(0x1000b, 0x2000c, 0x2000d, 2, 2) | |
right - 0x1000b - [3,7,8,9] <------------------- | (0x1000b is now sorted) | |
| | |
| free(left) (0x2000c is now freed) | |
| free(right) (0x2000d is now freed) | |
| | |
| | |
merge(arr, left, right, left_size, right_size) | | |
i.e. merge(0x0000, 0x1000a, 0x1000b, 3, 4) | | |
(0x0000 is now sorted) | | |
| | |
free(left) (0x1000a is now freed) | | |
free(right) (0x1000b is now freed) | | |
| | |
| | |
| | |
I know this is an old question but wanted to throw my thoughts of what helped me understand merge sort.
There are two big parts to merge sort
Splitting of the array into smaller chunks (dividing)
Merging the array together (conquering)
The role of the recurison is simply the dividing portion.
I think what confuses most people is that they think there is a lot of logic in the splitting and determining what to split, but most of the actual logic of sorting happens on the merge. The recursion is simply there to divide and do the first half and then the second half is really just looping, copying things over.
I see some answers that mention pivots but I would recommend not associating the word "pivot" with merge sort because that's an easy way to confuse merge sort with quicksort (which is heavily reliant on choosing a "pivot"). They are both "divide and conquer" algorithms. For merge sort the division always happens in the middle whereas for quicksort you can be clever with the division when choosing an optimal pivot.
process to divide the problem into subproblems
Given example will help you understand recursion. int A[]={number of element to be shorted.}, int p=0; (lover index). int r= A.length - 1;(Higher index).
class DivideConqure1 {
void devide(int A[], int p, int r) {
if (p < r) {
int q = (p + r) / 2; // divide problem into sub problems.
devide(A, p, q); //divide left problem into sub problems
devide(A, q + 1, r); //divide right problem into sub problems
merger(A, p, q, r); //merger the sub problem
}
}
void merger(int A[], int p, int q, int r) {
int L[] = new int[q - p + 1];
int R[] = new int[r - q + 0];
int a1 = 0;
int b1 = 0;
for (int i = p; i <= q; i++) { //store left sub problem in Left temp
L[a1] = A[i];
a1++;
}
for (int i = q + 1; i <= r; i++) { //store left sub problem in right temp
R[b1] = A[i];
b1++;
}
int a = 0;
int b = 0;
int c = 0;
for (int i = p; i < r; i++) {
if (a < L.length && b < R.length) {
c = i + 1;
if (L[a] <= R[b]) { //compare left element<= right element
A[i] = L[a];
a++;
} else {
A[i] = R[b];
b++;
}
}
}
if (a < L.length)
for (int i = a; i < L.length; i++) {
A[c] = L[i]; //store remaining element in Left temp into main problem
c++;
}
if (b < R.length)
for (int i = b; i < R.length; i++) {
A[c] = R[i]; //store remaining element in right temp into main problem
c++;
}
}
When you call the recursive method it does not execute the real function at the same time it's stack into stack memory. And when condition not satisfied then it's going to next line.
Consider that this is your array:
int a[] = {10,12,9,13,8,7,11,5};
So your method merge sort will work like below:
mergeSort(arr a, arr empty, 0 , 7);
mergeSort(arr a, arr empty, 0, 3);
mergeSort(arr a, arr empty,2,3);
mergeSort(arr a, arr empty, 0, 1);
after this `(low + high) / 2 == 0` so it will come out of first calling and going to next:
mergeSort(arr a, arr empty, 0+1,1);
for this also `(low + high) / 2 == 0` so it will come out of 2nd calling also and call:
merger(arr a, arr empty,0,0,1);
merger(arr a, arr empty,0,3,1);
.
.
So on
So all sorting values store in empty arr.
It might help to understand the how recursive function works

Determine number of row spans given a start index and a length

I have a matrix start index of my data and the number of elements of my data
and I need to find the number of rows that the data span.
e.g. the matrix
0 5
-------------------
| | | | |x |x |
-------------------
|x |x |x |x |x |x |
-------------------
| | | | | | |
-------------------
| | | | | | |
-------------------
My data is marked with x. I know the start index 4, the length of the data 8.
And I need to determine the number of rows this data spans, 2 in this case. (just doing length/6 is off by one in many cases, surely there have to be a simple formula for this..)
If you only know offset (i.e. index of the starting column), size (i.e. how many data), cols (i.e. maximum number of colums), and you want to calculate how many rows your data will span, you can do
int get_spanned_rows(int offset, int size, int cols) {
int spanned_rows = (offset + size) / cols
if ( ( (offset + size ) % cols) != 0 )
spanned_rows++
return spanned_rows
}
where % is the modulus (or reminder) operator
int calc_rows(int start,int length){
int rows = 0;
int x= 0;
if (start != 0){
x = 6%start;
rows+=1;
}
if ((start+length) % 6 != 0){
x +=(start+length) % 6;
rows+=1;
}
rows+= (length - x)/6;
return rows;
}
calculates number of rows by dividing by 6 but after subtracting partially filled rows count
In case you only want the number of rows you can calculate
num_rows = (offset + size + cols - 1) / cols
which in this case is
num_rows = (4 + 8 + 6 - 1) / 6 = 17 / 6 = 2

Resources