as a part of a C program I wrote the following function, which finds the second smallest element of an array
unsigned int array_second_min (unsigned int w[], unsigned int n)
{
unsigned int i, erst = UINT_MAX, zweit = UINT_MAX, count = 0;
if (n < 2)
return UINT_MAX;
for (i = 0;i < n; i++) {
if (w[i] == w[i + 1])
count++;
}
if (count == n - 1)
return UINT_MAX;
for (i = 0;i < n;i++) {
if (w[i] < erst)
erst = w[i];
}
for (i = 0;i < n;i++) {
if (w[i] == erst)
continue;
if ((w[i] - erst) < zweit)
zweit = w[i];
}
return zweit;
}
the problem is that it is not really functioning as it should. I think the problem is in the last for loop, but am not sure about that.
Thank you for your help
picture of the output:
The following code will return the second smallest element
unsigned int array_second_min (unsigned int w[], unsigned int n){
unsigned int i, first = UINT_MAX, second = UINT_MAX;
if(n < 2)
return UINT_MAX;
sort(w, w+n);
second = w[n-2];
return second;
}
This is a somewhat more efficient solution, as it is O(n):
struct pair {
int r[2];
};
struct pair small2(int *a, int n) {
int r[2];
int order;
r[0] = a[0];
r[1] = a[1];
order = (r[0] >= r[1]);
for (int i = 2; i < n; i++) {
if (a[i] <= r[order]) {
r[!order] = a[i];
order = !order;
} else if (a[i] <= r[!order]) {
r[!order] = a[i];
}
}
struct pair x;
x.r[0] = r[order];
x.r[1] = r[!order];
return x;
}
There is a lack of detail about duplicates, this handles them in an unsurprising fashion. Note the trickiness of the order variable; this works because you are only interested in the least two, if you wanted the least 3, you would have to add the extra tests. It would remain O(n), but the C would be greater.
Related
The problem I am facing:
I need to find a way to deal with very large sets (3 to 10000000) of positive and negative ints, this seemed relatively impossible based off of previous experiments.
However, I received hope when I found a Algorithm on github that is really efficient.
However, I really need to adjust it to work with positive and negative numbers... but I am struggling, I know the unsigned int's should be int. but that's all I've got so far.
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
short* flag;
int N, K, correspond = 0;
unsigned int* check, X = 0;
clock_t t1, t2;
void init() {
int i, j;
printf("N=");
scanf_s("%d", &N);
check = malloc(sizeof(unsigned int) * N);
if (check == NULL) {
perror("Out of memory");
exit(-1);
}
srand((unsigned)time(NULL));
printf("\n///check list///\n");
for (i = 0; i < N; i++) {
check[i] = rand() % 1000000 + 1;
printf("%uyen ", check[i]);
}
printf("\n");
K = rand() % N;
flag = malloc(sizeof(short) * N);
for (i = 0; i < N; i++)flag[i] = 0;
i = 0;
while (i <= K) {
j = rand() % N;
if (flag[j] == 0) {
flag[j] = 1;
X = X + check[j];
i++;
}
}
printf("\nX=%uyen\n", X);
}
void swap(int j, int k) {
unsigned int tmp;
tmp = check[j];
check[j] = check[k];
check[k] = tmp;
}
int partition(int left, int right) {
int j = left, k = right;
unsigned int v;
v = check[(left + right) / 2];
do {
while (check[j] > v) j++;
while (v > check[k]) k--;
swap(j, k);
} while (check[j] != check[k]);
return j;
}
void quicksort(int left, int right) {
int j;
if (left < right) {
j = partition(left, right);
quicksort(left, j - 1);
quicksort(j + 1, right);
}
}
void func(unsigned int sum, int i) {
int j, k, t = 0;
if (sum == X) {
correspond = 1;
t2 = clock();
double record = (double)(t2 - t1) / CLOCKS_PER_SEC;
printf("\nAnswer : ");
for (k = 0; k < N; k++) {
if (flag[k] == 1) {
if (t == 0) t = 1;
else if (t == 1) printf("+");
printf("%u", check[k]);
}
}
printf("\n\nThinking time : %f sec . \n", record);
if (record <= 60) printf("Triumph!\n");
else printf("Failure...\n");
return;
}
else if (sum < X) {
for (j = i + 1; (j <= N) && (correspond == 0); j++) {
flag[j] = 1;
func(sum + check[j], j);
}
}
flag[i] = 0;
return;
}
int main() {
int i;
init();
t1 = clock();
for (i = 0; i < N; i++)flag[i] = 0;
quicksort(0, N);
func(0, 0);
return 0;
}
EDITS:
Thanks for all of your inputs, it does help to get some constructive criticism.
To start off here is the to the Github Repo https://github.com/parthnan/SubsetSum-BacktrackAlgorithm credit goes to Parth Shirish Nandedkar.
The name of this Algorithm is "Amortized O(n) algorithm based on Recursive Backtracking" I am not really sure why it would be called "Amortized" as this would mean it divides the input array into multiple subset and use polynomial-time algorithm on each one.
**I have tried to fix the issues mentioned by ** "chux - Reinstate Monica"... please let me know if I did it incorrectly.
seemed relatively impossible based off of previous experiments.
First fix known problems.
At least these problems:
Out of range access
flag = malloc(sizeof(short) * (N + 1)); allocates such that code can access flag[0] to flag[N].
for (k = 1; k <= N + 1; k++) { if (flag[k] == 1) { attempts to access flag[N+1]. Result undefined behavior (UB).
Mis-matched printf
warning: format '%ld' expects argument of type 'long int', but argument 2 has type 'unsigned int' [-Wformat=]
More undefined behavior (UB).
printf("%ldyen ", check[i]);
printf("\nX=%ldyen\n", X);
Allocation success
Since the goal is "very large sets (3 to 10000000)", code definitely should check allocation success to save debug time.
check = malloc(sizeof(unsigned int) * (N + 1));
if (check == NULL) {
perror("Out of memory");
exit -1;
}
Side issues:
Code uses non-idiomatic array access
Code indexes [1...N]. More common to use [0...N-1].
Heavy use of global variables
More common to local variables, passing data as needed on function arguments.
"deal with ... positive and negative ints"
Fix that before posting - or if not important, no need to mention it here.
I am writing a program to read an integer n (0 < n <= 150) and find the smallest prime p and consecutive prime q such that q - p >= n.
My code works, but it runs for about 10 seconds for larger n.
#include <stdio.h>
#include <stdlib.h>
int isPrimeRecursive(int x, int i){
if (x <= 2){
return (x == 2 ? 1:0);
}
if (x % i == 0){
return 0;
}
if (i * i > x){
return 1;
}
return isPrimeRecursive(x, i+1);
}
int findSuccessivePrime(int x){
while (1){
x++;
if (isPrimeRecursive(x, 2)){
return x;
}
}
return 0;
}
int findGoodGap(int n, int *arr){
int prime = findSuccessivePrime(n*n);
while (1){
int gap;
int succPrime;
succPrime = findSuccessivePrime(prime);
gap = succPrime - prime;
if (gap >= n){
arr[0] = succPrime;
arr[1] = prime;
return gap;
}
prime = succPrime;
}
return 0;
}
int main(int argc, char *argv[]){
int n;
int arr[2];
scanf("%d", &n);
int goodGap;
goodGap = findGoodGap(n, arr);
printf("%d-%d=%d\n", arr[0], arr[1], goodGap);
return 0;
}
How can I make the program more efficient? I can only use stdio.h and stdlib.h.
The algorithm is very inefficient. You're recalculating the same stuff over and over again. You could do like this:
int n;
// Input n somehow
int *p = malloc(n * sizeof *p);
for(int i=0; i<n; i++) p[i] = 1; // Start with assumption that all numbers are primes
p[0]=p[1]=0; // 0 and 1 are not primes
for(int i=2; i<n; i++)
for(int j=i*2; j<n; j+=i) p[j] = 0;
Now, p[i] can be treated as a boolean that tells if i is a prime or not.
The above can be optimized further. For instance, it's quite pointless to remove all numbers divisible by 4 when you have already removed all that are divisible by 2. It's a quite easy mod:
for(int i=2; i<n; i++) {
while(i<n && !p[i]) i++; // Fast forward to next prime
for(int j=i*2; j<n; j+=i) p[j] = 0;
}
As Yom B mentioned in comments, this is a kind of memozation pattern where you store result for later use, so that we don't have to recalculate everything. But it takes it even further with dynamic programming which basically means using memozation as a part of the algorithm itself.
An example of pure memozation, that's heavily used in the C64 demo scene, is precalculating value tables for trigonometric functions. Even simple multiplication tables are used, since the C64 processor is MUCH slower at multiplication than a simple lookup. A drawback is higher memory usage, which is a big concern on old machines.
I think it would be a good approach to have all of the prime numbers found and store it in an array; in that case you wouldn't need to do divisions from scratch to find out whether a number is a prime number or not
This is the algorithm which checks if the number "n" is prime simply by doing divisions
bool isPrime(int n) {
if(n <= 1) return false;
if(n < 4) return true;
if(n % 2 == 0) return false;
if(n < 9) return true;
if(n % 3 == 0) return false;
int counter = 1;
int limit = 0;
while(limit * limit <= n) {
limit = limit * 6;
if(n % (limit + 1) == 0) return false;
if(n % (limit - 1) == 0) return false;
}
return true;
}
If you use the algorithm above which its time complexity is in order of sqrt(n) , your overall time complexity would be more than n^2
I suggest you to use "Sieve of Eratosthenes" algorithm to store prime numbers in an array
Check out this link
https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
Here is the code. I used optimized sieve in Main function.
#include <iostream>
using namespace std;
void Sieve(bool* list, const int n);
void OptimizedSieve(bool* list, const int n);
int main() {
bool list[100 / 2];
for(int i = 0; i < 100 / 2; i++) list[i] = true;
OptimizedSieve(list, 100 / 2);
for(int i = 0; i < 100 / 2; i++){
if(list[i]) cout << (2 * i) + 1 << endl;
}
return 0;
}
void Sieve(bool* list, const int n){
list[0] = false;
list[1] = false;
for(int p = 2; p * p <= n; p++){
if(!list[p]) continue;
for(int j = p * p; j < n; j += p){
if(list[j] == true) list[j] = false;
}
}
}
void OptimizedSieve(bool* list, const int n){
list[0] = false;
for(int p = 3; p * p <= n; p += 2){
if(!list[(2 * p) + 1]) continue;
for(int j = p * p; j <= n; j += 2 * p){
int index = (j - 1) / 2;
if(list[index]) list[index] = false;
}
}
}
I tackled the problem by first figuring out the length of two given numbers and aligning the one with less digits (if one exists) into a new array so that the ones, tens, hundreds etc. align with the bigger number's ones, tens, hundreds, etc.
Then I wanted to save the sum of each two aligned elements (with a mod of 10) into a new array while checking if the sum of digits is greater than 10 - just the basic sum stuff. Now the problem occurs with adding two elements into the aplusb integer and I've tried fixing it with writing
int aplusb = (lengthA[max-i]-'0') +(temp[max-i]-'0');
but it doesn't work. I'm stuck and I don't know what to do. Please help.
The whole code:
#include <stdio.h>
#include <math.h>
int main(){
char a[10000];
char b[10000];
scanf("%s %s", &a, &b);
char sum[10000];
int lengthA = 0;
int lengthB = 0;
int i = 0;
while(a[i]){
i++;
} lengthA = i;
i = 0;
while(b[i]){
i++;
} lengthB = i;
char temp[10000];
int aplusb;
int carry = 0;
int max = lengthA;
int difference = abs(lengthA - lengthB);
if(lengthA>lengthB){
for(i=0; i<lengthA; i++){
temp[i+difference]=b[i];
}
for(i=0; i<=max; i++){
aplusb = lengthA[max-i]+temp[max-i]; //<-- this is the problematic line
if(carry = 1) aplusb++;
if(aplusb>9){
carry = 1;
aplusb%=10;
}
sum[i]=aplusb;
}
}
for(i=0; i<=max; i++){
printf("%c", sum[i]);
}
/*
if(lengthB>lengthA){
max = lengthB;
for(i=0; i<lengthB; i++){
temp[i+difference]=a[i];
}
}*/
return 0;
}
Doing operations and storing on very large numbers is very akin to doing operations and storing polynomials, i.e. with x = 10. a0 + a1.10 + a2.10^2 ... + an.10^n.
There are many polynomial libraries on the Internet, where you could find inspiration. All operations on your very large numbers can be expressed in terms of polynomials. This means that by using base 2^8, or even base 2^63, instead of base 10 to internally store your large numbers you would greatly improve performance.
You must also normalize your coefficients after operations to keep them positive. Operations may result in a negative coefficient, That can easily be fixed, as it is very similar to borrowing after a subtraction, this means coefficients must be larger than your base by 1bit.
To convert back to base 10, you'd need to solve r (your result) for v (your value), such as r(10)=v(2^63). This has only one solution, if you enforce the positive coefficients rule.
[note] After thinking about it some more: the rule on positive coefficients may only be necessary for printing, after all.
Example: adding. no memory error checking
int addPolys(signed char** result, int na, const signed char* a, int nb, const signed char* b)
{
int i, nr, nmin, carry, *r;
nr = max(na, nb) + 1;
nmin = min(na, nb);
r = malloc(sizeof(signed char) * (na + nb + 1));
if (nb < na)
{
nr = nb;
}
for (i = 0; i < nmin; ++i)
{
r[i] = a[i] + b[i];
}
for (; i < na; ++i)
{
r[i] = a[i];
}
for (; i < nb; ++i)
{
r[i] = b[i];
}
r[nr - 1] = 0;
// carry - should really be a proc of its own, unoptimized
carry = 0;
for (i = 0; i < nr; ++i)
{
r[i] += carry;
if (r[i] > 10)
{
carry = r[i] / 10;
r[i] %= 10;
}
else if (r[i] < 0)
{
carry = (r[i] / 10) - 1;
r[i] -= (carry * 10);
}
else
carry = 0;
}
// 'remove' leading zeroes
for (i = nr - 1; i > 0; --i)
{
if (r[i] != 0) break;
}
++i;
*result = r;
if (i != nr)
{
*result = realloc(i * sizeof(signed char));
}
return i; // return number of digits (0 being 1 digit long)
}
That code is working now for any two positive numbers with up to ten thousand digits:
#include <stdio.h>
#include <math.h>
#include <string.h>
int main(){
char chara[10000];
char charb[10000];
scanf("%s %s", &chara, &charb);
int lengthA = strlen(chara);
int lengthB = strlen(charb);
int max = lengthA;
if(lengthB>lengthA) max=lengthB;
int dif = abs(lengthA - lengthB);
//ustvari int tabele
int a[max];
int b[max];
int sum[max+1];
// nastavi nule
int i;
for(i=0; i<max; i++){
a[i] = 0;
b[i] = 0;
sum[i] = 0;
} sum[max] = 0;
//prekopiraj stevila iz char v int tabele &obrni vrstni red
for(i=0; i<lengthA; i++){
a[i] = chara[lengthA-i-1]-'0';
}
for(i=0; i<lengthB; i++){
b[i] = charb[lengthB-i-1]-'0';
}
int vsota;
int prenos = 0;
for(i=0; i<max; i++){
vsota = a[i]+b[i] + prenos;
if(vsota>=10) prenos = 1;
else if (vsota<10) prenos = 0;
sum[i]=vsota%10;
}
if(prenos==1){
sum[max] = 1;
for(i = max; i>=0; i--){
printf("%d", sum[i]);
}
} else {
for(i = max-1; i>=0; i--){
printf("%d", sum[i]);
}
}
return 0;
}
I was trying to solve Project Euler question 16 using c. I did not use bignnum libraries. The question asks 2^1000. I decided to store every digit of that number in an array.
For Example: 45 means arr[0]=4, arr[1]=5;
The problem is definitely i the function int multi.
#include<stdio.h>
#include<conio.h>
int multi(int *base, int k);// does the multiplication of array term by 2
void switcher();//switches every term when the fore mostvalue is >10
int finder();// finds the array address of last value
int arr[1000];
int summer();//sums all values of the array
int main()
{
arr[1000] = { 0 };
arr[0] = 1;
int i, j, sum, k, p;
for (i = 0; i < 1000; i++)
{
j = 0;
k = finder();
p = multi(arr + k, j);
}
sum = summer();
printf("sum of digits of 2^1000 is %d", sum);
_getch();
}
int multi(int *base, int k)
{
int p;
if (base == arr)
{
*base = *base - 1;
*base = *base + k;
if (*base > 10)
{
*base = *base - 10;
switcher();
}
return 0;
}
*base = *base * 2;
*base = *base + k;
if (*base > 10)
{
*base = *base - 10;
p = multi(base - 1, 1);
}
else
{
p = multi(base - 1, 0);
}
}
void switcher()
{
int j;
for (j = 0;; j++)
{
if (arr[j] == 0)
{
break;
}
}
j--;
for (; j > 0; j--)
{
arr[j + 1] = arr[j];
}
arr[0] = 1;
}
int finder()
{
int j;
for (j = 0;; j++)
{
if (arr[j] == 0)
{
break;
}
}
return --j;
}
int summer()
{
int summ, i;
summ = 0;
for (i = 0; i<1000; i++)
{
summ = summ + arr[i];
if (arr[i] == 0)
break;
}
return summ;
}
It compiles but during runtime it shows Access Write Violation, base was ......
Please explain this error and how to resolve it ?
Array is of 100 Bytes but you are looping for 1000. Also in function Finder() , you do not have a limit on variable j so your array size is going beyond 100 bytes.
Also use memset to assign array variables to 0.
As said in the comments, 2^1000 has 302 decimal digits.
You're going far outside your array.
But your code is very complicated because you store the digits with the most significant one first.
Since you're only interested in the digits and not the order in which they would be written, you can store the number "in reverse", with the least significant digit first.
This makes the code much simpler, as you can loop "forwards" and no longer need to shuffle array elements around.
Using -1 as "end of number" marker, it might look like this:
void twice(int* digits)
{
int i = 0;
int carry = 0;
while (digits[i] >= 0)
{
digits[i] *= 2;
digits[i] += carry;
if (digits[i] >= 10)
{
carry = 1;
digits[i] -= 10;
}
else
{
carry = 0;
}
i++;
}
if (carry)
{
digits[i] = 1;
digits[i+1] = -1;
}
}
int main()
{
int digits[302] = {1, -1}; /* Start with 1 */
twice(digits); /* digits is now { 2, -1 } */
return 0;
}
I am trying to implement the sieve of eratosthenes in C. The code works for small input values, but once the input goes beyond a certain range, a run- time error is thrown. This is the second problem in the classical section of the SPOJ base. What is the mistake?
#include<stdio.h>
#include<math.h>
int prime(unsigned long int, unsigned long int);
int main()
{
int nitem;
unsigned long int sn,fn;
scanf("%d", &nitem);
while(nitem)
{
scanf("%lu", &fn);
//printf("%d",fn);
scanf("%lu", &sn);
prime(fn, sn);
nitem--;
}
return 0;
}
int prime(unsigned long int fn, unsigned long int sn)
{
unsigned long int prim[100000];
int i,j,k;
for(i = 0; i < 100000; i++)
{
prim[i] = 1;
}
prim[0] = 0;
prim[1] = 0;
//printf("%d", sn);
//printf("%d", k);
//printf("%d", (k <= sn));
for(k = 2; k <= sqrt(sn); k++)
{
// printf("alksnc%5d", k);
if(prim[k] == 1)
{
for(j = 2; (k * j) <= sn; j++)
{
//printf("%d", prim[k]);
prim[k * j] = 0;
}
}
}
for(int i = 0; i <= sn; i++)
{
if(prim[i] !=0 && i >= fn)
{
printf("%lu\n", i);
}
}
printf("\n");
return;
}
Input:
1
100000 100345
output:
run time error
Input:
1
3 5
output:
3
5
We can make more efficient use of memory (2x) by only sieving odd numbers as all the even numbers you're processing waste time and space. It's trickier to work out but gives us something like:
#include <math.h>
#include <libc.h>
#define MAX_ODD_PRIMES 1048576
void prime(unsigned long fn, unsigned long sn)
{
unsigned char primes[MAX_ODD_PRIMES];
for (unsigned long i = 0; i < MAX_ODD_PRIMES; i++)
{
primes[i] = TRUE;
}
primes[0] = 0; // preset first odd, '1'
for (unsigned long k = 3; k <= sqrt(sn) + 1; k += 2)
{
if (primes[k / 2])
{
for (unsigned long j = 3; (k * j) <= sn; j += 2)
{
primes[k * j / 2] = FALSE;
}
}
}
if (fn <= 2)
{
printf("2\n");
fn = 3;
}
for (unsigned long i = fn / 2; i * 2 + 1 <= sn; i++)
{
if (primes[i])
{
printf("%lu\n", i * 2 + 1);
}
}
}
EXAMPLE
> ./a.out
1 1999900 2000000
1999957
1999969
1999979
1999993
>
1) Array range error.
By changing code
for (j = 2; (k * j) <= sn; j++) {
if (k * j >= 100000) {
printf("Out of range %d %d\n", k, j);
exit(1);
}
prim[k * j] = 0;
}
}
With input 2, 100000
Output
Out of range 2 50000
By using an array (VLA) sized to the task, this is avoided. Many other optimizations available. Consider also a malloc() array.
void prime(unsigned long int fn, unsigned long int sn) {
unsigned long int prim[sn + 1];
2) int prime() eventually performs return; where return something; is expected. Suggest changing function to void prime()
int prime(unsigned long int fn, unsigned long int sn) {
unsigned long int prim[100000];
...
printf("\n");
return;
}