Binary Search Algorithm: Need help translating provided Pseudocode - c++

Doing a major programming assignment for a Data Abstraction and ADT class. It's a sorted linked list* type of "nested classes" referred to by pointers environment. The binary search algorithm is provided for us in the way of the pseudocode below.
**ALGORITHM** *BinarySearch*(A[0...n-1], n, k)* //appropriate for get & remove
//pre: A is sorted in ascending order, n is the number of items in the array
// k is the item being searched for
//post: if the search is successful the index of the match is returned( 1-based)
//if the search is unsuccessful, -1 is returned
f <-- 0 // 0-based indices used in this method
I <-- n-1 /* personal note. I think its an I, the pdf could be an l though */
/* personal note - I think the above is an I, pdf font could be an l though.
--- secondly, the brackets in this pseudocode are bottom-half brackets.
---- i.e., they could be "floor" or "minimum"-based brackets of a kind */
m <-- f + [(i-f)/2] // floor-brackets
while f <= I do
{
if (K = a[m]) // not-floor brackets, just subscript
return (m + 1)
else if ( K < A[m] ) // not-floor brackets, just subscript
I <-- m-1
else
f <-- m+1
m <-- f + [(I-f)/2] /* floor-based brackets */
return -1
second half of the algorithm
**ALGORITHM** *BinarySearch*(A[0...n-1], n, k) // appropriate for Add function
//pre: A is sorted in ascending order, n is hte number of items in the array
// K is the term being searched for
//post: if successful, index is returned (1-based)
// if the search is unsuccessful, the index of the current location is returned
//what if n = 0? (that is, the first item is being added to the list)
f <-- 0 //0-based indices used in this method
I <-- n-1 **
m <-- f + [(I-f)/2] /* floor-based square brackets */
while (f <= I) do
// int comp = (*compare)(K, A[m])[function ptr]
if(K = A[m] ) // not-floor brackets, just subscript
// comp == 0, duplicate found, add here, adjust for 1
return (m + 1)
else if( K < A[m] ) // comp < 0
I <-- m-1
else
f <-- m+1
m <-- f + [(I-f)/2] // these are floor-brackets, but what is M in all this?
return m+1 //Not found, but current mid position is the location to add
I understand most of it, but am having trouble translating some of his notation style. I'm not entirely sure what F, I, and M are all the time, or how they are totally applying.
Maybe 'F' is a function call being applied for the recursive nature of this algorithm?
This is a general template for variables being replaced by actual code objects and names, of course.
However, I tried looking up generalized templates of binary search algorithms, but I seem to be bad at finding proper example templates of certain method types. Especially on cplusplus.com, when looking up code gives me this advanced example that is in no way even TRYING to be an attempt at introducing a genenral concept of what a specific method or function does, generally, or what it always does or does not have.
So, could you help me parse what this pseudocode is saying? Maybe direct me to a good template of what a binary search algorithm template might be, to compare to this, to help me build the function body and definition?

Related

Can someone explain how recursion works when finding all subsets?

I cannot, for the life of me, picture recursion and what it's doing. I struggle with this a lot. From the Competitive Programmer's Handbook, I uncovered the following snippet of code in C++ as a solution to the following problem:
Consider the problem of generating all subsets of a set of n elements.
For example, the subsets of {0,1,2} are ;, {0}, {1}, {2}, {0,1},
{0,2}, {1,2} and {0,1,2}.
An elegant way to go through all subsets of a set is to use recursion.
The following function search generates the subsets of the set
{0,1,...,n − 1}. The function maintains a vector subset that will
contain the elements of each subset. The search begins when the
function is called with parameter 0.
When the function search is called with parameter k, it decides
whether to include the element k in the subset or not, and in both
cases, then calls itself with parameter k + 1 However, if k = n, the
function notices that all elements have been processed and a subset
has been generated.
void search(int k) {
if (k == n) {
// process subset
} else {
search(k+1);
subset.push_back(k);
search(k+1);
subset.pop_back();
}
}
So sure, this function works and I have done it about 3 times by hand to see that it does work flawlessly. But why?
Short of memorizing all recursive solutions for all problems I will never be able to come up with this kind of solution. What kind of abstraction is being made here? What is the more general concept that is being used here?
I've always struggled with recursion so any help is appreciated. Thank you.
For each k < n we simply call search(k+1) recursively. once with the value k inside your set and once without it.
search(k+1); // call search (k+1) with k NOT inside the set
subset.push_back(k); // puts the value k inside the set
search(k+1); // call search (k+1) with k inside the set
subset.pop_back(); // removes the value k from the set
Once we reach n==k the recursion is terminated.
Imagine a binary tree of depth n, where each level represents the current value and the two branches, the decision if the value goes into your final set or not. The leaves represent all final sets.
So given n=3 and starting with k=0 you get:
search(0);
-> search(1); // with 0 in
->-> search(2); // with 0 in AND 1 in
->->-> search (3); // with 0 in AND 1 in AND 2 in. terminates with (0,1,2)
->->-> search (3); // with 0 in AND 1 in AND 2 not in. terminates with (0,1)
->-> search(2); // with 0 in AND 1 not in
->->-> search (3); // with 0 in AND 1 not in AND 2 in. terminates with (0,2)
->->-> search (3); // with 0 in AND 1 not in AND 2 not in. terminates with (0)
-> search(1); // with 0 not in
->-> search(2); // with 0 not in AND 1 in
->->-> search (3); // with 0 not in AND 1 in AND 2 in. terminates with (1,2)
->->-> search (3); // with 0 not in AND 1 in AND 2 not in. terminates with (1)
->-> search(2); // with 0 not in AND 1 not in
->->-> search (3); // with 0 not in AND 1 not in AND 2 in. terminates with (2)
->->-> search (3); // with 0 not in AND 1 not in AND 2 not in. terminates with ()
As john smartly pointed out in his comment, the recursion uses the fact that:
all_subsets(a1,a2,...,an) == all_subsets(a2,...,an) U {a1, all_subsets(a2,...,an)} where U is the set union operator.
Many other mathematical definitions will translate into recursive calls naturally.
I think what you are lacking is visualization. So I will suggest you to visit sites like algorithm-visualizer.org , pythontutor.com .
You can paste this code snippet here and run it line by line so that you can understand how the code flow works.
#include <bits/stdc++.h>
using namespace std;
void subsetsUtil(vector<int>& A, vector<vector<int> >& res, vector<int>& subset, int index) {
res.push_back(subset);
for (int i = index; i < A.size(); i++) {
subset.push_back(A[i]);
subsetsUtil(A, res, subset, i + 1);
}
return;
}
vector<vector<int> > subsets(vector<int>& A) {
vector<int> subset;
vector<vector<int> > res;
int index = 0;
subsetsUtil(A, res, subset, index);
return res;
}
int32_t main() {
vector<int> array = { 1, 2, 3 };
vector<vector<int> > res = subsets(array);
for (int i = 0; i < res.size(); i++) {
for (int j = 0; j < res[i].size(); j++)
cout << res[i][j] << " ";
cout << endl;
}
return 0;
}
It's good that you are really trying to learn. This will help you in competitive programming a lot. Hope this will help you
This is not only your problem. Everyone who starts learning recursion first time, he/she will face this. The main thing is nothing but just visualization. Literally it's tough though.
If you try to visualize any recursion code by making it handy(using pen and paper), you will just see that "Oh!, it's working". But you should know that most of recursions have a recurrence relation. Based on that, the function recurs. Similarly, for finding all the the subsets of a particular set, there is a recurrence relation.That is the following...
By taking a particular item + By not taking that item
Here in your code, "Taking a particular item" implies "Push_back" and "Not taking a particular item" implies "Pop_back". That's it.
One of the possibility is, taking no item. We call it Null set .
Another possibility is, taking all the items. Here {0,1,2}.
From permutation combination theory, we can calculate the number of subsets. That is 2n, where n is number of items. Here n=3. So the number of subsets will be 23 = 8.
For 0, take it or throw it , possibilities = 2
For 1, take it or throw it , possibilities = 2
For 2, take it or throw it , possibilities = 2
So,total number of subsets is 2*2*2 = 8 (including Null Set).
If you discard the Null Set , so the total number of subsets will be 8-1 = 7.
That's the theory behind your recursion code.

calculation of permutation sequence

I am working on below problem and post code I am debugging and the problem statement. Actually I tried to find a few reference solutions, and all are similar without too much explanation. If anyone could help to explain how below logic works, it will be great. I am confused especially by the loop of "for(i=0,k--;i
The set [1,2,3,…,n] contains a total of n! unique permutations.
By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):
"123"
"132"
"213"
"231"
"312"
"321"
Given n and k, return the kth permutation sequence.
Note: Given n will be between 1 and 9 inclusive.
Code reference,
#include <iostream>
using namespace std;
string getPermutation(int n, int k) {
int i,j,f=1;
// left part of s is partially formed permutation, right part is the leftover chars.
string s(n,'0');
for(i=1;i<=n;i++){
f*=i;
s[i-1]+=i; // make s become 1234...n
}
for(i=0,k--;i<n;i++){
f/=n-i;
j=i+k/f; // calculate index of char to put at s[i]
char c=s[j];
// remove c by shifting to cover up (adjust the right part).
for(;j>i;j--)
s[j]=s[j-1];
k%=f;
s[i]=c;
}
return s;
}
int main(int argc, const char * argv[])
{
// insert code here...
std::cout << getPermutation(4, 5) << endl;
return 0;
}
Post another implementation which is more clear to read,
def kthperm(S, k): # nonrecursive version
P = []
while S != []:
f = factorial(len(S)-1)
i = int(floor(k/f))
x = S[i]
k = k%f
P.append(x)
S = S[:i] + S[i+1:]
return P
The problem statement asks for the Kth permutation of N elements, in the lexical ordering of the permutations.
The code implements a very nice algorithm that generates the elements of the Kth permutation directly, in order, like this (pseudo-code):
GenerateKthPermutation(Set elements, int k)
{
if (elements.size()==1)
{
output(elements.getOnlyElement());
return;
}
int n = elements.size();
//there are n! permutations of elements
//no matter which one we choose as the _first_ element, there
//will be (n-1)! permutations of the remaining elements.
//The complete lexical ordering of permutations consists of:
//(n-1)! permutations that start with the smallest element, then
//(n-1)! permutations that start with the second smallest element, then
//(n-1)! permutations that start with the 3rd smallest element, etc.
//so the FIRST element in the (0-indexed) kth permutation, is the
//(0-indexed) floor(k/(n-1)!)th-largest element
int j = floor((k-1)/(n-1)!); //k-1, because the parameter is 1-indexed
//removeJthLargest(0) removes and returns the smallest element
//removeJthLargest(1) removes and returns the second-smallest
//etc.
output(elements.removeJthLargest(j));
//now output the correct permutation of remaining elements.
//we've skipped j*(n-1)! permutations, so subtract that from k
k -= j*(n-1)!;
//remember elements is 1 smaller now.
//in real life you would iterate here instead of recursing
GenerateKthPermutation(elements, k);
}
I hope that makes things clear. To specifically answer your question in comments:
The original logic uses a sorted string to store the set of elements. the part that says "remove c by shifting..." is the part where I say "elements.removeJthLargest(j)". It removes the proper element from the string and shifts the remaining ones to make a new, smaller, but still-sorted string.

