Delete one element from a struct [duplicate] - c

I have an array of structs (actually it's a heap array sorted by priority).
typedef struct {
char name[MAX_CHARACTERS+1];
int priority;
} person;
person p[MAX_HEAPSIZE+1];
and want to remove the first element in the array. I'm not sure how or what command to use.
So far, I've been doing
void remove(){
swap(0, heapsize-1);
strcpy(p[heapsize-1].name, p[MAX_HEAP_SIZE+1].name);
p[heapsize-1].priority = p[MAX_HEAP_SIZE+1].priority;
}
this swaps the first and last non-empty element in the array. Then it tries to copy the data at an empty element to the last non-empty element (element i want to remove) in the array.
but I think it only copies the memory positions. Is there something simple where I can do
p[0] = NULL?

An array is a continuous block of memory. So if you want to remove the first element, you have to move all the following elements towards the beginning by one element:
void remove(void)
{
memmove(&p[0], &p[1], (MAX_HEAPSIZE - 1) * sizeof(person));
}
This is pretty inefficient. Popping the first element is a common operation with a heap, so you'd usually do it the other way around - remove the last element of an array - which is very fast, because the other elements of the array aren't affected.
void remove(void)
{
heapsize--;
}
heapsize can then be used as the index of the top element of the heap (assuming you preserve the heap property, of course).
If you want to overwrite the first element of the array with the last one and zero out the memory of the last element, which is not used anymore, you can use memcpy and memset:
void remove(void)
{
memcpy(&p[0], &p[heapsize - 1], sizeof(person));
memset(&p[heapsize - 1], 0x00, sizeof(person));
}
Zeroing out the memory of the last element is not strictly necessary, though, because you shouldn't be accessing it in the first place. Instead of overwriting the first element with the last using memcpy, it can also be done with strcpy and assignment of the priority (like in your remove); using memcpy is simply easier.

It sounds like you are trying to implement a heap sort. You don't actually need to "remove" the first element of the heap, or even the last one.
Instead, the algorithm is to copy the values from the the first element (the element with the highest priority) for output, then to copy the node from the "end" of the array to the first position in preparation to bubble it down into the correct position. The "end" of the array is indicated by the current heap_size.
To "remove" the last item of the array, just reduce the heap_size by 1.
I vaguely recall that the bubbling down is accomplished by checking the priorities of the children on the moving item, and then swapping it with the one with the highest priority. Repeat this on the moved item until the item is of equal or higher priority to its children.
The trick to find the children of an item is easy: they are the nodes at 2*i and 2*i+1, where the array starts at 1 instead of 0. (Would it be 2*(i+1)-1 and 2*(1+1) for 0-based arrays? Check my math, please. Or just waste one element of the array to keep the math simple.)

Related

How to write shift_elements function in C?

I have this question in C language:
Implement the function: shift_element(int * arr, int i).
The function will get a pointer (not necessarily the beginning of the array) and the function will move the i next values to the right. Note that the function assumes that there is memory for at least i+1 cells after the pointer of the array.
Isn't it a swap function that I can use in Insertion sort? I don't understand the question properly. Thanks.
You can use memcpy:
void shift_element(int * arr, int i)
{
// moves i bytes from arr to arr + 1
memcpy(arr + 1, arr, i);
}
Description from the manual:
The memcpy() function copies n bytes from memory area src to memory
area dest. The memory areas must not overlap. Use memmove(3) if the
memory areas do overlap.
If you are to shift your elements, you don't actually need to sort them, nor even to swap a couple of them neither. As you said, you just need to move each element to the next place.
A regular loop should be enough, in which you'll simply do arr[index+1] = arr[index] but be careful to walk from right to left (having a loop starting from i and descending to 0), or you will clobber the elements you're about to move.
Please note that in most programming languages, a "shift" function generally does the opposite : shifting all elements to the left, returning the one at top of the list, then discarding it.

Write an algorithm printing the removed element from head of a linked list in an array?

First of all this is an assignment. I'm not asking for any code just clarification.
I don't really understand the question, does it mean to put the removed element in an array and print it right away when you call the method removing the head element meaning every time I print 1 element and the array capacity is always 1? or you create an array as a class member and each time you remove an element it is put in the array and then have a method for printing the array? if so how do you deal with the array capacity since linked lists are not fixed sized?
My own solution is to create a static arraylist and each time I call deleteFirst() method, the data inside the node is put in the arraylist and then I just have a method printing the arraylist, to me this seems like a logical solution but I'm restricted to using arrays.
deleteFirst() deletes the head node in the linked list.
Since this is your assignment, you could do something like arrayList does with System.arraycopy method:
MyElementType[] elementArray = new MyElementType[10];
.....
element = deleteFirst();
if (!doWeHaveEmptyLocationInArray()) {
MyElementType[] tempElementArray = new MyElementType[elementArray.length() * 2];//double the size of array
System.arraycopy(elementArray, 0, tempElementArray, 0, elementArray.lengh());//copy elements from old array to new one
elementArray = tempElementArray;
}
...add the removed element to new array

Arranging elements in C array so there are no gaps

I have a regular array of structs in C, in a program that runs every second and updates all the data in the structs. When a condition is met, one of the elements gets cleared and is used as a free slot for new element (in this case timers) that might come in at any point.
What I do is just to parse all the elements of the array looking for active elements requiring updates. But even if the amount of elements is small (<2000), I feel this is wasting time going through the inactive ones. Is there a way I can keep the array gap-free so I just need to iterate though the number of currently allocated elements?
Assuming the specific order of the elements does not matter, it can be done very easily.
If you have your array A and the number of active elements N, you can then add an element E like this:
A[N++] = E;
and remove the element at index I like this:
A[I] = A[--N];
So how does this work? Well, it's fairly simple. We want the array to only store active elements, so we may assume that the array is like that when we start doing either of these things.
Adding an element will always put it at the end, and since all elements currently in the array, as well as the newly added element, will be active, we can safely add one to the end.
Removing an element is done by moving the last element to take over the array index of the element we want to remove. Thus, A[0..I-1] is active, as well as A[I+1..N], and by moving A[N] to A[I], the entire range A[0..N-1] is active (A[N] is not active, because it no longer exists - we moved it to A[I], and that's why we decrease N by 1).
If you're removing elements while iterating over them to update them, note that you can only increment your loop counter after processing an element which doesn't get removed, since otherwise, you would never process the moved elements.
Traversing 2,000 entries per second is negligible. It's really not worth optimizing. If you really feel you must, swap the inactive entry for the last active entry.
It doesn't sound like you have a great reason for not using a linked list. If you do the implementation well, you'll get O(1) inserts, O(1) removals and you'll only ever need to keep (and iterate over)active structs. There'd be some memory overhead... for even moderately sized structs, though, even a doubly-linked list would be pretty efficient. The nice thing about this approach is that you can keep elements in their insertion order without extra computational overhead.
A relatively simple way to accomplish this:
void remove(struct foo *foo_array, int *n)
{
struct foo *src = foo_array, *dst = foo_array;
int num_removed = 0;
for (int i=0; i<*n; ++i)
{
// Do we want to remove this? (should_remove() left as exercise for reader.)
if (should_remove(src))
{
// yes, remove; advance src without advancing dst
++src;
++num_removed;
}
else if (src != dst)
{
// advance src and dst (with copy)
*dst++ = *src++;
}
else
{
// advance both pointers (no copy)
++src;
++dst;
}
}
// update size of array
*n -= num_removed;
}
The idea is that you keep track of how many elements of the array are valid (*n here), and pass its pointer as an "in/out parameter". remove() decides which elements to remove and copies the ones that are out of place. Notice that this is O(n) regardless of how many elements are decided to be removed.
A few alternatives come to mind, choose according to your needs:
1) Leave it as it is unless you are having some performance issues or need to scale up.
2) Add a "next" pointer to each struct to use it as an element in a doubly linked list. Keep two lists, one for the active ones and one for the unused ones. Depending on how you use the struts, also consider making the list doubly linked. (You can also still have the elements in an array if you need to index the structs, or you can stop using the array if not.)
3) If you don't need indices (or order) of the structs in the array to be constant, move unused entries to the end of the array. Then when you iterate through the array from the beginning, you can stop whenever you reach the first unused one. (You can store the index of the last active struct so that whenever a struct is deactivated you can just have it switch places with the last active one, and then decrement the index of the last active struct.)
How about adding a linked list behavior in your struct, i.e. a pointer member pointing to the next active element?
You would have to update these pointers on element activation and deactivation.
EDIT: This method is not suitable for dynamically resized arrays, because that may change the memory object's address, invalidating the pointers used by the list..

