Quicksort partitioning - sorting

I am sorry to be dumb, but I have been struggling with my own quicksort implementation for quiet a while. To be more specific, I can't get my partition procedure to work properly. Ridiculously enough, but I've also tried to almost directly copy an implementation from Sedjewick's book, with no success, however.
Here is my code:
void partition(int a[], int size)
{
int i, j = size - 1;
int t, pivot = a[j / 2];
i = 0;
for (;;)
{
while (a[i] < pivot)
i++;
while (a[j] > pivot)
j--;
if (i >= j)
break;
t = a[i];
a[i++] = a[j];
a[j] = t;
}
}
Here is the example of input:
82, 65, 59, 10, 35, 51, 81, 47, 25, 64, 34, 38, 12, 38, 58, 74, 37, 42, 63, 18,
75, 67, 36, 77, 47, 48, 13, 91, 94, 52
The pivot here is 58, but I get wrong output:
52, 13, 48, 10, 35, 51, 47, 47, 25, 36, 34, 38, 12, 38, 18, 58, 37, 42, 63, 74,
75, 67, 64, 77, 81, 59, 65, 91, 94, 82
It looks almost correct, with a little exception of 37 and 42 going right after 58. I've tried a lot of variations of partitioning procedure, but they all get me similar results.

EDIT
My previous answer seemed to fix the issue but wasn't correct.
Your output is fine. Let me visually indicate the partition with vertical bars:
52, 13, 48, 10, 35, 51, 47, 47, 25, 36, 34, 38, 12, 38, 18, 58, 37, 42 || 63, 74, 75, 67, 64, 77, 81, 59, 65, 91, 94, 82
Everything to the left of the vertical bars is <= 58, and everything to the right is >= 58. This is what's expected from the partition step in a quicksort.
You do, however, need to decrement j in addition to incrementing i:
t = a[i];
a[i++] = a[j];
a[j--] = t; // added a decrement here
Other than that, the only thing you're missing is returning the partition index. Simply return the value of i at the end of the function and use that as the array boundary in your recursive step.

Replace a[j] = t; with a[j--] = t

Related

How to emulate normal distribution data by actual, real life events, instead of using a math formula?

I am trying to generate some Bell Shape data (Normal Distribution). There are some math formula to achieve that, but I am hoping to emulate it by natural, daily events that happen in real life.
For example, I am saying, for 50 students, assuming they have a 70% chance of getting a question in a multiple choice exam correct, for 100 questions. So what score does each student get? I have the code in JavaScript:
students = Array.from({ length: 50 });
students.forEach((s, i, arr) => {
let score = 0;
for (let i = 0; i < 100; i++) {
if (Math.random() >= 0.3) score++;
}
arr[i] = score;
});
console.log(students);
But the result doesn't seem like a normal distribution. For example, I got:
[
69, 70, 67, 64, 71, 72, 77, 70, 71, 64, 74,
74, 73, 80, 69, 68, 67, 72, 69, 70, 61, 72,
72, 75, 63, 68, 71, 69, 76, 70, 69, 69, 67,
63, 65, 80, 70, 62, 68, 63, 73, 69, 64, 79,
79, 72, 72, 70, 70, 66
]
There is no student who got a score of 12 or 20, and there is no student who got a score of 88 or 90 or 95 (the students who can get an A grade). Is there a way to emulate a real life event to generate normal distribution data?
Two issues:
100 students may be a bit too small a sample to produce such a pattern; 10000 students will give a better view.
You can better visualise the statistics by counting the number of students that have a given score. So you would get a count per potential score (0..100).
And now you can see the Bell curve:
let students = Array.from({ length: 10000 });
let studentsWithScore = Array(101).fill(0);
students.forEach(() => {
let score = 0;
for (let i = 0; i < 100; i++) {
if (Math.random() >= 0.3) score++;
}
studentsWithScore[score]++;
});
console.log(studentsWithScore);

doubly array from a stream of integers

