Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have an exercise (please take a look at picture):
Problem
The problem:
You input any number (number is integer) then the program will find numbers in binary tree has 4 levels. The top is your number you input, and the pair of 2 numbers at lower level will be added together and 2 times the parent number above. And the numbers must be used only once.
Here my code, but it still doesn't work properly. Please figure out for me what is my mistake here.
#include <stdio.h>
#include <stdbool.h>
#define MAX 15
int data[MAX]; // binary tree with 4 levels
void init_Data(){
int i=0;
for(i=0; i<=MAX; i++){
data[i] = -1;
}
}
void BackTracking(int index){
int c1, c2; // c1 and c2 are a pair that is added and equal 2 times the parent number
for(c1=1; c1<data[index]; c1++){
c2 = 2*data[index] - c1;
if(!Search(c1) && !Search(c2)){ // checking c1 and c2 is used or not
data[2*index+1] = c1; // put c1 into data
data[2*index+2] = c2; // put c2 into data
if(index == MAX/2) // the stop condition
print_Data(); // print out
else
BackTracking(index+1);
}
}
}
bool Search(int number){
int i=0;
for(i=0; i<MAX; i++){
if(number == data[i])
return true;
}
return false;
}
int main(int argc, char const *argv[]) {
int n = 0;
init_Data();
printf("Enter your number: ");
scanf("%d\n", &n);
data[0] = n;
BackTracking(0);
return 0;
}
I've got working code for this exercise, but since it is an exercise, I'll just give some primers.
How do you solve the problem? One way to find a valid configuration (of Sudoku grids, of eight non-attacking queens on a chess board or of numbers in a tree) is backtracking: You prober various possible solutions and when you find that it is invalid, you revert to a previous partial solution that is still valid.
One way to implement backtracking is to use recursion, where each step in the solution (put a number in the Sudoku grid, placing a queen, assigning a pait of numbers in your problem) is one level of recursion. Backracking then means to return to previous levels in the recursion.
How do you represent the tree? Your picture shows a binary tree. You can represent such a tree as a linear array:
0
1 2
3 4 5 6
7 8 9 10 11 12 13 14 15
For a node with the array index i, you get:
parent(i) == (i - 1) / 2
left(i) == 2*i + 1
right(i) == 2*i + 2
You need the array to print the solution once you have found it.
How do you traverse the tree? There are many ways to traverse a tree. Here, you can use many ways as long as you have assigned a value to the parent node before visiting it.
In your case, the easiest way is to do a level-wise iteration that follows the linear array. You can use the fact that the two numbers you need to find for each parant node are adjacent. Start with index i = 1 and if you can find two valid numbers, advace to i + 2.
That way to iterate also provides a nice terminating condition: When you reach the fifth level, you have found a valid solution.
How do you find out whether a number has been used? The straightforward solution is to look at all numbers up to the current index. This method will become slow the deeper you go in your tree, though. (But that shouldn't be a concern for a tree of 4 levels.)
If you choose your numbers such that the smaller number if always to the right, you have a binary search tree. You can use that to find whether a number has been used in (O log n), that is you have to visit each level of the tree once instead of visiting each node once.
There are other ways to keep track of which numbers have been used like bit sets or hashes, but these have to be implemented in C.
Edit: You've got the basics of the code right, but:
The termination criterion should be checked for the next step, so index + 1 == MAX/2. Alternatively, you can check index before (and instead of) entering the loop. (I prefer the latter, because it puts the termination criterion at the top of the function, but the former is closer to your existing code.)
In Search, you check the whole range of elements. That's okay, because the unused elements are −1. There is one problem, though: You don't reset the used elements, so that the check is against values from solutions that you have backtracked from. You can reset these values to −1 before backtracking. A better approach might be to check only the values that you have already entered. (Not resetting the values means that you will find fewer solutions. The first value for which there are solutions is 8, but without resetting, it won't find a solution here.)
Currently, you print all solutions. (Well, all solutions for which the left bracnch has the smaller number.) Depending on the value, there will be a lot of solutions. If you just want to print one solution, you can stop backtracking short by returning early.
You should provide prototypes of the functions before you use them, so that the compiler can make sure you are passing the correct arguments.
Here's a corrected version:
void BackTracking(int index){
int c1, c2;
for(c1=1; c1<data[index]; c1++){
c2 = 2*data[index] - c1;
if(!Search(c1) && !Search(c2)){
data[2*index+1] = c1;
data[2*index+2] = c2;
if(index + 1 == MAX/2)
print_Data();
else
BackTracking(index+1);
data[2*index+1] = -1;
data[2*index+2] = -1;
}
}
}
I think you can solve it using dynamic programming, if you do not care about number of computations, then you can also use combination algorithms.
your input = 10
for first level there could be X possible pair of numbers {n1,n2} = 2*10
for each of the pairs above pick one and use recursion to check further
run(input,tree)
for n1 from 0 to input:
for n2 from n1+1 to input:
if n1+n2 = 2*input:
pairs.add(n,input-n)
//if no pairs staisfy our condition
if pairs ==null:
return false
//check each pair
foreach pair in pairs:
run(pair.numbers, tree)
Related
I have dynamically allocated array consisting of a lot of numbers (200 000+) and I have to find out, if (and how many) these numbers are contained in given interval. There can be duplicates and all the numbers are in random order.
Example of numbers I get at the beginning:
{1,2,3,1484984,48941651,489416,1816,168189161,6484,8169181,9681916,121,231,684979,795641,231484891,...}
Given interval:
<2;150000>
I created a simple algorithm with 2 for loops cycling through all numbers:
for( int j = 0; j <= numberOfRepeats; j++){
for( int i = 0; i < arraySize; i++){
if(currentNumber == array[i]){
counter++;
}
}
currentNumber++;
}
printf(" -> %d\n", counter);
}
This algorithm is too slow for my task. Is there more efficient way for me to implement my solution? Could sorting the arrays by value help in this case / wouldn't that be too slow?
Example of working program:
{ 1, 7, 22, 4, 7, 5, 11, 9, 1 }
<4;7>
-> 4
The problem was simple as the single comment in my question answered it - there was no reason for second loop. Single loop could do it alone.
My changed code:
for(int i = 0; i <= arraySize-1; i++){
if(array[i] <= endOfInterval && array[i] >= startOfInterval){
counter++;
}
This algorithm is too slow for my task. Is there more efficient way for me to implement my solution? Could sorting the arrays by value help in this case / wouldn't that be too slow?
Of course, it is slow. A single pass algorithm to count the number of elements that are in the set should suffice, just count them in a single pass if they pass the test (be n[i] >= lower bound && be n[i] < upper bound or similar approach) will do the work.
Only in case you need to consider duplicates (e.g. not counting them) you will need to consider if you have already touched them or no. In that case, the sorting solution will be faster (a qsort(3) call is O(nlog(n)) against the O(nn) your double loop is doing, so it will run in an almost linear, then you make a second pass over the data (converting your complexity to O(nlog(n) + n), still lower than O(nn) for the large amount of data you have.
Sorting has the advantage that puts all the repeated key values together, so you have to consider only if the last element you read was the same as the one you are processing now, if it is different, then count it only if it is in the specified range.
One final note: Reading a set of 200,000 integers into an array to filter them, based on some criteria is normally a bad, non-scalable way to solve a problem. Your problem (select the elements that belong to a given interval) allow you for a scalable and better solution by streaming the problem (you read a number, check if it is in the interval, then output it, or count it, or whatever you like to do on it), without using a large amount of memory to hold them all before starting. That is far better way to solve a problem, as it allows you to read a true unbounded set of numbers (coming e.g. from a file) and producing an output based on that:
#include <stdio.h>
#define A (2)
#define B (150000)
int main()
{
int the_number;
size_t count = 0;
int res;
while ((res = scanf("%d", &the_number)) > 0) {
if (the_number >= A && the_number <= B)
count++;
}
printf("%zd numbers fitted in the range\n", count);
}
on this example you can give the program 1.0E26 numbers (assuming that you have an input file system large enough to hold a file this size) and your program will be able to handle it (you cannot create an array with capacity to hold 10^26 values)
I'm totally new here but I heard a lot about this site and now that I've been accepted for a 7 months software development 'bootcamp' I'm sharpening my C knowledge for an upcoming test.
I've been assigned a question on a test that I've passed already, but I did not finish that question and it bothers me quite a lot.
The question was a task to write a program in C that moves a character (char) array's cells by 1 to the left (it doesn't quite matter in which direction for me, but the question specified left). And I also took upon myself NOT to use a temporary array/stack or any other structure to hold the entire array data during execution.
So a 'string' or array of chars containing '0' '1' '2' 'A' 'B' 'C' will become
'1' '2' 'A' 'B' 'C' '0' after using the function once.
Writing this was no problem, I believe I ended up with something similar to:
void ArrayCharMoveLeft(char arr[], int arrsize, int times) {
int i;
for (i = 0; i <= arrsize ; i++) {
ArraySwap2CellsChar(arr, i, i+1);
}
}
As you can see the function is somewhat modular since it allows to input how many times the cells need to move or shift to the left. I did not implement it, but that was the idea.
As far as I know there are 3 ways to make this:
Loop ArrayCharMoveLeft times times. This feels instinctively inefficient.
Use recursion in ArrayCharMoveLeft. This should resemble the first solution, but I'm not 100% sure on how to implement this.
This is the way I'm trying to figure out: No loop within loop, no recursion, no temporary array, the program will know how to move the cells x times to the left/right without any issues.
The problem is that after swapping say N times of cells in the array, the remaining array size - times are sometimes not organized. For example:
Using ArrayCharMoveLeft with 3 as times with our given array mentioned above will yield
ABC021 instead of the expected value of ABC012.
I've run the following function for this:
int i;
char* lastcell;
if (!(times % arrsize))
{
printf("Nothing to move!\n");
return;
}
times = times % arrsize;
// Input checking. in case user inputs multiples of the array size, auto reduce to array size reminder
for (i = 0; i < arrsize-times; i++) {
printf("I = %d ", i);
PrintArray(arr, arrsize);
ArraySwap2CellsChar(arr, i, i+times);
}
As you can see the for runs from 0 to array size - times. If this function is used, say with an array containing 14 chars. Then using times = 5 will make the for run from 0 to 9, so cells 10 - 14 are NOT in order (but the rest are).
The worst thing about this is that the remaining cells always maintain the sequence, but at different position. Meaning instead of 0123 they could be 3012 or 2301... etc.
I've run different arrays on different times values and didn't find a particular pattern such as "if remaining cells = 3 then use ArrayCharMoveLeft on remaining cells with times = 1).
It always seem to be 1 out of 2 options: the remaining cells are in order, or shifted with different values. It seems to be something similar to this:
times shift+direction to allign
1 0
2 0
3 0
4 1R
5 3R
6 5R
7 3R
8 1R
the numbers change with different times and arrays. Anyone got an idea for this?
even if you use recursion or loops within loops, I'd like to hear a possible solution. Only firm rule for this is not to use a temporary array.
Thanks in advance!
If irrespective of efficiency or simplicity for the purpose of studying you want to use only exchanges of two array elements with ArraySwap2CellsChar, you can keep your loop with some adjustment. As you noted, the given for (i = 0; i < arrsize-times; i++) loop leaves the last times elements out of place. In order to correctly place all elements, the loop condition has to be i < arrsize-1 (one less suffices because if every element but the last is correct, the last one must be right, too). Of course when i runs nearly up to arrsize, i+times can't be kept as the other swap index; instead, the correct index j of the element which is to be put at index i has to be computed. This computation turns out somewhat tricky, due to the element having been swapped already from its original place. Here's a modified variant of your loop:
for (i = 0; i < arrsize-1; i++)
{
printf("i = %d ", i);
int j = i+times;
while (arrsize <= j) j %= arrsize, j += (i-j+times-1)/times*times;
printf("j = %d ", j);
PrintArray(arr, arrsize);
ArraySwap2CellsChar(arr, i, j);
}
Use standard library functions memcpy, memmove, etc as they are very optimized for your platform.
Use the correct type for sizes - size_t not int
char *ArrayCharMoveLeft(char *arr, const size_t arrsize, size_t ntimes)
{
ntimes %= arrsize;
if(ntimes)
{
char temp[ntimes];
memcpy(temp, arr, ntimes);
memmove(arr, arr + ntimes, arrsize - ntimes);
memcpy(arr + arrsize - ntimes, temp, ntimes);
}
return arr;
}
But you want it without the temporary array (more memory efficient, very bad performance-wise):
char *ArrayCharMoveLeft(char *arr, size_t arrsize, size_t ntimes)
{
ntimes %= arrsize;
while(ntimes--)
{
char temp = arr[0];
memmove(arr, arr + 1, arrsize - 1);
arr[arrsize -1] = temp;
}
return arr;
}
https://godbolt.org/z/od68dKTWq
https://godbolt.org/z/noah9zdYY
Disclaimer: I'm not sure if it's common to share a full working code here or not, since this is literally my first question asked here, so I'll refrain from doing so assuming the idea is answering specific questions, and not providing an example solution for grabs (which might defeat the purpose of studying and exploring C). This argument is backed by the fact that this specific task is derived from a programing test used by a programing course and it's purpose is to filter out applicants who aren't fit for intense 7 months training in software development. If you still wish to see my code, message me privately.
So, with a great amount of help from #Armali I'm happy to announce the question is answered! Together we came up with a function that takes an array of characters in C (string), and without using any previously written libraries (such as strings.h), or even a temporary array, it rotates all the cells in the array N times to the left.
Example: using ArrayCharMoveLeft() on the following array with N = 5:
Original array: 0123456789ABCDEF
Updated array: 56789ABCDEF01234
As you can see the first cell (0) is now the sixth cell (5), the 2nd cell is the 7th cell and so on. So each cell was moved to the left 5 times. The first 5 cells 'overflow' to the end of the array and now appear as the Last 5 cells, while maintaining their order.
The function works with various array lengths and N values.
This is not any sort of achievement, but rather an attempt to execute the task with as little variables as possible (only 4 ints, besides the char array, also counting the sub function used to swap the cells).
It was achieved using a nested loop so by no means its efficient runtime-wise, just memory wise, while still being self-coded functions, with no external libraries used (except stdio.h).
Refer to Armali's posted solution, it should get you the answer for this question.
I have an array of int (the length of the array can go from 11 to 500) and i need to extract, in another array, the largest ten numbers.
So, my starting code could be this:
arrayNumbers[n]; //array in input with numbers, 11<n<500
int arrayMax[10];
for (int i=0; i<n; i++){
if(arrayNumbers[i] ....
//here, i need the code to save current int in arrayMax correctly
}
//at the end of cycle, i want to have in arrayMax, the ten largest numbers (they haven't to be ordered)
What's the best efficient way to do this in C?
Study maxheap. Maintain a heap of size 10 and ignore all spilling elements. If you face a difficulty please ask.
EDIT:
If number of elements are less than 20, find n-10 smallest elements and rest if the numbers are top 10 numbers.
Visualize a heap here
EDIT2: Based on comment from Sleepy head, I searched and found this (I have not tested). You can find kth largest element (10 in this case) in )(n) time. Now in O(n) time, you can find first 10 elements which are greater than or equal to this kth largest number. Final complexity is linear.
Here is a algo which solves in linear time:
Use the selection algorithm, which effectively find the k-th element in a un-sorted array in linear time. You can either use a variant of quick sort or more robust algorithms.
Get the top k using the pivot got in step 1.
This is my idea:
insert first 10 elements of your arrayNum into arrMax.
Sort those 10 elements arrMax[0] = min , arrMax[9] = max.
then check the remaining elements one by one and insert every possible candidate into it's right position as follow (draft):
int k, r, p;
for (int k = 10; k < n; k++)
{
r = 0;
while(1)
{
if (arrMax[r] > arrNum[k]) break; // position to insert new comer
else if (r == 10) break; // don't exceed length of arrMax
else r++; // iteration
}
if (r != 0) // no need to insert number smaller than all members
{
for (p=0; p<r-1; p++) arrMax[p]=arrMax[p+1]; // shift arrMax to make space for new comer
arrMax[r-1] = arrNum[k]; // insert new comer at it's position
}
} // done!
Sort the array and insert Max 10 elements in another array
you can use the "select" algorithm which finds you the i-th largest number (you can put any number you like instead of i) and then iterate over the array and find the numbers that are bigger than i. in your case i=10 of course..
The following example can help you. it arranges the biggest 10 elements of the original array into arrMax assuming you have all positive numbers in the original array arrNum. Based on this you can work for negative numbers also by initializing all elements of the arrMax with possible smallest number.
Anyway, using a heap of 10 elements is a better solution rather than this one.
void main()
{
int arrNum[500]={1,2,3,21,34,4,5,6,7,87,8,9,10,11,12,13,14,15,16,17,18,19,20};
int arrMax[10]={0};
int i,cur,j,nn=23,pos;
clrscr();
for(cur=0;cur<nn;cur++)
{
for(pos=9;pos>=0;pos--)
if(arrMax[pos]<arrNum[cur])
break;
for(j=1;j<=pos;j++)
arrMax[j-1]=arrMax[j];
if(pos>=0)
arrMax[pos]=arrNum[cur];
}
for(i=0;i<10;i++)
printf("%d ",arrMax[i]);
getch();
}
When improving efficiency of an algorithm, it is often best (and instructive) to start with a naive implementation and improve it. Since in your question you obviously don't even have that, efficiency is perhaps a moot point.
If you start with the simpler question of how to find the largest integer:
Initialise largest_found to INT_MIN
Iterate the array with :
IF value > largest_found THEN largest_found = value
To get the 10 largest, you perform the same algorithm 10 times, but retaining the last_largest and its index from the previous iteration, modify the largest_found test thus:
IF value > largest_found &&
value <= last_largest_found &&
index != last_largest_index
THEN
largest_found = last_largest_found = value
last_largest_index = index
Start with that, then ask yourself (or here) about efficiency.
I am currently working on a project for my algorithms class and am at a bit of a standstill. We were assigned to do improvements to merge sort, that was in the book, by implementing specific changes. I have worked fine through the first 2 changes but the 3'rd one is killer.
Merge sort, the one we are improving, copies the contents of the input array into the temporary array, and then copies the temporary array back into the input array. So it recursively sorts the input array, placing the two sorted halves into the temporary array. And then it merges the two halves in the temporary array together, placing the sorted sequence into the input array as it goes.
The improvement is that this double copying is wasteful can be done without. His hint is that: We can make it so that each call to Merge only copies in one direction, but the calls to Merge alternate the direction.
This is supposedly done by blurring the lines between the original and temporary array.
I am not really looking for code as I am confident that I can code this. I just have no idea what i'm supposed to be doing. The professor is gone for the day so I can't ask him until next week when I have his course again.
Has anyone done something like this before? Or can decipher and put it into laymans terms for me :P
The first improvement, simply has it use insertion sort whenever an Array gets small enough that it will benefit greatly, timewise, from doing so.
The second improvement stops allocating two dynamic arrays (the 2 halves that are sorted) and instead allocates 1 array of size n and that is what is used instead of the two dynamic arrays. That's that last one I did. The code for that is :
//#include "InsertionSort.h"
#define INSERTION_CUTOFF 250
#include <limits.h> // needed for INT_MAX (the sentinel)
void merge3(int* inputArray, int p, int q, int r, int* tempArray)
{
int i,j,k;
for (i = p; i <= r; i++)
{
tempArray[i] = inputArray[i];
}
i = p;
j = q+1;
k = p;
while (i <= q && j <= r)
{
if (tempArray[i] <= tempArray[j])
{
inputArray[k++] = tempArray[i++];
}
else
{
inputArray[k++] = tempArray[j++];
}
}
}//merge3()
void mergeSort3Helper(int* inputArray, int p, int r, int* tempArray)
{
if (r - p < INSERTION_CUTOFF)
{
insertionSort(inputArray,p,r);
return;
}
int q = (p+r-1)/2;
mergeSort3Helper(inputArray,p,q,tempArray);
mergeSort3Helper(inputArray,q+1,r,tempArray);
merge3(inputArray,p,q,r,tempArray);
}//mergeSort3Helper()
void mergeSort3(int* inputArray, int p, int r)
{
if (r-p < 1)
{
return;
}
if (r - p < INSERTION_CUTOFF)
{
insertionSort(inputArray,p,r);
return;
}
int* tempArray = malloc((r-p)+1*sizeof(int));
tempArray[r+1] = INT_MAX;
mergeSort3Helper(inputArray,p,r,tempArray);
// This version of merge sort should allocate all the extra space
// needed for merging just once, at the very beginning, instead of
// within each call to merge3().
}//mergeSort3()
The algorithm is like this:
A1: 7 0 2 9 5 1 4 3
A2: (uninitialized)
Step 1:
A1 : unchanged
A2: 0 7 2 9 1 5 3 4
Step 2:
A1: 0 2 7 9 1 3 4 5
A2: unchanged
Step 3:
A1: unchanged
A2: 0 1 2 3 4 5 7 9
This involves you copying only one way each time and follows the steps of mergesort. As your professor said, you blur the lines between the work array and the sorted array by alternating which is which, and only copying once things are sorted.
I suspect it would be difficult and ultimately unprofitable to avoid all copying. What you want to do instead is to avoid the copy you currently do with each merge.
Your current merge3(inputArray, p,q,r, tempArray) returns the merged result in its original array, which requires a copy; it uses its tempArray buffer only as a resource. In order to do better, you need to modify it to something like merge4(inputArray, p,q,r, outputArray), where the result is returned in the second buffer, not the first.
You will need to change the logic in mergeSort3Helper() to deal with this. One approach requires a comparable interface change, to mergeSort4Helper(inputArray, p,q,r, outputArray), such that it also yields its result in its second buffer. This will require a copy at the lowest (insertion sort) level, and a second copy in the top-level mergeSort4() if you want your final result in the same buffer it came in. However, it eliminates all other unnecessary copies.
Alternately, you could add a boolean parameter to mergeSort4Helper() to indicate whether you want the result returned in the first or second buffer. This value would alternate recursively, resulting in at most one copy, at the lowest level.
A final option might be to do the merging non-recursively, and alternate buffers at each pass. This would also result in at most one copy; however, I would expect the resulting access pattern to be inherently less cache-friendly than the recursive one.
If you have an array of integers, such as 1 2 5 4 3 2 1 5 9
What is the best way in C, to remove cycles of integers from an array.
i.e. above, 1-2-5-4-3-2-1 is a cycle and should be removed to be left with just 1 5 9.
How can I do this?
Thanks!!
A straight forward search in an array could look like this:
int arr[] = {1, 2, 5, 4, 3, 2, 1, 5, 9};
int len = 9;
int i, j;
for (i = 0; i < len; i++) {
for (j = 0; j < i; j++) {
if (arr[i] == arr[j]) {
// remove elements between i and j
memmove(&arr[j], &arr[i], (len-i)*sizeof(int));
len -= i-j;
i = j;
break;
}
}
}
Build a graph and select edges based on running depth first search on it.
Mark vertices when you visit them, add edges as you traverse graph, don't add edges that have already been selected - they would connect previously visited components and therefore create a cycle.
From the array in your example we can't tell what is considered a cycle.
In your example both 2 -> 5 and 1 -> 5 as well as 1 -> 2 so in graph (?):
1 -> 2
| |
| V
+--> 5
So where is the information of which elements are connected?
There is a simple way, with O(n^2) complexity: simply iterate over each array entry from the beginning, and search the array for the last identical value. If that is in the same position as your current position, move on. Otherwise, delete the sequence (except for the initial value) and move on. You should be able to implement this using two nested for loops plus a conditional memcpy.
There is a more complex way, with O(n log n) complexity. If your data set is large, this one will be preferable for performance, though it is more complex to implement and therefore more error-prone.
1) Sort the array - this is the O(n log n) part if you use a good sorting algorithm. Do so by reference - you want to keep the original. This moves all identical values together. Break sort-order ties by position in the original array, this will help in the next step.
2) Iterate once over the sorted array (O(n)), looking for runs of the same value. Because these runs are themselves sorted by position, you can trivially find each cycle involving that value by comparing adjacent pairs for equality. Erase (not delete) each cycle from the original array by replacing each value except the last with a sentinel (zero might work). Don't close the gaps yet, or the references will break.
NB: At this stage you need to ignore any endpoints that have already been erased from the array. Because they will resolve to sentinels, you simply have to be careful to not erase "runs" that involve the sentinel value at either end.
3) Throw away the sorted array, and use the sentinels to close the gaps in the original array. This should be O(n).
Actually implementing this in any given language is left as an exercise for the reader. :-)