Beginner Removing first element from an array of structs (C)

I have an array of structs (actually it's a heap array sorted by priority).
typedef struct {
char name[MAX_CHARACTERS+1];
int priority;
} person;
person p[MAX_HEAPSIZE+1];
and want to remove the first element in the array. I'm not sure how or what command to use.
So far, I've been doing
void remove(){
swap(0, heapsize-1);
strcpy(p[heapsize-1].name, p[MAX_HEAP_SIZE+1].name);
p[heapsize-1].priority = p[MAX_HEAP_SIZE+1].priority;
}
this swaps the first and last non-empty element in the array. Then it tries to copy the data at an empty element to the last non-empty element (element i want to remove) in the array.
but I think it only copies the memory positions. Is there something simple where I can do
p[0] = NULL?
An array is a continuous block of memory. So if you want to remove the first element, you have to move all the following elements towards the beginning by one element:
void remove(void)
{
memmove(&p[0], &p[1], (MAX_HEAPSIZE - 1) * sizeof(person));
}
This is pretty inefficient. Popping the first element is a common operation with a heap, so you'd usually do it the other way around - remove the last element of an array - which is very fast, because the other elements of the array aren't affected.
void remove(void)
{
heapsize--;
}
heapsize can then be used as the index of the top element of the heap (assuming you preserve the heap property, of course).
If you want to overwrite the first element of the array with the last one and zero out the memory of the last element, which is not used anymore, you can use memcpy and memset:
void remove(void)
{
memcpy(&p[0], &p[heapsize - 1], sizeof(person));
memset(&p[heapsize - 1], 0x00, sizeof(person));
}
Zeroing out the memory of the last element is not strictly necessary, though, because you shouldn't be accessing it in the first place. Instead of overwriting the first element with the last using memcpy, it can also be done with strcpy and assignment of the priority (like in your remove); using memcpy is simply easier.
It sounds like you are trying to implement a heap sort. You don't actually need to "remove" the first element of the heap, or even the last one.
Instead, the algorithm is to copy the values from the the first element (the element with the highest priority) for output, then to copy the node from the "end" of the array to the first position in preparation to bubble it down into the correct position. The "end" of the array is indicated by the current heap_size.
To "remove" the last item of the array, just reduce the heap_size by 1.
I vaguely recall that the bubbling down is accomplished by checking the priorities of the children on the moving item, and then swapping it with the one with the highest priority. Repeat this on the moved item until the item is of equal or higher priority to its children.
The trick to find the children of an item is easy: they are the nodes at 2*i and 2*i+1, where the array starts at 1 instead of 0. (Would it be 2*(i+1)-1 and 2*(1+1) for 0-based arrays? Check my math, please. Or just waste one element of the array to keep the math simple.)

In C, is it possible do free only an array first or last position?

I've an array, but I don't need its first (or last) position. So I point a new variable to the rest of the array, but I should free the array first/last position. For instance:
p = read_csv_file();
q = p + 1; // I don't need the first CSV file field
// Here I'd like to free only the first position of p
return q;
Otherwise I've to memcpy the array to other variable, excluding the first position, and then free the original array. Like this:
p = read_csv_file();
q = (int*) malloc(sizeof(int) * (SOME_SIZE - 1));
memcpy(q, p+1, sizeof(int) * (SOME_SIZE - 1));
free(p);
return q;
But then I'll have the overhead of copying all the array.
Is this possible to only free a single position of an array?
No. You can only free() a complete block obtained from a call to malloc() (or one of malloc()'s friends), not a piece of that block.
Your best bet is probably to leave the allocated block as-is and just use a pointer to the element at index one as if it were the beginning of the array (and ignore the last element).
Using memcpy works if it is really that important to free the two elements.
You could also shift all of the elements to the left by one (i.e., move the element at index one to index zero and so forth) and then call realloc() to resize the block and remove the last two elements. This isn't really a good idea, though, because the most likely outcome is that either (a) the underlying heap allocation won't actually be resized and you'll have moved thing around and gotten no benefit, or (b) the underlying heap allocation will be resized and everything will get moved a second time.
That is what realloc(3) is for. For releasing the first array element I'd suggest revising the algorithm.

Resources