how to convert Flux<List> into Flux<int[][]>.
I have a Flux<List> -> {1,2,3,.....100} I want to group them by 30 numbers -> [[1,2,3,.....30], [31,32....60],[61.....100]]
I have tried the below approach but was not successful. elements are getting grouped in batches of 5 [ [1,2,3,4,5], [6,7,8,9,10],.....]
Flux<int[][]> groupedData = fluxData.map(x -> {
int outerArraySize = (int) Math.ceil(x.size() / 30) +1;
System.out.println(outerArraySize);
int[][] boxedData = new int[30][outerArraySize];
AtomicInteger innerArray = new AtomicInteger(0);
AtomicInteger outerArray = new AtomicInteger(0);
x.forEach(ids -> {
boxedData[innerArray.get()][outerArray.get()] = ids;
innerArray.getAndIncrement();
if (innerArray.get() == 30) {
innerArray.set(0);
outerArray.getAndIncrement();
}
});
Flux has a useful operator called 'buffer', we can use it to batch the List of Integers.
I have created my 'fluxData' like this, just so I can test my code:
List<Integer> list1 = IntStream.rangeClosed(1, 100).boxed().collect(Collectors.toList());
List<Integer> list2 = IntStream.rangeClosed(1, 40).boxed().collect(Collectors.toList());
List<Integer> list3 = IntStream.rangeClosed(1, 70).boxed().collect(Collectors.toList());
Flux<List<Integer>> fluxData = Flux.just(list1, list2, list3);
Now, we can do the following:
fluxData.map(integersList -> {
List<List<Integer>> batchesList = Flux.fromStream(integersList.stream())
.buffer(30) // This the magic.
.collectList()
.block();
// List<List<Integer>> --> int[][]
int[][] batchesArray = new int[batchesList.size()][];
for(int i = 0;i < batchesArray.length;i++){
batchesArray[i] = new int[batchesList.get(i).size()];
for (int j = 0; j < batchesArray[i].length; j++) {
batchesArray[i][j] = batchesList.get(i).get(j);
}
}
return batchesArray;
})
.subscribe(batchesArray -> System.out.println(Arrays.deepToString(batchesArray)));
Output:
[[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], [61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90], [91, 92, 93, 94, 95, 96, 97, 98, 99, 100]]
[[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]]
[[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], [61, 62, 63, 64, 65, 66, 67, 68, 69, 70]]

Why won't ruby-mcrypt accept an array as a key?

Hello I am having trouble encrypting using an array as the key and the value with the ruby-mcrypt gem. The gem lets me use an array for the key fine, cipher = Mcrypt.new("rijndael-256", :ecb, secret) works. But it will give me an error when I try to encrypt. I've tried many things but no luck. Does anyone know if Mcrypt just doesn't like encrypting with an array?
require 'mcrypt'
def encrypt(plain, secret)
cipher = Mcrypt.new("rijndael-256", :ecb, secret)
cipher.padding = :zeros
encrypted = cipher.encrypt(plain)
p encrypted
encrypted.unpack("H*").first.to_s.upcase
end
array_to_encrypt = [16, 0, 0, 0, 50, 48, 49, 55, 47, 48, 50, 47, 48, 55, 32, 50, 50, 58, 52, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
key_array = [65, 66, 67, 68, 49, 50, 51, 52, 70, 71, 72, 73, 53, 54, 55, 56]
result = encrypt(array_to_encrypt, key_array)
p "RESULT IS #{result}"
The output is as follows:
Mcrypt::RuntimeError: Could not initialize mcrypt: Key length is not legal.
I traced this error to here in the ruby-mcrypt gem but don't understand it enough to figure out why I am getting the error message. Any help or insights would be amazing. Thanks!
The library doesn't support arrays. You'll need to use Strings instead:
def binary(byte_array)
byte_array.pack('C*')
end
array_to_encrypt = [16, 0, 0, 0, 50, 48, 49, 55, 47, 48, 50, 47, 48, 55, 32, 50, 50, 58, 52, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
key_array = [65, 66, 67, 68, 49, 50, 51, 52, 70, 71, 72, 73, 53, 54, 55, 56]
result = encrypt(binary(array_to_encrypt), binary(key_array))
p "RESULT IS #{result}"

Print ASCII table without loop

I just had an interview and I have been asked a question: How would you print all the ASCII table characters without using a loop. The language doesn't matter.
The only method for doing so that comes to my mind is by using recursion instead of loops. An algorithm for doing this will be something like:
void printASCII(int i){
if(i == 128)
return;
print(i + " " + ((char)i) + "\n");
printASCII(i + 1);
}
You should call the previous function using:
printASCII(0);
This will print the complete ASCII table, where each line contains the index followed by a space and the actual ASCII character.
I don't think you can find any other way to do so, specially that it clearly says:
The language doesn't matter
This usually means that the question is about an algorithmic idea, rather than being specific for any language.
Two other approaches that weren't mentioned:
The obvious:
#include <stdio.h>
int main() {
printf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", 0, 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, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127);
}
The power of two tree (probably intended by the interviewer):
#include <stdio.h>
int c;
#define a128 a64; a64;
#define a64 a32; a32;
#define a32 a16; a16;
#define a16 a8; a8;
#define a8 a4; a4;
#define a4 a2; a2;
#define a2 a; a;
#define a printf("%c", c++);
int main() {
c = 0;
a128
}

d3.layout.histogram() and attributes don't work in v4

I would like to "convert" a D3.js v3 based code to D3.js v4.
I don't know what I have to change in the following code that it doesnt display any error:
var data = d3.layout.histogram()
.bins(resolution)
.frequency(0)
(results);
I know that in d3.js v4 there isn't something like d3.layout.histogram() - I only found d3.histogram() in the API. But how do I change the "syntax" of line 2-4 in order to make it working with v4? Thanks in Advance.
According to this article we have the following list of differences between histogram layout in d3v3 and d3v4:
d3.layout.histogram becomes d3.histogram
.bins becomes .thresholds
d3.scale.linear becomes d3.scaleLinear
d.x+d.dx becomes d.x1
d.y becomes d.length
d.dx becomes d.x1-d.x0
More detailed explanations from d3v4 changelog:
The new d3.histogram API replaces d3.layout.histogram. Rather than
exposing bin.x and bin.dx on each returned bin, the histogram exposes
bin.x0 and bin.x1, guaranteeing that bin.x0 is exactly equal to bin.x1
on the preceeding bin. The “frequency” and “probability” modes are no
longer supported; each bin is simply an array of elements from the
input data, so bin.length is equal to D3 3.x’s bin.y in frequency
mode. To compute a probability distribution, divide the number of
elements in each bin by the total number of elements.
The histogram.range method has been renamed histogram.domain for
consistency with scales. The histogram.bins method has been renamed
histogram.thresholds, and no longer accepts an upper value: n
thresholds will produce n + 1 bins. If you specify a desired number of
bins rather than thresholds, d3.histogram now uses d3.ticks to compute
nice bin thresholds. In addition to the default Sturges’ formula, D3
now implements the Freedman-Diaconis rule and Scott’s normal reference rule.
So you should rewrite mentioned code snippet this way:
var data = d3.histogram()
.thresholds(resolution)
(results);
But you also need to rewrite other parts of your code and replace: d.x+d.dx to d.x1, d.y to d.length and d.dx to d.x1-d.x0.
Example how to create histogram layout with d3v4 see in the hidden snippet below:
var data = [
79, 54, 74, 62, 85, 55, 88, 85, 51, 85, 54, 84, 78, 47, 83, 52, 62, 84, 52, 79, 51, 47, 78, 69, 74, 83, 55, 76, 78, 79, 73, 77, 66, 80, 74, 52, 48, 80, 59, 90, 80, 58, 84, 58, 73, 83, 64, 53,
82, 59, 75, 90, 54, 80, 54, 83, 71, 64, 77, 81, 59, 84, 48, 82, 60, 92, 78, 78, 65, 73, 82, 56, 79, 71, 62, 76, 60, 78, 76, 83, 75, 82, 70, 65, 73, 88, 76, 80, 48, 86, 60, 90, 50, 78, 63, 72,
84, 75, 51, 82, 62, 88, 49, 83, 81, 47, 84, 52, 86, 81, 75, 59, 89, 79, 59, 81, 50, 85, 59, 87, 53, 69, 77, 56, 88, 81, 45, 82, 55, 90, 45, 83, 56, 89, 46, 82, 51, 86, 53, 79, 81, 60, 82, 77,
76, 59, 80, 49, 96, 53, 77, 77, 65, 81, 71, 70, 81, 93, 53, 89, 45, 86, 58, 78, 66, 76, 63, 88, 52, 93, 49, 57, 77, 68, 81, 81, 73, 50, 85, 74, 55, 77, 83, 83, 51, 78, 84, 46, 83, 55, 81, 57,
76, 84, 77, 81, 87, 77, 51, 78, 60, 82, 91, 53, 78, 46, 77, 84, 49, 83, 71, 80, 49, 75, 64, 76, 53, 94, 55, 76, 50, 82, 54, 75, 78, 79, 78, 78, 70, 79, 70, 54, 86, 50, 90, 54, 54, 77, 79, 64,
75, 47, 86, 63, 85, 82, 57, 82, 67, 74, 54, 83, 73, 73, 88, 80, 71, 83, 56, 79, 78, 84, 58, 83, 43, 60, 75, 81, 46, 90, 46, 74
];
var width = 952;
var height = 476;
var x = d3.scaleLinear().domain([30, 110]).range([0, width]);
var bins = d3.histogram().domain(x.domain()).thresholds(x.ticks(30))(data);
var max = d3.max(bins, function(d) {
return d.y;
});
var y = d3.scaleLinear().domain([0, .1]).range([0, height]);
var yForHistogram = d3.scaleLinear()
.domain([0, d3.max(bins, function(d) {
return d.length;
})])
.range([height, 0]);
var vis = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var bars = vis.selectAll("g.bar")
.data(bins)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) {
return "translate(" + x(d.x0) + "," + yForHistogram(d.length) + ")";
});
bars.append("rect")
.attr("fill", "steelblue")
.attr("width", x(bins[0].x1) - x(bins[0].x0) - 1)
.attr("height", function(d) {
return height - yForHistogram(d.length);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.12.0/d3.min.js"></script>

Resources