Longest increasing subsequence - c

The task is to find the length of the longest subsequence in a given array of integers such that all elements of the subsequence are sorted in ascending order. For example, the length of the LIS for { 15, 27, 14, 38, 26, 55, 46, 65, 85 } is 6 and the longest increasing subsequence is {15, 27, 38, 55, 65, 85}.
Following is the code I wrote. I am not sure if my logic is fine but the code fails to run properly. If I try to input the following test case
9
15
27
14
The program stops reading the values after 14 and gives me the output 2. It should read 9 values but the code is reading only 3 values. I have checked my code several times but unfortunately, I am unable to spot the error.
#include<stdio.h>
int main()
{
int N,max_val,i,j,k,l=1;
int a[100000], track[100000];
track[0]=0;
max_val=1;
scanf("%d",&N);
for(i=0;i<N;++i)
{
printf("x");
scanf(" %d",&a[i]);
if(i!=0)
{
for(j=0;j<l;++j)
{
if(a[i]>a[track[j]])
{
max_val++;
track[0]=i;
l=1;
break;
}
else
{
track[l]=i;
l++;
}
}
}
}
printf("%d",max_val);
return 0;
}
Help is appreciated. Thanks!

Oh, nicely convoluted. You have undefined behavior here, and the way it expresses itself is instructive. The general problem is that
if(a[i]>a[track[j]]) // <-- when i == 2, this first is false with
{ // your input
max_val++;
track[0]=i;
l=1;
break;
}
else
{
track[l]=i; // <-- and you end up here, where you write
l++; // into track[l] and increase l.
}
After l is increased, you go back to the loop
for(j=0;j<l;++j)
Here j is increased, but since l has also increased, the condition is never (except not really, see below) false, and the loop continues. From this point on, the condition
a[i]>a[track[j]]
is always false, because you keep comparing the same two numbers, so l is incremented every turn, and this just keeps happening.
This goes on until track is full with twos (because i remains 2). In fact, it goes on after track is full, writing into whatever happens to lie behind track in memory. What this is is not defined in the C language standard; for me this happens to be first a, then N, max_val and so forth in order of declaration (found that out with a debugger, a tool I encourage you to look into). YMMV. So, for me, a is also filled, and then N is overwritten with 2, max_val etc. are also overwritten with 2, then l is overwritten with 2, and only then does the loop end. And then you go back to
for(i=0;i<N;++i)
...where now N is 2 and i is just being incremented to 3. Then the loop ends, and then the program ends.
Perhaps needless to say, this is not behavior you can depend upon. The compiler doesn't have to arrange the stack variables in this order, and an optimising compiler can even generate code that doesn't hold certain variables in memory (or at all). But that is what happens.

Related

Debug-print for loop omitting 1st value

I was debugging a low level program, I had to ensure that my array exp have all values I expect it to have. So I wrote a code snippet that prints my array to help debug it. Problem is standard library isn't available so I need to use my own code.
My code snippet:
int test=0;char val[5]={};
int l=0;
for(int k=0;exp[k]!=0;k++)
{
test=exp[k]; //taking in value
int_to_ascii(test, val);
print_char(val,2*l,0xd);
for(int m=0;val[m]!='\0';m++)//clearing out val for next iteration
val[m]='\0';
l=k*0xA0; //next line
}
exp is an integer array..
code for int_to_ascii:
if(src==0)
{
stack[i++]='\0'; //pushing NULL and 0 to stack
stack[i++]='0';
}
else
{
while(src!=0) //converting last digit and pushing to stack
{
stack[i]=(0x30+src%10);
src/=10;
i++;
}
}
i--;
len=i;
while(i>=0)
{
dest[len-i]=stack[i]; //popping and placing from left to right
i--; //inorder not to get reversed.
}
print_char works because I use it to print entire window and interface. It basically takes
char* szarray,int offset,int color.
I was yelling at my computer for nearly 2 hours because I thought my array is incorrect but it shouldn't be, but the actual problem was in this debug code.It doesn't print exp[0].
When it should output:
20480
20530
5
It just prints
20530
5
I even tried brute forcing values into exp[0]. If I give any value except 20480 into that, it will print invalid characters into first entry,like this:
20530P\. ;not exact value, demonstration purpose only
5
I think something is off in int_to_ascii, but that also is extensively used in other parts without any problems.
Any one have any idea with it?

Having trouble understanding the for loop

