I left out main but basically this should sort 8 elements but when I compile it, it says:
prelab3.c: In function ‘sort’:
prelab3.c:77: error: invalid operands to binary > (have ‘DynamicArray’ and ‘DynamicArray’)
and I'm not sure why exactly, can you not compare things in a struct using pointers?
Code below:
typedef struct Array_
{
int data;
}DynamicArray;
void sort(DynamicArray *v, unsigned int size)
{
int i, j;
int min;
DynamicArray temp;
for (i=0; i<size-1; i++)
{
min = i;
for(j=i+1; j<size; j++)
{
if(*(v+i) > *(v+j))
{
min = j;
}
}
if(min != i)
{
temp = *v;
*v = *(v+min);
*(v+min) = temp;
}
}
}
Comparing structs is meaningless but you could compare the integers inside them. Try this:
(v+i)->data > (v+j)->data
As #David said, you can't compare structs. Your algorithm have some mistakes too:
The j loop is intended to find the minimum item in the range [i,size), so your comparison must be against the minimum so far found:
(v+min)->data > (v+j)->data
I recommend you to use the array notation, in my opinion is clearer:
v[min].data > v[j].data
The last part (after the min != i comparison) is intended to exchange the values between the min and i positions, so your code should look something like:
temp = v[i];
v[i] = v[min];
v[min] = temp;
Finally, keep in mind that struct assignment not always work, for more complex structs than yours, you might need to use field by field assignment, or memcpy().
Related
I am trying to implement a Left shift/ Right Shift on arrays.
I was able to accomplish this using double loops.
Can I get some help to improve the efficiency?
This is the working code for LeftShift/RightShift which is using 2 loops.
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
struct Array
{
int A[10];
int size;
int length;
};
void Display(struct Array arr)
{
printf("\nElements are : \n");
for(int i = 0;i<arr.length;i++)
printf("%d ", arr.A[i]);
}
// Left Shift-------------------------------------------------------------------------------------------------------
void LeftShift1(struct Array *arr, int n) //n is the number of shifts
{
int temp = arr->A[0];
for(int i=0; i<n; i++)
{
for(int j=0; j<arr->length-1; j++)
{
arr->A[j] = arr->A[j+1];
}
arr->A[arr->length-1] = 0;
}
}
//Right Shift-------------------------------------------------------------------------------------------------------
void RightShift(struct Array *arr, int n) //n is the number of shifts
{
for(int i = 0; i<n; i++)
{
for(int j=arr->length-1; j>0; j--)
{
arr->A[j] = arr->A[j-1];
}
arr->A[0] = 0;
}
}
int main()
{
struct Array arr={{1,2,3,4,5},10,5};
LeftShift1(&arr, 2);
//RightShift(&arr, 1);
Display(arr);
return 0;
}
I'm trying something like this which uses 2 iterators to solve this problem!
This is also working!
void LeftShift2(struct Array *arr, int n)
{
for(int k=0; k<n; k++)
{
int i,j;
for(i=0, j=0; j<arr->length-1; i++, j++)
{
arr->A[j] = arr->A[j+1];
}
arr->A[arr->length-1] = 0;
}
}
But can this be solved without loops? OR with a single loop?
Can this be made more efficient?
some help to improve the efficiency?
Shift: Shift once. Go from O(n*length) to O(length).
Rotate: Shift once into a temporary. Go from O(n*length) to O(length).
Qualify n first.
void LeftShift_alt(struct Array *arr, int n) {
if (n > arr->length) {
n = arr->length;
}
memmove(&arr->A[0], &arr->A[n], (arr->length - n)*sizeof arr->A[0]);
memset(&arr->A[arr->length - n], 0, n * sizeof arr->A[0]);
}
void LeftRotate_alt(struct Array *arr, int n) {
if (arr->length > 0) {
n %= arr->length;
if (n > 0) {
int temp[n];
memcpy(temp, arr->A, sizeof temp);
memmove(arr->A, arr->A + n, sizeof arr->A[0] * (arr->length - n));
memcpy(arr->A + n, temp, sizeof temp);
}
}
}
Replace mem...() with pointer code if desired.
Rather than actually moving the contents of the array around, you could provide all the common accessor operators (<<, >>, [], etc.) in the struct. (Assuming you're using a compiler that supports this. Otherwise, you'll need to create these functions C-style.) If someone did this:
my_array <<= 5;
my_array >>= 2;
...you'd simply keep track of how much the array has been shifted. In this case, they've shifted a total of 3 positions to the left. When someone indexes into the array, you add the accumulated offset to their index (modulo the size of the array) to get the actual location of the entry they're looking for. This makes shifts O(1) instead of O(n). If you're looking for an efficient solution, this is about as good as it gets.
After CODE REVIEW:
In C, efficiency can be improved by using a single loop. Instead of shifting elements one position at a time we can move them n positions!
Something like this:
void LeftShift1(struct Array* arr, unsigned int n) {
if (n > arr->length) {
n = arr->length;
}
for (unsigned int i = 0; i < arr->length; i++) {
if (i + n < arr->length)
arr->A[i] = arr->A[i + n];
else
arr->A[i] = 0;
}
}
In practical usage, we would want to consider doing this array shifting with element types other than a plain int. In fact, it may be a complex type like a string and we should not do raw memcpy on string.
In my code, I was setting the shifted-out elements to 0 which was OK for an integer and related types, but it won't work similarly in string.
As of C++20, there is a standard std::shift_left and std::shift_right ready to use.
There also exists std::rotate which can be used to rotate the elements.
int arr[] = {1,2,3,4,5};
using std::ranges::begin;
using std::ranges::end;
std::shift_left (begin(arr),end(arr),2);
Display(arr);
Also in C++, we should use flexible container like vector in place of struct!
Also If we are doing a lot of adding and removing elements from both ends then there is a container specifically designed for that called deque ("doubly ended queue").
I have coded out a Bubble Function that is supposed to Bubble sort an array of user input integers, but for some reason, my array is only working with arrays with size 6... otherwise the array outputs a zero for the largest number. Please run this code and help me identify the problem.
#include <stdio.h>
//prototype
void bubble(int array[], int size);
int main(void)
{
int n,i,j,size,temp,counter = 0;
//FOR SOME REASON, ONLY INPUT SIZE 6 WORKS PERFECTLY.
int k;
printf("How many numbers to sort?\n");
scanf("%d",&size);
int array[size];
for(i=0;i<size;i++)
{
printf("Enter number %d\n",i+1);
scanf("%d",&k);
array[i] = k;
}
printf("Array before sorting:\n");
for(i=0;i<size;i++)
{
printf("%d ",array[i]);
}
bubble(array,size);
return 0;
}
// use this if you want to test print an array
// for(i=0;i<size;i++)
// {
// printf("%d",array[i]);
// }
void bubble(int array[], int size)
{
int i, j, temp;
for(j=0;j<size;j++)
{
printf("\nIteration# %d\n",j+1);
for(i=0;i<size;i++)
{
if(array[i] > array[i+1])
{
temp = array[i];
array[i] = array[i+1];
array[i+1] = temp;
}
printf("%4d",array[i]);
}
}
}
// void select(int array[], int size)
// {
// int i, j, temp;
// min = array[0];
// for(j=0;j<size;j++)
// {
// if(array[j] < min)
// {
// array[j] = temp;
// min = array[j];
// }
// }
// }
Your inner-loop top-end conditional break is size, but within the loop you reference array[i+1], which means you're referring to array[size]. Since C arrays are zero-base indexed, the only allowable indexing is from 0...(size-1). Your code breaches that by one item repeatedly.
Changing the top-end of the inner loop to size-1 will work in your case. but there is arguably a better alternative that alleviates you from remembering the minus-1 in the first place. It involves modifying size as you sort to control the top-end of your inner loop directly. It also eliminates one local variable that you no longer need).
void bubble(int array[], int size)
{
while (size-- > 0)
{
for(int i=0; i<size; ++i)
{
if(array[i] > array[i+1])
{
int temp = array[i];
array[i] = array[i+1];
array[i+1] = temp;
}
}
}
}
Often called a "goes-down-to" expression (because it looks like a long arrow pointing at a limiting value), the outer loop has been changed to become while (size-- > 0). This takes the current value of size to a temporary, decrements size, and compares the temporary against > 0 (more or less). The result is size now reflects the top limit of your inner loop that you want. Each enumeration of the outer loop will shrink the next inner loop pass by one. The point of bubble sort is that, once an element has been "bubbled up" to its proper position, you need not visit that element ever again, something your code is not taking advantage of.
Bonus Optimization
Finally, you can optimize this further and give your bubblesort the one and only redeeming quality the algorithm can offer: O(n) in best case where the sequence is already sorted. You do this by doing "swap-detection". If you ever pass over the inner loop without making a single swap, it makes no sense to perform anymore sorting. The sequence is sorted and you're done. It's a near-freebie addition to the original algorithm above, and looks like this:
void bubble(int array[], int size)
{
int swapped = 1;
while (swapped && size-- > 0)
{
swapped = 0;
for(int i=0; i<size; ++i)
{
if(array[i] > array[i+1])
{
int temp = array[i];
array[i] = array[i+1];
array[i+1] = temp;
swapped = 1;
}
}
}
}
Given an already sorted sequence of a ten, a hundred, or a hundred-thousand elements, this will finish after only one pass. Worth noting: even one element out of position on one extreme end will make this optimization irrelevant. I.e. if any element that belongs near the beginning is originally near the end, it will take up to size iterations to bring it home, and with that the optimization becomes moot. In short, this sequence
1 3 4 5... 9998 9999 2
will completely foil the optimization above. There are techniques to combat this as well including a two pass inner loop enumeration, where you ascend to bubble up larger values, then reverse direction to descend, bubbling down smaller values. but at this point you're better off using a finer algorithm like quicksort or heapsort. The discussion of that, and indeed the latter half of this post, is beyond the scope of your question.
i<size in combination with i+1 will go past the bounds of the array.
You should replace this:
for(i=0;i<size;i++)
with this:
for(i=0;i<size-1;i++)
in order to sort an array in ascending order, i thought of the following:
#define SIZE 10 //as an example
void swapValues(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = temp;
}
void sort(int *array)
{
int i, j;
for(i = 0; i < SIZE-1; i++) {
for(j = i + 1; j < SIZE; j++) {
if(array[i] > array[j]) {
swapValues( (array+i) , (array+j) );
}
}
}
}
the function works, but after taking a look on
this, i'm a bit curious, this looks like a bubble sort algorithm, but it isn't, so:
is this function an implementation of an already known sorting algorithm?
how would this function fare in comparison to other simple sorting algorithms like bubble sort or selection sort?
Your implementation is using selection sort. It's not bubble sort. Since in bubble sort we compare two consecutive elements at once, therefore this isn't it. This is selection sort where in you compare one element with the rest of elements at a time in an array, and swap accordingly.
I'm creating a map with n * m dimensions, that should be gotten from a file input. Each position of the map matters for distance counting. In the whole execution cycle I go through 4 malloc() calls, however I can't match them with 4 free() calls or the execution might or might not finish and I can't understand why.
Here's the main call:
int main()
{
map_t newMap;
newMap = map_create(30, 30);
//there's some test calls that I'm ommiting as they simply work and don't matter
map_destroy(newMap);
return 0;
}
the map_t as I understand and as I want is a pointer to a structure, it's defined on a header file as following:
typedef struct map *map_t;
it's implementation is on the corresponding .c file for matters of encapsulation. Here's the implementation and the important functions for the case:
struct map{
position_t **positions;
int lines, columns;
};
map_t map_create(int n, int m)
{
map_t newMap = malloc(sizeof(map_t));
newMap->lines = n;
newMap->columns = m;
newMap->positions = malloc(n * sizeof(position_t*));
int i;
int k;
for(i = 0; i < n; ++i)
{
newMap->positions[i] = malloc(m * sizeof(position_t));
for(k = 0; k < m; ++k)
{
newMap->positions[i][k] = position_create();
}
}
return newMap;
}
void map_destroy(map_t map_p)
{
int i, k;
int n = map_p->lines;
int m = map_p->columns;
for(i=0; i < n; ++i)
{
for(k=0; k < m; ++k)
{
position_destroy(map_p->positions[i][k]);
}
free(map_p->positions[i]);
}
free(map_p->positions);
free(map_p);
}
For matters of completeness, here's the position struct specific code, it follows the same idea of the map struct.
typedef struct position *position_t; //this is on the .h, the rest is on the .c file
struct position{
int has_treasure;
int times_visited;
};
position_t position_create()
{
position_t newPosition = malloc(sizeof *newPosition);
newPosition->has_treasure = YES;
newPosition->times_visited = 0;
return newPosition;
}
void position_destroy(position_t position_p)
{
free(position_p);
}
I've identified which free calls are causing the problem, I just can't understand why. If I comment these 2 lines:
free(map_p->positions);
free(map_p);
everything works fine. I've seen different ways to allocate the initial memory such as this one - How do I correctly set up, access, and free a multidimensional array in C? - but even with the various solutions found there I keep getting the same unstability.
It might be extremely simple and I'm just overlooking something, been on this for 5 days now, as much I hate to borrow anyone's time on this mess, even if I have to implement a different solution I'd like to at least understand what's wrong.
Code isn't producing any warnings with -Wall -g -c and if I add -pedantic I just get complaints about comments.
Cheers in advance
EDIT: Changed position_t newPosition = malloc(sizeof(position_t)); to position_t newPosition = malloc(sizeof *newPosition);
behaviour is still the same
EDIT2: did the exact type of change on the map_t malloc, problem solved, the whole time I thought the problem was on the **positions
The first malloc(sizeof(map_t)); allocates only space for a pointer. You need to use malloc(sizeof(*map_t));.
But you already found that now, I see.
I have a structure consisting of two elements char *word and int number. When I want to sort them using bubble sort, I have to write exchange parts for both of them:
int i,j,tmp;
char * temp;
for(i=0; i<max;i++)
{
for(j=0;j<max-i;j++)
{
if(strcmp(array[j].word,array[j+1].word)>0)
{
temp=array[j].word;
array[j].word=array[j+1].word;
array[j+1].word=temp;
tmp=array[j].number;
array[j].number=array[j+1].number;
array[j+1].number=tmp;
}
}
}
EDIT My struct declaration
typedef struct{
char *word;
int number;
}
words;
words *array=NULL;
What if I had n elements in the array ? That would be very time consuming to exchange everything. Is there any way to omit this?
OF COURSE except for other sorting algorithms, which I don't want to use (like qsort).
If your concern is with the performance in the swapping process, you should consider and array of pointers of type the struct you are using:
struct your_stuct *arr[MAX];
If you set correctly this array, the swap will change only the memory addresses rather than the struct contents and it could run faster:
Within your inner loop you should use:
struct your_struct *temp;
temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
Is this what you mean in your question?
Rather than sorting the structs themselves, create an array of pointers to the structs, and an appropriate comparison function that reads the appropriate values from the struct through the pointer, and sort the list of pointers. Of course, all the extra indirections may mask any performance gain you get from not actually swapping the structs around, since your structs are fairly small, but for large structs, this approach makes a lot of sense.
int i, j, tmp;
words temp;
for (i = 0; i < max; i++)
{
for (j = 0; j < max - i; j++)
{
if (strcmp(array[j].word, array[j + 1].word) > 0)
{
memcpy(&temp, array[j], sizeof(words));
memcpy(array[j], array[j + 1], sizeof(words));
memcpy(array[j + 1], &temp, sizeof(words));
}
}
}