I try to implement the karger Minimum Cut algorithm (Karger wiki page)
So far, I have tried my algorithm on small examples (input of size 10) and it seems to work. But when I try to have a bigger input, let's say 200. It just crashes.
To store the minimum cut data, I create a 2D array: GraphCut[SIZE_ARRAY][SIZE_ARRAY_2]
SIZE_ARRAY = 200 in this case, but I can't find a good length for SIZE_ARRAY_2.
Issue is, SIZE_ARRAY_2 has to be big as I modify the initial array to merge the different vertices.
If I declare SIZE_ARRAY_2 = 200, the size won't be enough, but if i put SIZE_ARRAY_2 = 1000, the program just crashes.
The thing is, I have to execute the algorithm 100000 times.
Here is parts of the code:
#define ARRAY_SIZE 200
#define ARRAY_SIZE_2 200
int main()
{
int minCut,minMinCut;
for (int k = 0; k < ARRAY_SIZE * ARRAY_SIZE * 4;k++) {
minCut = kargerMinCut(k);
if (k == 0)
minMinCut = minCut;
else if (minMinCut > minCut)
minMinCut = minCut;
}
printf("\n minMinCut = %d\n", minMinCut);
return 0;
}
int kargerMinCut(int k) {
// 1st dimension: each different node
// 2nd dimension: vertices
long graphCut[ARRAY_SIZE + 1][ARRAY_SIZE_2] = {0};
populateIntegerArray(graphCut); // import data from a file
int nodeToMain[ARRAY_SIZE + 1];
int sizeOfMainNode, indexToMerge,initialRand,i,j,m,nodeToMerge,nodeRemaining = ARRAY_SIZE;
for (m = 0;m<ARRAY_SIZE + 1;m++) // initialization of nodeToMain
nodeToMain[m] = m;
while (nodeRemaining > 2) {
i = 0;
j = 0;
srand(time(NULL) + nodeRemaining);// initialise rand
initialRand = nodeToMain[rand()%(ARRAY_SIZE) + 1]; // pick a random initial node, but not a merged one
sizeOfMainNode = sizeOfArray(graphCut[initialRand]); // size of the initial node
srand(time(NULL) + k); // initialise rand
indexToMerge = rand()%sizeOfMainNode;// pick another random node in the linked nodes (its index to be precise)
nodeToMerge = nodeToMain[graphCut[initialRand][indexToMerge]];
for (m = 0;m<ARRAY_SIZE + 1;m++) // update the nodeToMain array, initialRand is now the main node for nodeToMerge
if (nodeToMain[m] == nodeToMerge)
nodeToMain[m] = initialRand;
// remove the nodeToMerge numbers from the graphCut[initialRand] (as they are going to be merged)
while(graphCut[initialRand][j] > 0 && j < sizeOfMainNode) {
if (initialRand == nodeToMain[graphCut[initialRand][j]]) {
// if this is the last element, do nothing
while(nodeToMain[graphCut[initialRand][sizeOfMainNode - 1]] == initialRand && j < sizeOfMainNode - 1) {
graphCut[initialRand][sizeOfMainNode - 1] = 0;
sizeOfMainNode--;
}
graphCut[initialRand][j] = nodeToMain[graphCut[initialRand][sizeOfMainNode - 1]];
graphCut[initialRand][sizeOfMainNode - 1] = 0;
sizeOfMainNode--;
}
j++;
}
i = 0;
while (graphCut[nodeToMerge][i] > 0 && sizeOfMainNode < ARRAY_SIZE_2 && i < ARRAY_SIZE_2) { // add each vextex of the nodeTomerge to the merged nodes
if (nodeToMain[graphCut[nodeToMerge][i]] != initialRand) {
graphCut[initialRand][sizeOfMainNode] = nodeToMain[graphCut[nodeToMerge][i]];
sizeOfMainNode++;
}
i++;
}
nodeRemaining--;
}
return sizeOfArray(graphCut[nodeToMain[1]]);
}
I'm sure that the code is not really clean, maybe even really bad (beginner in C). So i Welcome any other advice.
The errors I get with the debugger seems really random.
Error is:
Impossible to divide by 0
it stops in time64.c at line 62
tim = (__time64_t)((nt_time.ft_scalar - EPOCH_BIAS) / 10000000i64);
The change in array size is probably causing a stack overflow. A common default size for the stack is 1MB (1048576 bytes). If you have:
long graphCut[200][1000];
and 4 == sizeof(long) the graphCut array is taking up 200 * 1000 * 4 = 800000 bytes, which leaves 248576 bytes which may not be enough for the stack variables in populateIntegerArray() function (I don't see that function). If 8 == sizeof(long) then the array would require 1600000 bytes, which is greater than 1MB.
If an array of that size is required then allocate (all or part) on the heap instead of the stack. For example:
long* graphCut[ARRAY_SIZE_1];
int i;
for (i = 0; i < sizeof(graphCut)/sizeof(graphCut[0]); i++)
{
graphCut[i] = malloc(ARRAY_SIZE_2 * sizeof(graphCut[0][0]));
memset(graphCut[i], 0, ARRAY_SIZE_2 * sizeof(graphCut[0][0]));
}
for (i = 0; i < sizeof(graphCut)/sizeof(graphCut[0]); i++)
{
free(graphCut[i]);
}
Some possible problems are integer or stack overflow (so you're on the right site) and memory initialization.
This implementation should allocate graphCut on the heap, and zero it every time kargerMin gets called, thus addressing those problems.
int minCut, minMinCut;
// There is a small possibility that ARRAY_SIZE*ARRAY_SIZE*4 exceeds int boundary if 16-bit
long k;
long **buffer;
// Allocate graphCut on the heap
buffer = malloc((ARRAY_SIZE + 1)*sizeof(long *));
for (k = 0; k < ARRAY_SIZE + 1; k++)
buffer[k] = malloc(ARRAY_SIZE_2*sizeof(long));
for (k = 0; k < ARRAY_SIZE * ARRAY_SIZE * 4;k++) {
minCut = kargerMinCut(k, buffer);
if (k == 0)
minMinCut = minCut;
else if (minMinCut > minCut)
minMinCut = minCut;
}
printf("\n minMinCut = %d\n", minMinCut);
// Here we free the buffer. We could do it in any order, but
// as it costs nothing here to do so, we free it in reverse-
// allocation-order to avoid any possible memory fragmentation
// - which is moot anyway, if this is a main() and we're exiting
// the program. In other instances it could be relevant.
for (k = 0; k < ARRAY_SIZE + 1; k++)
{
free(buffer[ARRAY_SIZE-k]); buffer[ARRAY_SIZE-k] = NULL;
}
free(buffer); buffer = NULL;
// The NULLing of the just-freed variables has no purpose except
// to GUARANTEE that any illegal use of them, dangling pointers,
// leftover copies etc. will immediately trigger a core dump and
// be discovered, instead of lurking undetected.
return 0;
}
int kargerMinCut(long k, long **graphCut) {
// 1st dimension: each different node
// 2nd dimension: vertices
// Zero graphCut. If populateIntegerArray rewrites
// the whole of graphCut, these four lines are redundant.
int i, j;
for (i = 0; i < ARRAY_SIZE + 1; i++)
for (j = 0; j < ARRAY_SIZE_2; j++)
graphCut[i][j] = 0;
// otherwise, they make sure that no old value of graphCut
// or uninitialised value is going to linger and potentially
// corrupt calculations later on.
populateIntegerArray(graphCut); // import data from a file
I have implemented the Karger algorithm in C++. My code below works on large files but I have not optimized enough...it still runs fast though..but could be faster..Try this solution.
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <string>
#include <map>
#include <list>
#include <fstream>
#include <sstream>
#include <set>
#include <stdlib.h>
#include <time.h>
int pick_edge(std::map <int, std::list<int>> g2, set<int> myset, int &u, int &v)
{
std::map <int, std::list<int>>::iterator it;
std::list<int> eachRow;
int rand_vertex;
int rand_edge;
srand (time(NULL));
rand_vertex = (rand() + 1) % myset.size() ;
if (rand_vertex == 0)
rand_vertex = 1;
u = get_value_at_i(myset, rand_vertex);
for (it = g2.begin(); it != g2.end(); ++it) {
if (it->first == u) {
eachRow = it->second;
rand_edge = (rand() + 1) % eachRow.size();
if (rand_edge == 0)
rand_edge = 1;
v = get_edge_at_j(eachRow, rand_edge);
break;
}
}
return 0;
}
map <int, std::list<int>> merge_uv(map <int, std::list<int>> g2, int u, int v)
{
std::map <int, std::list<int>>::iterator it_g;
std::map <int, std::list<int>>::iterator it_u;
std::map <int, std::list<int>>::iterator it_v;
std::list<int>::iterator iter_l;
std::list<int> eachRow, uRow, vRow;
std::list<int> newRow;
int vertex;
int j = 0;
map <int, std::list<int>> new_Graph_G;
vRow.clear();
uRow.clear();
eachRow.clear();
newRow.clear();
for (it_g = g2.begin(); it_g != g2.end(); ++it_g) {
vertex = it_g->first;
eachRow = it_g->second;
if (vertex == u) {
uRow = it_g->second;
it_u = it_g;
j++;
continue;
}
if (vertex == v) {
vRow = it_g->second;
it_v = it_g;
j++;
continue;
}
}
if (j == 2) {
uRow.sort();
vRow.sort();
// uRow.merge(vRow);
for (std::list<int>::iterator ite = vRow.begin(); ite != vRow.end(); ++ite) {
if (*ite != u) {
uRow.push_back(*ite);
}
}
g2.erase(v);
g2[u] = uRow;
}
for (it_g = g2.begin(); it_g != g2.end(); ++it_g) {
eachRow = it_g->second;
for (std::list<int>::iterator ite = eachRow.begin(); ite != eachRow.end(); ++ite) {
if (*ite == v && *ite != it_g->first) {
newRow.push_back(u);
} else if (*ite == it_g->first) {
continue;
} else {
newRow.push_back(*ite);
}
}
new_Graph_G[it_g->first] = newRow;
newRow.clear();
}
for (it_g = g2.begin(); it_g != g2.end(); ++it_g) {
eachRow = it_g->second;
if (it_g->first == u) {
for (std::list<int>::iterator ite = eachRow.begin(); ite != eachRow.end(); ++ite) {
if (*ite != u && *ite != v) {
newRow.push_back(*ite);
}
}
new_Graph_G[it_g->first] = newRow;
break;
}
}
return new_Graph_G;
}
int get_min_cut(std::map <int, std::list<int>> g1)
{
int v;
std::list<int> eachRow;
std::map <int, std::list<int>>::iterator it_g;
int min_cut = 0;
for (it_g = g1.begin(); it_g != g1.end(); ++it_g) {
eachRow = it_g->second;
v = it_g->first;
for (std::list<int>::iterator ite = eachRow.begin(); ite != eachRow.end(); ++ite) {
if (*ite != v) {
min_cut++;
}
}
break;
}
return min_cut;
}
int EdgeContractionAlgorithm()
{
std::map <int, std::list<int>>::iterator it;
int min_cut = 0;
int vertex = 1;
std::list<int> eachRow;
std::set<int> myset;
std::set<int>::iterator itSet;
std::map <int, std::list<int>> g2;
int edge;
int n_vertices;
int cnt = 0;
int u, v;
n_vertices = Cal_nVertices(myset, Graph_G);
g2 = Graph_G;
// Contraction algorithm.
while (n_vertices > 2) {
edge = pick_edge(g2, myset, u, v);
g2 = merge_uv(Graph_G, u, v);
n_vertices = g2.size();
myset.erase (myset.find(v));
Graph_G = g2;
}
print_graph(g2);
min_cut = get_min_cut(g2);
return (min_cut);
}
Related
I am already puzzling for two weeks programming a knapsack problem in C.
Since I didn't manage to get it working with structs directly, I have made a solution with an extra array. If you know how to use the structs directly, that would be great!
But the main problem is, that when I get multiple solutions with the same value, I'd want to only get the solution with the least weight.
My code till now:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#define TEAMS 5
#define max_players 20
typedef struct Team
{
char name [10];
int players;
bool Is_Playing;
int points;
} Team;
struct Team one = { "Ones", 12, true, 18 };
struct Team two = { "Twos", 4, true, 10 };
struct Team three = { "Threes", 5, true, 9 };
struct Team four = { "Fours", 12, true, 22 };
struct Team five = { "Fives", 8, true, 15 };
typedef struct selection_entry
{
int points;
int team;
struct selection_entry *prev;
} selection_entry;
Team *teams[TEAMS] = { &one, &two, &three, &four, &five };
int selection(int players[], const int *selection_points, size_t n,
int capacity, int **solution)
{
int i, j;
selection_entry **table;
int result;
selection_entry *head;
/* Allocate the table */
table = malloc((n + 1) * sizeof(selection_entry *));
for (i = 0; i <= n; i++) {
table[i] = malloc((capacity + 1) * sizeof(selection_entry));
}
/* Calculate the points and build chains */
for (i = 0; i <= n; i++) {
for (j = 0; j <= capacity; j++) {
if (i == 0 || j == 0) {
/* Initialising the first row or column */
table[i][j].points = 0;
table[i][j].team = 0;
table[i][j].prev = NULL;
}
else if (players[i - 1] <= j) {
/* Can add team */
if (selection_points[i - 1] + table[i - 1][j - players[i - 1]].points
> table[i - 1][j].points) {
/* Add team */
table[i][j].points = selection_points[i - 1] + table[i - 1][j - players[i - 1]].points;
table[i][j].team = i - 1;
table[i][j].prev = &table[i - 1][j - players[i - 1]];
}
else {
/* Don't add team */
table[i][j].points = table[i - 1][j].points;
table[i][j].team = table[i - 1][j].team;
table[i][j].prev = table[i - 1][j].prev;
}
}
else {
/* Don't add team */
table[i][j].points = table[i - 1][j].points;
table[i][j].team = table[i - 1][j].team;
table[i][j].prev = table[i - 1][j].prev;
}
}
}
/* Read back the solution */
*solution = calloc(n, sizeof(int));
for (i = 0, head = &table[n][capacity];
head->prev != NULL;
head = head->prev, i++) {
(*solution)[head->team] = 1;
}
result = table[n][capacity].points;
for (i = 0; i <= n; i++) {
free(table[i]);
}
free(table);
return result;
}
int GetSelectionArraySize()
{
int s=0;
for (int i = 0; i < TEAMS; i++)
{
if (teams[i]->Is_Playing)
{
s++;
}
}
return s;
}
void main()
{
int a_size = GetSelectionArraySize();
int players[a_size];
int selection_points[a_size];
int i, j=0;
for (int i = 0; i < TEAMS; i++)
{
if (teams[i]->Is_Playing)
{
players[j] = teams[i]->players;
selection_points[j] = teams[i]->points;
j++;
}
}
const int capacity = max_players;
const size_t n = sizeof(players) / sizeof(players[0]);
int *solution;
int points = selection(players, selection_points, n, capacity, &solution);
fprintf(stdout, "Value: %d\n", points);
for (i = 0; i < n; i++)
{
if (solution[i])
{
fprintf(stdout, "Team %d with %d players and %d points.\n", i, players[i], selection_points[i]);
}
}
free(solution);
}
Problems:
I can't figure out why this isn't working properly and how I get it to give me the best solution (highest points but least players within the maximum specified number of players).
Sub-problem:
The array-workaround annoys me, but I fail in making it work with the original arrays of structs directly...
Thank you very much in advance!!!
Kindest regards!
Ralf
I'm not going into detail of your code, but instead lets have a look at the problem and the knapsack-like solution.
Basically, the relevant properties of your solution are value and weight, where weight is constrained and a solution A is better than solution B, if A.value > B.value or if A.value = B.value AND A.weight < B.weight as long as A and B satisfy the constraint.
So, given a list of potential items [item1, [others...]], where a solution including items1 is possible, you need to find the better solution
subresult1 = solve([others...], weightconstraint - item1.weight)
candidate1 = (subresult1.value + item1.value, subresult1.weight + item1.weight)
candidate2 = solve([others...], weightconstraint)
if (candidate1.value > candidate2.value) return candidate1
if (candidate1.value == candidate2.value && candidate1.weight < candidate2.weight) return candidate1
return candidate2
I hope this pseudo-code is clear enough to explain the logic to be implemented.
In the following code, the result is ok, but the code will be crash when executing finish, and increase one error: Heap corruption detected, the free list is damaged at 0x600000008f50
int *mergeSort(int *a,int count) {
int leftCount = count / 2;
int rightCount = count - leftCount;
int *leftData = getData(a, 0, leftCount);
int *rightData = getData(a, leftCount, count);
int *sortedLeftData = mergeSort(leftData, leftCount);
int *sortedRightData = mergeSort(rightData, rightCount);
int *resultData = mergeData(sortedLeftData, sortedRightData, leftCount,
rightCount);
return resultData;
}
int *getData(int *a,int from, int to) {
if (from > to) { return nil; }
int *res = malloc(to - from + 1);
for (int index = from; index < to; index ++) {
int value = a[index];
res[index-from] = value;
}
return res;
}
int *mergeData(int *a, int *b, int acount, int bcount) {
int *result = malloc(acount + bcount);
int aindex,bindex,rindex;
aindex = bindex = rindex = 0;
while (aindex < acount | bindex < bcount) {
int value,avalue = INT_MAX,bvalue = INT_MAX;
if (aindex < acount) { avalue = a[aindex]; }
if (bindex < bcount) { bvalue = b[bindex]; }
// get value from a point.
if (avalue <= bvalue) {
value = avalue;
aindex ++;
}else {
// get value from b point.
value = bvalue;
bindex ++;
}
result[rindex] = value;
rindex ++;
}
return result;
}
I don't understand why does crash when free the point, any answer will helpfull, thanks.
All of your allocations are too small, and thus you are overflowing your buffers.
The malloc function allocates the requested number of bytes. You need to multiply the number of elements you require by sizeof(int) if your elements are int type. e.g.
int *result = malloc((acount + bcount) * sizeof(int));
Other potential problems I spotted while reading your code are:
Using the bitwise-or operator instead of logical-or:
while (aindex < acount | bindex < bcount)
// ^ should be ||
You never free your temporary buffers, thus your program will blow out memory by leaking like crazy. You must free leftData, rightData, sortedLeftData and sortedRightData in the mergeSort function after you are finished with them.
Note that merge sort actually does not require so much allocation. Doing so will have a huge impact on performance. An efficient implementation only requires a single additional buffer for scratch operations, which can be allocated at the beginning.
I did implementation merge sort use single buffer, as the following code:
void mergeSort(int *a, int count) {
int *tempBuffer = malloc(count * sizeof(int));
mergeSortWithBuffer(a, 0, 0, count - 1,tempBuffer);
free(tempBuffer);
}
void mergeSortWithBuffer(int *a, int leftStart, int rightStart, int end, int *tempBuffer) {
int leftCount = rightStart - leftStart;
int rightCount = end - rightStart + 1;
if (leftCount + rightCount <= 1) { return; }
if (leftCount != 0) {
// left dichotomy
int lls = leftStart;
int lrs = leftStart + leftCount/2;
int lnd = rightStart - 1;
mergeSortWithBuffer(a, lls, lrs, lnd,tempBuffer);
}
if (rightCount != 0) {
// right dichotomy
int rls = rightStart;
int rrs = rightStart + rightCount/2;
int rnd = end;
mergeSortWithBuffer(a, rls, rrs, rnd,tempBuffer);
}
mergeData(a, leftStart, rightStart, end, tempBuffer);
}
void mergeData(int *a, int leftStart, int rightStart, int end,int *tempBuffer) {
int leftCount = rightStart - leftStart;
int rightCount = end - rightStart + 1;
int lindex,rindex;
lindex = rindex = 0;
while (lindex < leftCount || rindex < rightCount) {
int lv = INT_MAX,rv = INT_MAX;
if (lindex < leftCount) { lv = a[leftStart + lindex]; }
if (rindex < rightCount) { rv = a[rightStart + rindex]; }
if (lv <= rv) {
tempBuffer[leftStart + lindex + rindex] = lv;
lindex ++;
}else {
tempBuffer[leftStart + lindex + rindex] = rv;
rindex ++;
}
}
for (int index = 0; index < end - leftStart + 1; index ++) {
a[leftStart + index] = tempBuffer[leftStart + index];
}
}
I thought the mergeData function can replace data in the point a each other without the temp buffer, but the logic is too complex and the efficient is not fast, so i add the temp buffer in this function.
Would you have better suggestions if you have willing?
Hi Guys i have edited the questions.Here is my entire code.I have given basic amount of readability to my program.I hope u guys can understand the program.
#include<stdio.h>
#include<stdlib.h>
int Max_Min(int,int,int,int *, int *);
int *Max,Number;
int main()
{
int n1, n2,Maximum_Element=0,*Max;
int i = 0, j = 0;
scanf("%d",&Number);
Max =(int *) malloc(sizeof(int)*Number);//Array Max is created
for (int k = 0;k <(Number/2);k++)
{
scanf("%d", &n1);
scanf("%d", &n2);
Max[k] = Max_Min(0,1,0,&n1,&n2);//Passing integer elements n1,n2 with flag 0
}
Maximum_Element=Max_Min(1,1,((sizeof(Max)*Number)/8),Max,Min);//Passing array elements Max,Min with flag 1 to function Max_Min
printf("Maximum_Element=%d", Maximum_Element);
return 0;
}
int Max_Min(int flag,int Max_Min_flag,int length,int *n1,int *n2)//n1 and n2 should be able to handle array and integers
{
int i=0,j = 0,k1,k2,Min1 = 0, Min2 = 0,count=0, Not_Zero = 0,x=0,y=0, *New_Max = 0,*New_Min;
/*Recursive Loop for splitting the array elements and calling the array */
if (flag == 1)
{
New_Max = (int *)(malloc(sizeof(int)*length));
for (;i <= ((length) / 2);i = i + 2)//
{
k1 = n1[i];
j = i + 1;
if (j <= ((length + 1) / 2))
{
k2 = n1[j];
New_Max[count] = Max_Min(0, 1, 0, &k1, &k2);//It is passing integer elements with flag 0 to function Max_Min
count++;
}
}
New_Max[count] = n1[j + 1];
for (int i = 0;i < count + 1;i++)
{
**/* Problem is assigning Max[i]=New_Max[i] is not getting assigned*/**
Max[i] = New_Max[i];//Copying from New_Max to Max because New_Max will be overwritten,so possible chaunce of dataloss
Not_Zero++;
}
while ((sizeof(Max) / 4 - (Not_Zero))>0)
{
Max[Not_Zero] = 0;
Not_Zero++;
}
/*Logic for calling recursive functions based on the count*/
if (count > 1)
{
count--;
Max_Min(1, 1, count, Max, Min);//Calling Recursive function by Passing Entire Arrays with flag 1.
}
else if (count == 1 && Max[1] == 0)
{
*n1 = Max[0];
*n2 = Min[0];
}
else if (count == 1 && Max[2] == 0)
{
Max_Min(1, 1, count + 1, Max, Min);
count--;
}
}
/*Logic for Finding Maximum & Minimum element is present down*/
if (flag == 0)
{
printf("flag");
if (Max_Min_flag == 1)
{
if (*n1 > *n2)
{
}
else if ((*n1 < *n2) && Max_Min_flag == 1)
{
int temp = 0;
temp = *n1;//5
*n1 = *n2;//7
*n2 = temp;//5
}
}
else if (Max_Min_flag == 2)
{
if (*n1 > *n2)//7>2
{
int temp = 0;
temp = *n1;//2
*n1 = *n2;//2
*n2 = temp;//2,7
}
else if (*n1 < *n2)
{
}
}
}
return *n1;//7
}
Problem is assigning Max[i]=New_Max[i] in function Max_Min().It shows Run time error as "Access violation writing location 0x00000000."
First you need to #include <stdlib.h> to use malloc
You must declare your function before using it.
func must return int*.
Also in func "n", first "Max", and second "Max" needs to be the same variable. Rename "n" to "Max"
This is the code corrected with an extra printf;
#include <stdio.h>
#include <stdlib.h>
int *Max,Number=5;
int* func(int *Max)
{
for(int j=0;j<5;j++)
Max[j]=j;//Its not working in this line
return Max;
}
int main()
{
Max=(int *) malloc(sizeof(int)*Number);
for(int i=0;i<5;i++)
Max[i]=i;
int* x = func(Max);
for(int i=0;i<5;i++)
printf("%d", x[i]);
}
The following contains only minor adaptations of your code and it runs fine:
int *func(int *n);
int *Max,Number=5;
int main()
{
int *x,i;
Max=(int *) malloc(sizeof(int)*Number);
for(i=0;i<Number;i++)
Max[i]=i;
x=func(Max);
free(Max);
return(0);
}
int *func(int *n)
{
int j;
for (j=0;j<Number;j++)
n[j]=Number-j; // reverse the number, just to check
return Max;
}
I've tried solving a math problem (https://projecteuler.net/problem=2) in C but my program leads to a segmentation fault. I've tried looking through the code, searching on this site as well as using -Wall and -Wpedantic to no avail. What exactly in this code is causing a segmentation fault (core dumped)?
#include <stdio.h>
#include <stdlib.h>
// Calculates the sum of all fib numbers
// below (non-inclusive) the parameter num.
int calculate(int num) {
int i = 2, bytes_to_allocate;
// ---------- BEGIN: Memory Allocation Calculation ----------
// Calculates the exact number of fibs less than num, and saves this
// to the variable called "bytes_to_allocate".
int flist[3]; // A small list of 3 ints to calculate fib numbers.
flist[0] = 1;
flist[1] = 2;
// The if statements in this loop are used to move the
// index i to the proper place in order to calculate
// every fib number less than num.
while(1) {
if(i == 0) {
if(flist[i+1] + flist[i+2] >= num) {
break;
}
flist[i] = flist[i+1] + flist[i+2];
i = 1;
}
else if(i == 1) {
if(flist[i-1] + flist[i+1] >= num) {
break;
}
flist[i] = flist[i-1] + flist[i+1];
i = 2;
}
else if(i == 2) {
if(flist[i-1] + flist[i-2] >= num) {
break;
}
flist[i] = flist[i-1] + flist[i-2];
i = 0;
}
bytes_to_allocate++;
}
// ---------- END: Memory Allocation Calculation ----------
// Allocates exactly the right amount of bytes corresponding
// to the number of fibs below value num.
int* list = calloc(bytes_to_allocate, sizeof(int));
if(list == NULL) {
printf("Malloc failed.\n");
exit(1);
}
list[0] = 1;
list[1] = 2;
// This loop initializes all fibs that are < num in list.
for(i = 2; i < num; i++) {
if(list[i-1] + list[i-2] < num) {
list[i] = list[i-1] + list[i-2];
}
else { // If not less than num
break;
}
}
// Add all of the even fibs in the list (and the cleared adresses)
int sum = 0;
for(i = 0; i < num; i++) {
if(list[i] % 2 == 0) {
sum += list[i];
}
}
free(list); // Frees up allocated memory.
return sum;
}
int main(void) {
int sum;
int num = 4000000;
sum = calculate(num);
printf("\nSum of even-valued fibs < %d: %d\n\n", num, sum);
return 0;
}
You're not allocating enough memory for list. Just make it big enough to hold num numbers:
int* list = calloc(num, sizeof(int));
For issues like this, valgrind is your friend. When I ran your code through it, it said that initialization loop was writing past the end of the allocated memory.
EDIT:
Doing this also saves you the time and code of counting the number of fibs beforehand, so everything in calculate before the allocation can go away.
EDIT 2:
A much simpler way that doesn't require a large memory footprint:
int calculate(int num)
{
int prev1, prev2, curr;
int sum;
sum = 0;
prev1 = 0;
prev2 = 1;
curr = 1;
while (curr < num) {
if (curr % 2 == 0) {
sum += curr;
}
prev1 = prev2;
prev2 = curr;
curr = prev1 + prev2;
}
return sum;
}
You are trying to bytes_to_allocate++ where bytes_to_allocate is uninitialized.
Initialize bytes_to_allocate++ first.
I need an idea how to effectively find areas below marked with 0 in two-dimensional array. It should be noted that there are other areas, such as this picture shows one of two who owns coordinate (0.0) and the other owns coordinate (21.3).
00000000000111110000111
00000000001111110000111
00000000011111100000111
00000000000111000001101
00000000011100000011101
00000001111100001111001
00000111111111011111001
00000001111100001111001
00000000010000000011001
00000000000000000001111
Of course a real array will be much larger.
Recursive version that goes to all sides and stops at mark 1 or array side isn't fast enough.
It looks like you're looking for a flood-fill algorithm. The wikipedia page I linked lists a few algorithms which may be faster than the obvious recursive method.
Flood-fill will be a good match if the areas you're looking for are small compared to the entire array, and you don't need to search for all of them. If you need to know about most or all of them, then computing them all in a single shot using a union-merge based connected component labeling algorithm may be a better choice. Here's some code that implements such an algorithm (note that I've altered it to run in a single pass):
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <map>
const char *data[] = {
"00000000000111110000111",
"00000000001111110000111",
"00000000011111100000111",
"00000000000111000001101",
"00000000011100000011101",
"00000001111100001111001",
"00000111111111111111001",
"00000001111100001111001",
"00000000010000000011001",
"00000000000000000001111",
NULL
};
struct label {
private:
int index;
int rank;
label *parent;
public:
label ()
: index(-1), rank(0), parent(this)
{ }
int getIndex(int &maxIndex) {
if (parent != this)
return find()->getIndex(maxIndex);
if (index < 0)
index = maxIndex++;
return index;
}
label *find() {
if (parent == this)
return this;
parent = parent->find();
return parent;
}
label *merge(label *other)
{
label *xRoot = find();
label *yRoot = other->find();
if (xRoot == yRoot)
return xRoot;
if (xRoot->rank > yRoot->rank) {
yRoot->parent = xRoot;
return xRoot;
} else {
xRoot->parent = yRoot;
if (xRoot->rank == yRoot->rank)
yRoot->rank++;
return yRoot;
}
}
};
int width, height;
int main() {
for (int i = 0; data[0][i]; i++)
width = i + 1;
for (int i = 0; data[i]; i++) {
height = i + 1;
}
std::vector<std::vector<unsigned short> > lblinfo;
lblinfo.resize(height, std::vector<unsigned short>(width, 0));
std::vector<label *> labels;
labels.push_back(NULL); // 0 is used as an unassigned flag
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (data[y][x] == '1')
continue;
// Try to find a neighboring label
unsigned short lblid = 0;
if (x != 0 && lblinfo[y][x-1] != 0)
lblid = lblinfo[y][x-1];
// merge with cells above
if (y != 0) {
for (int x2 = x - 1; x2 <= x + 1; x2++) {
if (x2 < 0)
continue;
if (x2 >= width)
continue;
unsigned short otherid = lblinfo[y - 1][x2];
if (!otherid)
continue;
if (!lblid)
lblid = otherid;
else {
labels[lblid]->merge(labels[otherid]);
}
}
}
if (!lblid) {
// assign a new label
lblid = labels.size();
labels.push_back(new label);
}
lblinfo[y][x] = lblid;
}
}
// Assign indices to the labels by set and print the resulting sets
int maxindex = 0;
static const char chars[] = "abcefghijklmnopqrstuvwxyz";
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
unsigned short labelid = lblinfo[y][x];
if (labelid == 0) {
putchar(data[y][x]);
continue;
}
label *label = labels[labelid];
int idx = label->getIndex(maxindex);
if (idx >= sizeof(chars) - 1) {
printf("\n\n Too many labels to print!\n");
exit(1);
}
putchar(chars[idx]);
}
printf("\n");
}
return 0;
}