#include <stdio.h>
int n, a[100001], x, y;
int main() {
scanf("%d", &n);
while (n--) {
scanf("%d.%d", &x, &y);
a[x*1000+y]++;
}
for (int i = 0, c = 0; i <= 100000; i++) {
while (a[i]) {
--a[i], ++c;
printf("%d.%03d\n", i / 1000, i % 1000);
if (c == 7) return 0;
}
}
return 0;
}
This is the code that receives an integer n, then the program is expected to receive n number of double or integer variables.
The program is supposed to print out the smallest 7 variables among the input variables to 3 decimal points.
Now the question is i can't seem to figure out how this code in for loop
while (a[i]) {
--a[i], ++c; // <- specifically this part
printf("%d.%03d\n", i / 1000, i % 1000);
if (c == 7) return 0;
}
generates 7 smallest variables.
Any help would be much appreciated
Suppose 8.3 is an input, then you are storing the 8003rd index of the array to 1. i.e a[8003]=1. if 8.3 is input twice then a[8003] will be equal to 2.
So in the for loop when i=8003, a[8003] is non zero that that means there was an input 8.3. So it is considered in the top 7 smallest input values and the loop exits when count reaches 7.
As hellow mentioned, This is bad code and if you are a student, stay away from such programming style (Not just student, everyone should stay away).
What this code does is it creates sort of "Look-up" table.
Whenever a number is entered, it increases a count at that array instance.
e.g. If I input 3.2, it increments a[3002] th location. Code for this is:
scanf("%d.%d", &x, &y);
a[x*1000+y]++;
x = 3 and y = 2 so a[3*1000+2]++ --> a[3002] = 1
(Note: Code assumes that array a is initialized with 0 - another bad habit)
Now say I entered 1.9, code will increment a[1009]. If I enter 3.2 again, a[3002] will be incremented again.
This was input part.
Now code parses entire array a starting from 0. At first it will encounter 1009, code will print 1.9 and keep on parsing array.
When it finds 7 non=zero locations, loop exits.
When you enter same number again, like 3.2, while(a[i]) executes twice printing same number again.
As smaller number will be at lower location in array and array parsing starts from 0, it prints smallest 7 numbers. If you reverse the for loop, you can print 7 biggest numbers.
The answer here is how the input data is being stored.
User entered values populate array a. It does not store actual entered numbers, but a COUNT how many times the value was entered (code makes lots of assumptions about data sanity, but lets ignore that)
The data is naturally Sorted from smallest to largest, so to find 7 smallest inputs you just take first 7 values (iterations tracked by index i, c tracks how many values we already did print out) where the COUNT is not zero (a[i], non zero value indicates how many times user entered corresponding value)

Sorting program query

