Simple recursive function to determine if two elements are transitively true - c++

newbie here. Even newer to recursion. I'm writing a function for my C++ program, and as you'll be able to tell, I'm a bit clueless when it comes to recursive algorithms. I'd appreciate it greatly if someone could fix my function so I can get it working and perhaps have a better idea how to handle recursion afterward.
My function takes a two-dimensional square array of booleans, and integer i, and an integer array_size as parameters. The function returns a boolean value.
The array is an adjacency matrix that I use to represent a set of conditionals. For example, if the value at [0][3] is true, then 0 -> 3 (if 0, then 3). If [3][7] is true, then 3 -> 7 (if 3, then 7). By the transitive property, 0 -> 7 (if 0, then 7).
The integer i is a particular element in the set of conditionals. The function will return true if this element is transitively connected to the last element in the array. The last element in the array is the integer (array_size - 1),
The integer array_size is the size of each dimension of the square array. If array_size is 20, then the array is 20x20.
The idea of this function is to determine if there is any logical "path" from the first integer element to the last integer element by the transitive property. When the path exists, the function returns true, otherwise, it returns false. The recursive call should allow it to traverse all possible paths, returning true once it finally reaches the last element and false if all paths fail.
For example, if i = 0 and array_size = 10, then the function will return whether or not 0 -> 9 is valid according to the conditionals provided by the matrix and the transitive property.
This is my code so far:
bool checkTransitivity(bool **relations, int i, int array_size){
bool isTransitive = false;
if (i == array_size - 1)
{
isTransitive = true;
}
else
{
for (int j = i; j < array_size; j++){
if (relations[i][j])
{
isTransitive = checkTransitivity(relations, j, array_size);
}
}
}
return isTransitive;
Currently, the function returns true for all input.
Any help at all is appreciated. Thanks in advance!

EDIT: This first part is unnecessary because of your if-else statement. Move on to END OF EDIT.
Let's start with what a base case in a recursive function is:
if (i == array_size - 1)
{
isTransitive = true;
}
Well you do have a base case, but nothing is being returned. You are just setting a flag to true. What you want to do is:
if (i == array_size - 1) {
return true;
}
Now the function will work its way up the recursive stack to return true. END OF EDIT.
But we still need to fix the recursive case:
else {
for (int j = i; j < array_size; j++) {
if (relations[i][j]) {
isTransitive = isTransitive || checkTransitivity(relations, j, array_size);
}
}
}
return isTransitive;
The || means binary OR. So you have the logic right. You want to check each possible path to see if it can get there, but by setting isTransitive to the result of each check, isTransitive is only going to be set to the last call. By doing isTransitive = isTransitive || recursive call, isTransitive will be true as long as one of the calls results in a true value.
The last thing I want to say is a caution: if relations[i][j] == true and relations[j][i] == true, your code will still be in an infinite loop. You must find a way to eliminate the potential backtracking. One way to do this is to create another array that stores which paths you have already checked so you do not infinitely loop.
More information can be found here: Depth First Search

I think all you need is a break condition to stop continuing the loop when you encounter a non-transitive item. See below (haven't tested)
bool checkTransitivity(bool **relations, int i, int array_size){
bool isTransitive = false;
if (i == array_size - 1)
{
isTransitive = true;
}
else
{
for (int j = i; j < array_size; j++){
isTransitive = relations[i][j] && checkTransitivity(relations, j, array_size);
if (!isTransitive)
break;
}
}
return isTransitive;
}

Related

leetcode question 81 c++ returns wrong answer

question:
There is an integer array nums sorted in non-decreasing order (not necessarily with distinct values).
Before being passed to your function, nums is rotated at an unknown pivot index k (0 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,4,4,5,6,6,7] might be rotated at pivot index 5 and become [4,5,6,6,7,0,1,2,4,4].
Given the array nums after the rotation and an integer target, return true if target is in nums, or false if it is not in nums.
You must decrease the overall operation steps as much as possible.
class Solution {
public:
int search(vector<int>& nums, int target) {
int s=0;
vector<int> f(4999);
vector<int> x(4999);
int y=f.size()-1;
int z=x.size()-1;
for (int i=0;i<nums.size();i++){
for (int j=1;j<nums.size();j++){
if (i<=j){
f.push_back(nums[i]);
}else if (i>j){
f.push_back(nums[i]);
x.push_back(nums[j]);
for (int k=j;k<nums.size();k++)
x.push_back(nums[k]);
break;
}
}
}
if (target==x[0]||target==f[0]){
return true;
}
else if (target>f[0]){
while (s<=y){
int mid=0;
mid=(y+s)/2;
if (f[mid]>target){
y=mid-1;
}else if (f[mid]<target){
s=mid+1;
}else if (f[mid]==target){
return true;
}
}
return false;
}else if (target<f[0]){
while (s<=z){
int mid=0;
mid=(z+s)/2;
if (x[mid]>target){
z=mid-1;
}else if (x[mid]<target){
s=mid+1;
}else if (x[mid]==target){
return true;
}
}
return false;
}
else{
return false;
}return false;
}
};
input [2,5,6,0,0,1,2] target 2 returned false expected true
input [1] target 1 returned false expected true
input [1] target 0 returned true expected false
trying to stick to a binary search solution how can this work
help is appriciated thanks
To figure out why it's not working, you can walk through one of the failing test cases. You'd want to pick the easiest one to manage in your head, so in this case I recommend one of those with an array length of 1.
So let's walk through
input [1] target 1 returned false expected true
Your function first creates two large arrays, each with 4999 zeros in them. See this answer for why they're zero.
Then that nested for loop runs, but it doesn't actually do anything because the inner loop will not run -- j=1 is not less than nums.size(), which is 1.
So by the time you do your binary searches below, both f and x are filled with 4999 zeros. Your code does the binary search on f, so it won't find your target of 1.
If you want to see the solution to this problem, check out this Stack Overflow answer.

while greater than negative number not working

I have a very trivial piece of code that basically needs to count down from a certain number, and use that count as an index to an array.
auto bigSize = BigArray.size() - 1;
while(bigSize > -1) {
auto thing = arr[bigSize ];
bigSize--;
}
However the code never seems to hit anything inside the loop. I've also tried with a for loop:
auto bigSize = BigArray.size() - 1;
for(int i = bigSize ; i >= 0 && i < bigSize ; --i) {
auto thing = arr[i];
}
I feel like I'm doing something incorrect, but I can't seem to find it.
while(bigSize > -1) {
auto thing = arr[bigSize ];
bigSize--;
}
This will never stop. bigSize is unsigned which means it can't contain negative values. The moment bigSize is 0 and you try to decrement it it becomes std::numeric_limits<type>::max(). (underflow, not negative) So it'll keep on looping.
Either change your condition or make bigSize explicitly an int.
std::Container.size() always returns an unsigned number. An unsigned number will always be greater than a negative number, even if you underflow.

Initializing An Array with a Variable Size

I am almost done with my code except I need help on two thing. Here is my code: Code. For the function below, I am trying to make it so that I can use the input of "n" to initialize my array, myBits, instead of a constant, which is currently 5.
My Other question is right below that. I am trying to switch all of the right most bits to "true". I wrote the for loop in "/* .....*/" but it doesn't seem to be working. Right above it, I do it long ways for C(5,4) ....(myBit[0] = myBit[1]....etc...... (I am using this to find r-combinations of strings).... and it seems to work. Any help would be appreciated!!
void nCombination(const vector<string> &Vect, int n, int r){
bool myBits[5] = { false }; // everything is false now
myBits[1] = myBits[2] = myBits[3] = myBits[4] = true;
/* for(int b = n - r - 1; b = n - 1; b++){
myBits[b] = true; // I am trying to set the r rightmost bits to true
}
*/
do // start combination generator
{
printVector(Vect, myBits, n);
} while (next_permutation(myBits, myBits + n)); // change the bit pattern
}
These are called variable length arrays (or VLAs for short) and they are not a feature of standard C++. This is because we already have arrays that can change their length how ever they want: std::vector. Use that instead of an array and it will work.
Use std::vector<bool>:
std::vector<bool> myBits(n, false);
Then you have to change your while statement:
while (next_permutation(myBits.begin(), myBits.end()));
You will also have to change your printVector function to take a vector<bool>& as the second argument (you won't need the last argument, n, since a vector knows its own size by utilizing the vector::size() function).
As to your program: If you're attempting to get the combination of n things taken r at a time, you will need to write a loop that initializes the last right r bools to true instead of hard-coding the rightmost 4 entries.
int count = 1;
for (size_t i = n-1; i >= 0 && count <= r; --i, ++count)
myBits[i] = true;
Also, you should return immediately from the function if r is 0.

bubble sort algorithm for loop statement warning

I saw a piece of bubble sort code and initially I thought the code is wrong. But after compile and run, it surprised me that it actually works. I want to know how come second statement in the first for loop is not a condition but an assignment. In addition, how come this code will not go into infinitely loop?
PS: It will generate an warning: "suggest parentheses around assignment used as truth value [-Wparentheses]" complaining about the first for loop. Surprisingly it's not an error.
#include <iostream>
void bubblesort(int A[], int n)
{
for (bool sorted = false; sorted = !sorted; n--)
{
for (int i = 1; i < n; ++i)
{
if (A[i-1] > A[i])
{
int tmp = 0;
tmp = A[i];
A[i] = A[i-1];
A[i-1] = tmp;
sorted = false;
}
}
}
}
int main()
{
int a[5] = {1,4,5,2,3};
bubblesort(a, 5);
for (unsigned int i = 0; i < 5; ++i)
{
std::cout << a[i] << std::endl;
}
return 0;
}
The result of an assignment is the left operand, so the condition
sorted = !sorted
is using sorted as the condition after it's assigned a new value. The warning is there to give you a notice that using assignment as condition is sometimes not what you expected. You can use
(sorted = !sorted) == true
to silence the warning.
It's one of the quirks of C and C++ that they allow an assignment in the middle of a statement. Usually it's an error (= instead of ==) so a good compiler will warn you about it.
The value of such an expression is the same as the assigned value.
In this case it's a very tricky optimization; if the value was false it's reset to true and the loop continues, if it was true then it becomes false and the loop termination condition is met. I would never use this in code that anybody was expected to maintain.
An explanation for the code. Basically, if sorted ever is true before the condition the loop will stop.
1st loop: sorted is true
Within the second for loop, it basically checks if the array is sorted. If it isn't sorted -> false and the loop continues. If it is, sorted-> true and execution stops.
The comparision normally is as follows:
sorted != sorted
Of course, this does not make any sense. But instead, you have the following:
sorted = !sorted
By doing this, you just negate the condition for sorting, meaning that the array, which is unsorted, is assumed to be sorted. Then, if you traverse the complete array without making any swap, the left side of the assignment is taken as a condition (which in this case is true).

Recursive Function Error

Im trying to create a recursive function that contains a vector of numbers and has a key, which is the number we are looking for in the vector.
Each time the key is found the function should display a count for how many times the key appears in the vector.
For some reason my recursive function is only returning the number 1 (disregard the 10 I was just testing something)
Here's my code:
int recursive_count(const vector<int>& vec, int key, size_t start){
if (start == vec.size())
return true;
return (vec[start] == key? 23 : key)
&& recursive_count(vec, key, (start+1));
}
int main() {
vector <int> coco;
for (int i = 0; i<10; i++) {
coco.push_back(i);
}
cout << coco.size() << endl;
int j = 6;
cout << recursive_count(coco, j, 0) << endl;
}
Not sure what you are trying to do, but as is - your function will return false (0) if and only if the input key is 0 and it is in the vector. Otherwise it will return 1.
This is because you are basically doing boolean AND operation. The operands are true for all values that are not 0, and the only way to get a 0 - is if it is in the vector - and the key is 0.
So, unless you get a false (0) along the way, the answer to the boolean formula is true, which provides the 1.
EDIT:
If you are trying to do count how many times the key is in vec - do the same thing you did in iterative approach:
Start from 0 (make stop condition return 0; instead of return true;)
Increase by 1 whenever the key is found instead of using operator&&, use the operator+.
(I did not give a direct full answer because it seems like HW, try to follow these hints, and ask if you have more questions).
To me it seems that a recursive function for that is nonsense, but anyway...
Think about the recursion concepts.
What is the break condition? That the current character being checked is not in the string anymore. You got that right.
But the recursion case is wrong. You return some kind of bool (what's with the 23 by the way?
The one recursion round needs to return 1 if the current element equals key, and 0 otherwise.
Then we only need to add up the recursion results, and we're there!
Here's the code
int recursive_count(const vector<int>& vec, int key, size_t start) {
if (start >= vec.size()) {
return 0;
} else {
return
((vec[start] == key) ? 1 : 0) +
recursive_count(vec, key, start+1);
}
}
Since this is even tail-recursion, good compilers will remove the recursion for you by the way, and turn it into its iterative counterpart...
Your recursive_count function always evaluates to a bool
You are either explicitly returning true
if (start == vec.size())
return true;
or returning a boolean compare
return (vec[start] == key? 23 : key) // this term gets evaluated
&& // the term above and below get 'anded', which returns true or false.
recursive_count(vec, key, (start+1)) // this term gets evaluated
It then gets cast to your return type ( int ), meaning you will only ever get 0 or 1 returned.
As per integral promotion rules on cppreference.com
The type bool can be converted to int with the value false becoming
​0​ and true becoming 1.
With,
if (start == vec.size())
return true;
your function with return type int returns 1