Lets say I have an array of pointers to some object.
foo* bar[256];
and lets say it contains a list of all the blitted(blitting) textures to my buffer. I then request to take something off the array via deletion, and the thing I am taking off is NOT at the end, right. So there is an empty sort of gap in the array
(filled memory), (empty), (filled memory), (filled memory), etc
While I guess in this example it doesn't really matter, but how would I take every entry in the array that is ahead of the empty space and sort of press it back so the empty space is on the end?
Sorry about the poor wording, friends!
Shifting all the items takes time. If the order of the items doesnt matter I suggest shift only the last item to fill the gap and hold a size int to specify the occupied size.
You should hold it in a struct
typedef struct{
int occupied;
foo* bar[256];
}
lets say we want to delete the k'th cell:
delete(myStruct.bar[k]);
myStruct.bar[k] = myStruct.bar[myStruct.occupied--];
Let's say for example, that you know bar[128] is empty.
The following loop will shift all the elements after bar[128] to the left by one, and thus leave the empty space at the end:
for (int k = 129; k < 128; k++) {
bar[k-1] = bar[k];
}
It is definitely possible to generalize this to more than one gap in your array, but that becomes a little bit more complicated.
int i, j;
for (i=0; i<256; i++) {
if (!(bar[i])) {
for (j=i; j<255; j++) {
bar[j] = bar[j+1];
}
}
}
There is no other way to do that than going through each element in the array that'S above the gap and sort it. If this happens very often, it can become a performance issue. Maybe you should try another data structure, like a linked list. There each element has a pointer to it's next element. Now when you remove one element in the middle of the list, you just have to point the element before the removed one to the element that was next to the removed one - that's it, now your list is sorted again.
Related
I have to do a function which, taken as parameters a pointer (int *vect) and the dimension (dim) of the array allocated, returns a new array which contains all the elements of the old array not repeated and all the first occurrence of repeated elements, this is the code where i put the elements not repeated of the first array, but i don't know how to proceed to put the first occurrence of repeated elements (e.g. INPUT : vect={1;2;3;3;4;5;5} OUTPUT : {1;2;3;4;5})
int* deleteDup(int *vect,int dim){
int* vect2,int dim2;
vect2=malloc(sizeof(int)*dim2);
int i,j,temp;
int count=0;
for(i=0;i<dim-1;i++){
temp=vect[i];
for(j=i+1;j<dim;j++){
if(temp==vect[j]){
count++;
}
}
if(count==0){
dim2++;
vect2=realloc(vect2,dim2*sizeof(int));
vect2[dim2]=temp;
}
*dim_nodup=dim2;
return vect2;
}
This looks like homework to me.
You need to first count the number of unique elements, then allocate an array of that size, and then move one instance of each unique element to the new array.
This can be optimised various ways.
I prefer not to give you code or even pseudo code, as you should figure this out yourself when solving the problem.
i don't know how to proceed to put the first occurrence of repeated elements
To do this you must move elements one by one into the array you are returning, and for each item check if it is already in the array.
Good luck! :)
im having trouble "removing" my struct/array. Right now i can define max array to be size 10. I can fill the array with struct containing name, age, ect. My search function will let me search between a set of interval, say age 10 to 25. What i want my remove function do is remove those all those people between age 10-25. I should be able to re-enter new people into the database as long as it doesn't exceed my defined limit. Right now it seems to randomly remove stuff from the array.
struct database
{
float age,b,c,d;
char name[WORDLENGTH];
};
typedef struct database Database;
search func();
.........
void remove(Database inv[], int *np, int *min, int *max, int *option)
{
int i;
if (*np == 0)
{
printf("The database is empty\n");
return;
}
search(inv, *np, low, high, option);
if (*option == 1)
{
for (i = 0; i<*np; i++)
{
if (inv[i].age >= *low && inv[i].age <= *high)
{
(*np)--;
}
}
}
}
Right now it seems to randomly remove stuff from the array.
The items that your code removes are not random at all. This line
(*np)--;
removes the last item. Therefore, if the range contains two items that match the search condition at the beginning of the inv, your code would remove two items off the end. Things get a little more complicated if matching items are located in the back of the valid range of inv, so deletions start looking random.
Deleting from an array of structs is not different from deleting from an array of ints. You need to follow this algorithm:
Maintain a read index and a write index, initially set to zero
Run a loop that terminates when the read index goes past the end
At each step check the item at read index
If the item does not match the removal condition, copy from read index to write index, and advance both indexes
Otherwise, advance only the read index
Set new np to the value of write index at the end of the loop.
This algorithm ensures that items behind the deleted ones get moved toward the front of the array. See this answer for an example implementation of the above approach.
You can't remove an array element simply by decreasing the count of number of elements.
If you want to remove the n'th element in the array, you have to overwrite the n'th element with the (n+1)'th element and overwrite the (n+1)'th element with the (n+2)'th element and so on.
Something like:
int arr[5] = { 1, 2, 3, 4, 5};
int np = 5;
// Remove element 3 (aka index 2)
int i;
for (i = 2; i < (np-1); ++i)
{
arr[i] = arr[i+1];
}
--np;
This is a simple approach to explain the concept. But notice that it requires a lot of copy so in real code, you should use a better algorithm (if performance is an issue). The answer from #dasblinkenlight explains one good algorithm.
Recently I was reading a Programming book and found this question:
I have an array :
array = [2,3,6,7,8,9,33,22];
Now, Suppose I have deleted the element at 4th position i.e. 8 .
Now I have to rearrange the array as:
Newarray = [2,3,6,7,9,33,22];
How Can I do this. And I have to also minimize the complexity.
Edit I have no choice to make another copy of it.I have to only modify it.
You can "remove" a value from an array by simply copy over the element by the next elements, that's easy to do with memmove:
int array[8] = {2,3,6,7,8,9,33,22};
memmove(&array[4], &array[5], sizeof(int) * 3);
The resulting array will be {2,3,6,7,9,33,22,22}.
And from that you can see the big problem with attempting to "remove" an element from a compile-time array: You can't!
You can overwrite the element, but the size of the array is fixed at time of compilation and can't actually be changed at run-time.
One common solution is to keep track of the actual number of valid elements in the array manually, and make sure you update that size as you add or remove elements. Either that or set unused elements to a value that's not going to be used otherwise (for example if your array can only contain positive numbers, then you could set unused elements to -1 and check for that).
If you don't want to use a library function (why not?) then loop and set e.g.
array[4] = array[5];
array[5] = array[6];
and so on.
Do this, just use these two functions and it will work fine
index=4;//You wanted to delete it from the array.
memcpy(newarray,array,sizeof(array));
memmove(&newarray[index], &newarray[index + 1], sizeof(newarray)-1);
now the newarray contains your exact replica without the character that you wished to remove
You can simply displace each element from the delIdx(deletion index) one step forward.
for(int i=delIdx; i<(arr_size-1);i++)
{
arr[i]= arr[i+1];
}
If required you can either set the last element to a non-attainable value or decrease the size of the array.
I am not sure why I am not able to get this right, I spend some time on this, and I don't get what I want. and now I am upset. I have a list LL[] of desired items, and a list seenLL[] which may contain items from LL[], but in any random order. I wanted to put the missing items in unseen[] and then print unseen. At-least that is my idea :(
unsigned int i=0, j=0, k=0;
unsigned int LL[] = {0xB173,0xB193,0xB14D,0xB14E}; //Desired items
unsigned int seenLL[5]; // Seen items
unsigned int unseen[5]; // For unseen items
printf("\n List of Logcodes seen in filtered view :");
for(i=0;i<view->numFilters;i++){ // I can't explain this, as it's BIG
if(flt->filterType == LOGCODE_TYPE ){
printf(" 0x%04X,",flt->code); // This will print the list of items in the view. Usually about 2 or 3 items
seenLL[k]=flt->code; // Copy them to seenLL[]
k++;
}
}
k=0;
// At this point though my seenLL[] has a few of my desired items, it also contains junk information, which I am unable to explain.
for(i=0;i<sizeof(LL)/sizeof(LL[0]);i++){
for(j=0;j<sizeof(seenLL)/sizeof(seenLL[0]);j++){
if(LL[i] != seenLL[j]){
unseen[k]=LL[i]; // I was trying to copy to unseen[] items that are missing from the desired list LL[]
k++;
}
//else{ // Dumb, but what if seenLL[] had items from LL[] but not in the same order as they are in the array LL[], it can occur in any order
// if(sizeof(unseen)/sizeof(unseen[0])!=0)
// if(LL[i] == unseen[i]{
// k--;
// unseen[i]=0;
// }
}
}
if(k>0) printf(" Missing Logs Pkts :");
if(k>0) for(i=0;i<sizeof(unseen)/sizeof(unseen[0]);i++) //sigh! my pathetic attempt to print missing items.
printf("%d,",unseen[i]);
You must scan the seenLL array for each element of LL but properly detect if the element has been seen:
for (i = 0;i < sizeof(LL) / sizeof(LL[0]); i++) {
for (j = 0; j < sizeof(seenLL) / sizeof(seenLL[0]); j++) {
if (LL[i] == seenLL[j])
break;
}
if (j >= sizeof(seenLL) / sizeof(seenLL[0])) {
unseen[k++] = LL[i]; // scan went to the end, no match.
}
}
I suggest using the macro countof to clarify your code:
#define countof(a) ((sizeof(a) / sizeof((a)[0]))
The logic is wrong.
What you're doing: For each item in LL: if it is different from some item in seenLL, add it to unseen.
What you should do: For each item in LL: if it is different from every item in seenLL, add it to unseen.
(Another way to think of these two possible logics: the first one checks for some item whether it is the same as every item in seenLL, while the second one checks whether it is the same as some item in seenLL. It's clear that the first check cannot succeed if seenLL contains at least two different items.)
Array seenLL has space for only five elements, but there's nothing to suggest or ensure that the number of codes you attempt to record in it will be five or fewer if LL had more than five elements.
Furthermore, after you are done populating seenLL, you discard the value of variable k, which tells you how many of the elements of seenLL actually contain valied data.
Later, you test each element of LL against potentially all the elements of seenLL, possibly including some that do not contain valid data. In fact, you should test against all valid elements but no invalid ones, else you are likely to turn up all elements as unseen (they will fail to match at least one element of seenLL).
Array unseen also has space for only five elements, but there's nothing to suggest or ensure that the number of codes you attempt to record in it will be five or fewer.
Then, at the end, if you in fact did recognize any unseen elements, you print every element of unseen, likely including some that do not contain valid data.
I need to remove a specific element from an array, that array is dynamically resized in order to store an unknown number of elements with realloc.
To control the allocated memory and defined elements, I have two other variables:
double *arr = NULL;
int elements = 0;
int allocated = 0;
After some elements being placed in the array, I may need to remove some of them. All texts that I've found says to use memmove and reduce the variables by the number of elements removed.
My doubt is if this method is secure and efficient.
I think this is the most efficient function you can use (memcpy is not an option) regarding secured - you will need to make sure that the parameters are OK, otherwise bad things will happen :)
Using memmove is certainly efficient, and not significantly less secure than iterating over the array. To know how secure the implementation actually is, we'd need to see the code, specifically the memmove call and how return results from realloc are being checked.
If you get your memmove wrong, or don't check any realloc returns, expect a crash.
In principle, assuming you calculate your addresses and lengths correctly, you can use memmove, but note that if you overwrite one or more elements with the elements at higher indexes, and these overwritten elements were structs that contained pointers to allocated memory, you could produce leaks.
IOW, you must first take care of properly disposing the elements you are overwriting before you can use memmove. How you dispose them depends on what they represent. If they are merely structs that contain pointers into other structures, but they don't "own" the allocated memory, nothing happens. If the pointers "own" the memory, it must be deallocated first.
The performance of memmove() and realloc() can be increased by data partitioning. By data partitioning I mean to use multiple array chunk rather than one big array.
Apart from memmove(), I found memory swaping is efficient way. But there is drawback. The array order may be changed in this way.
int remove_element(int*from, int total, int index) {
if(index != (total-1))
from[index] = from[total-1];
return total-1; // return the number of elements
}
Interestingly array is randomly accessible by the index. And removing randomly an element may impact the indexes of other elements as well. If this remove is done in a loop traversal on the array, then the reordering may case unexpected results.
One way to fix that is to use a is_blank mask array and defer removal.
int remove_element(int*from, int total, int*is_valid, int index) {
is_blank[index] = 1;
return total; // **DO NOT DECREASE** the total here
}
It may create a sparse array. But it is also possible to fill it up as new elements are added in the blank positions.
Again, it is possible to make the array compact in the following efficient swap algorithm.
int sparse_to_compact(int*arr, int total, int*is_valid) {
int i = 0;
int last = total - 1;
// trim the last blank elements
for(; last >= 0 && is_blank[last]; last--); // trim blank elements from last
// now we keep swapping the blank with last valid element
for(i=0; i < last; i++) {
if(!is_blank[i])
continue;
arr[i] = arr[last]; // swap blank with the last valid
last--;
for(; last >= 0 && is_blank[last]; last--); // trim blank elements
}
return last+1; // return the compact length of the array
}
Note that the algorithm above uses swap and it changes the element order. May be it is preferred/safe to be used outside of some loop operation on the array. And if the indices of the elements are saved somewhere, they need to be updated/rebuilt as well.