I came across a sorting code in quora and I was very confused with some of the lines of code, if someone explains it to me then it will be a big help.
The code is as follows:
#include <stdio.h>
int array[1000001] = {0};
int main(){
int i,j;
scanf("%d",&j);
int x;
for (i=0;i<j;i++){
scanf("%d",&x);
array[x]++;
}
for (i=0;i<1000001;i++){
while(array[i]>0){
printf("%dn",i);
array[i]--;
}
}
return 0;
}
Can someone explain what is happening in
for(i=0;i<j;i++)
{
scanf("%d",&x);
array[x]++;
}
and here
for (i=0;i<1000001;i++)
{
while(array[i]>0)
{
printf("%dn",i);
array[i]--;
}
}
and what does this dn stands for?
This is by far the best reason not to copy anything from quora or other sources without understanding what it is doing.
No matter what, it doesn't ensure if any of the inputs is right or not.
for(i=0;i<j;i++)
{
scanf("%d",&x);
// Are you sure that 'x' is always a valid int value and is less than your array size?
// No, if a monkey enters 200000 here, kabooom!
array[x]++;
}
In this for loop, which will iterate for j times, an input of type int is taken, and value at that index will be incremented, to know what value was entered by marking that index as 1.
for (i=0;i<1000001;i++)
{
while(array[i] > 0)
{
printf("%dn",i);
array[i]--;
}
}
Its bad by design, because if I have entered only 3 numbers to sort, it still iterates for 1000001 times.
But, it works for an expected/deliberately bounded input values.
For example, lets say user entered 6 values: 4, 2, 7, 0, 6, 8
So, j = 6, and contents of array would be all zeroes except for 4th, 2nd, 7th , 0th, 6th and 8th index.
Now this while loop does a job: it checks if ith index is set, i.e. if that index was entered by user not not. So the code inside while loop will only be executed for 4th, 2nd, 7th , 0th, 6th and 8th indexes.
To explain how the value is printed, lets dry run the code, Initially i is 0.
// Is ith index 1?
while (array[i] > 0) // i is 0
{
// Yes it is,
printf("%d ", i);
// See above, Prints 0 - not 1!
// Printing 'i' is the trick, instead of printing array[i]..
array[i]--; // Note, makes it zero!
}
for next iteration, i is 1
// Is ith index 1? - No, so move on to next index
while (array[i] > 0) // i is 1
{
//
}
lets say iteration has reached 7th index,
// Is ith index 1?
while (array[i] > 0) // i is 7
{
// Yes it is,
printf("%d ", i);
// See above, Printing 'i' is the trick,
// instead of printing array[i]..
array[i]--; // Note, makes it zero!
}
This will sort the numbers, without a doubt, but with some predefined constaints.
Additionally, you can/should add some implementation to get the sorted values in an array, based on if your are required to do it or not.
Finally, "%dn" is not a format specifier. It was probably meant to be "%d\n".
If it is kept unchanged the way it is, it will append n as a character after every number it prints, pointless.
This attempts to read in a number and ingores that the reading might fail.
scanf("%d",&j);
Afterwards j is therefor potentially uninitialised.
This makes a loop, which will do j steps, i.e. potentially an uninitialised number of loops.
for(i=0;i<j;i++)
This attempts to read a number once per loop, without caring about potential failures.
scanf("%d",&x);
It then uses the potentially uninitialised or non-updated number x to access an array.
array[x]++;
In case x is inconsitently for any reason, the access may well be beyond the array, which introduces potential undefined behaviour.
Should it however succeed, the array entry is increased by one.
Most of the array entries are implicitly initialised by the way, not because of the {0}.
So the array entry at the index which matches the read number is counted up.
In total, the number of occurrences of each number in the hopefully correctly formatted input is counted.
Nothing is sorted.
Yet.
This loops over all entries in the array, starting at the lower indexes, i.e. at the lower values of occurred values in the input.
for (i=0;i<1000001;i++)
If an entries in the array is not 0, the index/value is printed and the count is decreased until the entry is zero.
{
printf("%dn",i);
array[i]--;
}
I.e. the current index/value is printed as often as it has been seen in the input.
Implicitly, any value which did not occur in the input is not printed.
Concerning the "%dn" have a look here:
Is %dn a format string?
The most plausible explanation why the "n" does not occur in output, while the output does contain otherwise unexplained newlines, is that the "n" is actually an "\n" in the code which produced the shown output but got lost when posting the code.
(I agree with #WedaPashi that the code will have trouble with negative numbers in input on top of all the other vulnerabilities. Well spotted.)
I believe that the apparent speed of the solution for low values is sabotaged by looping over many empty entries for high values. It gives misleadingly fast output, while taking a long time doing nothing to reach the end of the array before actually being finished.

C prime factorization (loop failure?)

I've been looking into this simple piece of code for 1.5 hrs now and do not find the mistake. I start going crazy ;)
Could anyone of you with a fresh mind and view give me a little hint, where I might have the mistake in? (I am relatively new to C)
The problem is: The code works fine for most of the numbers I entered and tested, but accidentically I found a number that does not work: 3486118 (or 55777888 which is a multiple of it) It goes right for the first loop(s), but after factor 2 it becomes an endless loop.
Here is my code: (any help is greatly appreciated)
// Program calculates prime factors of entered number and returns them
#include <stdio.h>
int main() {
long int num, num_cp;
long int product=1;
/*prime number array up to 100.000*/
long int prime[] = {2, 3, **[...cut out MANY numbers...]** 99971, 99989, 99991};
printf("Please enter a positive integer:\n");
scanf("%li", &num);//55777888 or 3486118 not working... why?
//copy the entered number to keep the original for comparison with "product" and "break;" if equal
num_cp=num;
printf("prime factorization of %li:\n\n", num);
for (int i=0; i<sizeof(prime); i++) {
if (num_cp%prime[i]==0) {
num_cp/=prime[i];
product*=prime[i];
if (product==num) {
printf("%li\n\n", prime[i]);
break;
}
printf("%li*", prime[i]);
//If prime factor found but "product" is still not equal to "num" reset loop counter "i" to -1 (==0 in next loop)
i=-1;
}
}
printf("END");
return 0;
}
"I've been looking into this simple piece of code for 1.5 hrs now and do not find the mistake. I start going crazy ;)"
Don't. Leave it. Go away and eat a pizza. Veg out in front of your favourite movie. Have a shower. Aim for a new high-score on 2048 (or whatever). Your brain gets stuck in a rut and you are no longer seeing your code. You are only seeing what you think your code is.
When you get your brain out of the rut, then -- and only then -- go back and actually read the code you wrote. Not the code you think you wrote, but the code you actually wrote. Yes, they are different.
The prime factors of 55777888 are 2·2·2·2·2·1743059, where the last factor is too large to be contained in your list.
You can fix this in your code: When the product is equal to the product of the prime factors you have found, num_cp is 1. If num_cp is greater than one after you have exhausted your prime list, it is a factor of num. If num/num_cp is smaller than the largest prime you have checked, you can assume that the remaining value of num_cp is a prime. If it wasn't you'd have found more factors earlier.
You can fix this by adding an additional check after your main loop:
if (num_cp > 1) printf("%li\n\n", num_cp);
(If long int is a 64-bit number on your system, you're still not safe: The remaining factor might be made up of several numbers that are not in your array.)
Finally: Resetting the for loop counter so that the loop starts over isn't a good idea. It always starts from the beginning and re-checks primes that you have already checked. And it just isn't natural program flow, which makes it hard to read. A while loop instead of the inner if block would be more natural in my opinion.
Edit: To illustrate:
#include <stdio.h>
int main() {
long int num;
/* prime number array up to 100.000 */
long int prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31};
int nprime = sizeof(prime) / sizeof(*prime);
num = 55;
printf("%li == ", num);
for (int i = 0; i < nprime; i++) {
long int p = prime[i];
if (num <= 1) break;
while (num % p == 0) {
num /= prime[i];
printf("%li", p);
if (num > 1) printf(" * ");
}
}
if (num > 1) printf("%li", num);
printf("\n");
return 0;
}
Things to note:
Instead of resetting the main loop counter i, a while loop is used, which consumes all repetitions of the same factor. If a prime p doesn't divide the number, the while loop isn't entered, just like an if clause.
I've removed the copy of num and used num throughout, mainly to remove clutter. I've also removed the product. Your logic that all prime factors should multiply to the original number, is good. But it also works the other way round: After dividing the number by all primes, we are left with 1. And we have to divide the number anyways. By removing the product, we have to keep track of only one variable instead of two.
I've moved the break condition to the front, so we catch negative numbers and 0 early.
That said, your way to code isn't wrong, just maybe a bit unusual in places.

Heap sort "visual" tree prints extra zeros

I've learned Heap Sort with a visual representation of it with the infamous tree diagram (here), so I set out to find a way to print one out and I've progressed very well so far. My only problem seems to be that if, there aren't any more values to fill up on the line, my program seems to print zeros for some reason.
I'm certain it's probably an error in my code, or an extra line that needs to be added but I'm also looking for advice if this was the best approach. Code below.
#include <stdio.h>
int HeapArray[] = {165, 245, 398, 426, 575, 661, 775, 895, 901, 1028, 1184, 1283, 1350,1427, 1598, 1698};
int main()
{
int i = 0, numL = 1;
int j, k;
for(k = 0; k < 6; k++)
{
if(HeapArray[i] == 0)
break;
for(j = 0; j < numL;j++)
{
printf("%d ", HeapArray[i]);
i++;
}
printf("\n");
numL *= 2;
}
return 0;
}
Things to mention:
In the other most for-loop, I've using the value 6 as the maximum lines to print, however the program stops printing on the line with the last array values in it.
I haven't implemented any alignment to make the diagram 100% accurate since it seemed easy enough to leave for last (i.e. no extra code to confuse me).
Your index i is probably going past the bound of the array
You have 16 elements, so the first time you print 1, then you print 2, then 3, etc
In total you would print 1 + 2 + 4 + 8 = 15 on the fourth line.
When you get to the last line (fifth line), you only have one element to print. However, your inner loop goes from 0 to 16, going past the bounds of the array (and so it prints 0s)
You should add a check in the inner loop to make sure you still have enough elements.
Note that I also highly recommend you actually add a 0 element to the end of the array, so you are not relying on memory outside of its bounds

Resources