longest contiguous subsequence such that twice the number of zeroes is less than equal to thrice the number of ones

I was trying to solve this problem from hacker rank I tried the brute fore solution but it doesnt seem to work. Can some one gimme an idea to solve this problem efficiently.
https://www.hackerrank.com/contests/sep13/challenges/sherlock-puzzle
Given a binary string (S) which contains ‘0’s and ‘1’s and an integer K,
find the length (L) of the longest contiguous subsequence of (S * K) such that twice the number of zeroes is <= thrice the number of ones (2 * #0s <= 3 * #1s) in that sequence.
S * K is defined as follows: S * 1 = S
S * K = S + S * (K - 1)
Input Format
The first (and only) line contains an integer K and the binary string S separated by a single space.
Constraints
1 <= |S| <= 1,000,000
1 <= K <= 1,000,000
Output Format
A single integer L - the answer to the test case
Here's a hint:
Let's first suppose K = 1 and that S looks like (using a dot for 0):
..1...11...11.....111111....111....
e f b a c d
The key is to note that if the longest acceptable sequence contains a 1 it will also contain any adjacent ones. For example, if the longest sequence contains the 1 at a, it will also contain all of the ones between b and c (inclusive).
So you only have to analyze the sequence at the points where the blocks of ones are.
The main question is: if you start at a certain block of ones, can you make it to the next block of ones? For instance, if you start at e you can make it to the block at f but not to b. If you start at b you can make it to the block at d, etc.
Then generalize the analysis for K > 1.
Brute force obviously won't work since it's O((n * k) ** 2). I will use python style list comprehensions in this answer. You'll need an array t = [3 if el == "1" else - 2 for el in S]. Now if you use the p[i] = t[0] + ... + t[i] array you can see that in the k == 1 case you are basically looking for a pair (i, j), i < j such that p[j] - (p[i - 1] if i != 0 else 0) >= 0 is true and j - i is maximal among
these pairs. Now for each i in 0..n-1 you have to find find it's j pair such that the above is maximal. This can be done in O(log n) for a specific i so this gives and O(n log n) solution for the k == 1 case. This can be extended to an O(n log n) solution for the general case(there is a trick to find the largest block that can be covered). Also there is an O(n) solution to this problem but you need to further examine the p sequence for that. I don't suggest to write a solution in a scripting language though. Even the O(n) solution times out in python...

Sort an array with recursion

To start off this is a homework assignment and I am just looking for some pointers on using recursion.
I have an array of psuedo random integers of size n. I need to sort the array from lowest highest. Below is the recursive sort function that I have created but I know that I am missing a piece but I am not sure what.
template <typename T>
void sort_array_recur(T* random_array,T n)
{
//stop case
if(n = 1 )
{
if(random_array[n] < random_array[ n + 1 ])
{
T temp = random_array[n + 1];
random_array[n] == random_array[n + 1];
random_array[n + 1] == temp;
}
}
else
{
sort_array_recur(random_array, (n - 1));
}
}
I think what I am missing is some sort of insert function that also needs to be called recursively. I have also searched around and nothing seems particular to my situation (or at least I couldn't understand it as such). Thank you for your time in advance.
EDIT:
I guess I forgot to mention the spec says "sort the first n-1 elements of an n-element array. Then place the nth element in its proper position within the n-1 sorted elements". I guess I am not understanding how to sort the first the first n-1 elements of an array?
You are asked to use recursion. Your problem sorts a size n array. The first step is sorting n-1 elements of that array.
Consider m = n-1. Can you apply your problem to a size m array? i.e. sort the first m-1 elements and then place the m'th element in its correct position?
Consider k = m-1. Can you do the same with a size k array?
Do you see how you can use recursion with this problem?
Also consider how you will end the recursion; what will you do with a size 1 array?

Finding the maximum weight subsequence of an array of positive integers?

I'm tring to find the maximum weight subsequence of an array of positive integers - the catch is that no adjacent members are allowed in the final subsequence.
The exact same question was asked here, and a recursive solution was given by MarkusQ thus:
function Max_route(A)
if A's length = 1
A[0]
else
maximum of
A[0]+Max_route(A[2...])
Max_route[1...]
He provides an explanation, but can anyone help me understand how he has expanded the function? Specifically what does he mean by
f[] :- [],0
f [x] :- [x],x
f [a,b] :- if a > b then [a],a else [b],b
f [a,b,t] :-
ft = f t
fbt = f [b|t]
if a + ft.sum > fbt.sum
[a|ft.path],a+ft.sum
else
fbt
Why does he expand f[] to [],0? Also how does his solution take into consideration non-adjacent members?
I have some C++ code that is based on this algorithm, which I can post if anyone wants to see it, but I just can't for the life of me fathom why it works.
==========For anyone who's interested - the C++ code ==============
I should add, that the array of integers is to be treated as a circular list, so any sequence containing the first element cannot contain the last.
int memo[55][55];
int solve(int s, int e)
{
if( s>e ) return 0;
int &ret=memo[s][e];
if(ret!=-1)
{
return ret;
}
ret=max(solve(s+1,e), solve(s+2,e)+a[s]);
return ret;
}
class Sequence
{
public:
int maxSequence(vector <int> s)
{
memset(memo,-1);
int n = s.size();
for(int i=0; i<n; i++)
a[i]=s[i];
return max(solve(0,n-2),solve(1,n-1));
}
};
I don't really understand that pseudocode, so post the C++ code if this isn't helpful and I'll try to improve it.
I'm tring to find the maximum weight subsequence of an array of positive integers - the catch is that no adjacent members are allowed in the final subsequence.
Let a be your array of positive ints. Let f[i] = value of the maximum weight subsequence of the sequence a[0..i].
We have:
f[0] = a[0] because if there's only one element, we have to take it.
f[1] = max(a[0], a[1]) because you have the no adjacent elements restriction, so if you have two elements, you can only take one of them. It makes sense to take the largest one.
Now, generally you have:
f[i > 1] = max(
f[i - 2] + a[i] <= add a[i] to the largest subsequence of the sequence a[0..i - 2]. We cannot take a[0..i - 1] because otherwise we risk adding an adjacent element.
f[i - 1] <= don't add the current element to the maximum of a[0..i - 2], instead take the maximum of a[0..i - 1], to which we cannot add a[i].
)
I think this way is easier to understand than what you have there. The approaches are equivalent, I just find this clearer for this particular problem, since recursion makes things harder in this case and the pseudocode could be clearer either way.
But what do you NOT understand? It seems quite clear for me:
we will build the maximal subsequence for every prefix of our given sequence
to calculate the maximal subsequence for prefix of length i, we consider two possibilities: Either the last element is, or isn't in the maximal subsequence (clearly there are no other possibilities).
if it is there, we consider the value of the last element, plus the value of maximal subsequence of the prefix two elements shorter (because in this case, we know the last element cannot be present in the maximal subsequence because of the adjacent elements rule)
if it isn't we take the value of maximal sum of prefix one element shorter (if the last element of the prefix is not in the maximal subsequence, the maximal subsequence has to be equal for this and the previous prefix)
we compare and take the maximum of the two
Plus: you need to remember actual subsequences; you need to avoid superfluous function invocations, hence the memoization.
Why does he expand f[] to [],0?
Because the first from the pair in return value means current maximal subsequence, and the second is its value. Maximal subsequence of an empty sequence is empty and has value zero.