proper usage of the remove() function? - c++

i'm working on this personal project and i'm a bit confused on how the remove() function works.
header:
class IntSet {
public:
IntSet(); //Constructor
~IntSet(); //Destructor
int size() ; //
bool isEmpty();
bool contains(int number1);
void add(int number2);
void remove(int number2);
private:
int* ptr; //pointer to the array
int sizeOfArray; //current size of the array
int currentValue; //number of values currently in IntSet
};
main (only including add() part)
#include "IntSet.hpp"
#include <iostream>
IntSet::IntSet(){
sizeOfArray = 10;
currentValue = 0;
ptr = new int[10];
}
IntSet::~IntSet(){
delete[] ptr;
}
//returning the number of values in the IntSet
int IntSet::size()
{
return currentValue;
}
//Determining whether the stack is empty
bool IntSet::isEmpty()
{
if (currentValue == 0)
return true;
else
return false;
}
//defining contains() function
bool IntSet::contains(int number1)
{
for (int i = 0; i < currentValue; i++)
{
if (ptr[i] == number1)
return true;
}
return false;
}
//defining add() function
void IntSet::add(int number2)
{
if (currentValue == sizeOfArray)
{
sizeOfArray = sizeOfArray * 2; //doubling size of arrayCapacity
int* temp = new int[sizeOfArray]; //allocating new one that's twice as large
for (int i = 0; i < currentValue; i++)
{
temp[i] = ptr[i]; //copying old stuff into new one
}
delete[] ptr; //deallocate old array
ptr = temp; //set ptr to new array
}
}
//defining remove() function goes here
So for the add() function I had to take an int parameter add it to the array. When it gets full I have to double the size of the array, copy the contents of the old array into the new one, redirect the data member pointer to the new array and then deallocate the array.
For the remove() function I have to just take an int parameter and remove it from the IntSet by shifting over all the subsequent elements of the array. Should I just use parts of my add function and pretty much tell it to do the opposite for my remove() function? If not, how do I even begin to write the remove() function? I'll show the rest of my code if needed. Thank you guys so much!

Give this a try for removing:
void IntSet::remove(int number2)
{
bool bIntRemoved = false;
for(int i=0; i < currentValue; i++){
// check if we are currently searching or shifting
if(!bIntRemoved){
// still searching
// check if we should remove int at current index
if(ptr[i] == number2){
// found the int to remove
// We'll decrement i and set bIntRemoved = to true
// So the else-if code handles shifting over the array
i--;
bIntRemoved = true;
}
}else if(i < currentValue-1){
// We have spots to shift
// Check if this is the last index
ptr[i] = ptr[i+1];
} // else, we are at the last index and we have nothing to shift
}
if(bIntRemoved){
// The int was successfully located and any necessary shifting has been
// executed. Just decrement currentValue so the current last index will be
// disregarded.
currentValue--;
} // else, the int to remove could not be located
}
I haven't tested, but in theory, this should locate the first instance of the int you need to remove, shift all values left by one spot (unless the int to remove is in the last index of the array), and then decrement the currentValue variable so the previous last index of the array is disregarded and can be overwritten. Anyway, sorry if that's a poor explanation, but it's not the easiest concept to explain. I attempted to document the code fairly well, so hopefully that will make sense :P Let me know if you have any questions and let me know if this works or doesn't work for you (I find feedback to be very important.)
EDIT: Also, I intended to mention this, but I forgot, so thank you, #Viet, for mentioning this in your answer, your add() function does not seem to handle cases when the currentValue is less than the size of the array. I assume you are already handling that and you just omitted the else statement that takes care of it?
EDIT #2:
The following is code to properly handle adding new elements to the array:
void IntSet::add(int number2){
if (currentValue == sizeOfArray)
{
sizeOfArray = sizeOfArray * 2; //doubling size of arrayCapacity
// nothrow is used below to allow for graceful error handling if there is not enough
// ram to create the new array
int* temp = new (nothrow) int[sizeOfArray]; //allocating new one that's twice as large
// check if new int array could be create
if(temp == nullptr){
// new int array could not be created
/** Possibly set an error flag here or in some way warn the calling function that
the function failed to allocate the necessary memory space.
I'll leave that up to you, OP. **/
// Right now we'll just return without modifying the existing array at all
return;
}
for (int i = 0; i < currentValue; i++)
{
temp[i] = ptr[i]; //copying old stuff into new one
}
delete[] ptr; //deallocate old array
ptr = temp; //set ptr to new array
// Now we'll just let the code below add the number to the array
} // else we have enough space to add the number to the array
ptr[currentValue] = number2;
currentValue++;
}
Again, I have not tested this code, but let me know if it works or does not work for you. Also, I modified the line that makes a new array (int *temp = new int[sizeOfArray];) to now handle errors if memory cannot successfully be allocated. To do this I am using the (nothrow) object (more on that on this CPlusPlus page). If allocation fails, a temp is set to a null pointer. Without this, the method would instead throw a bad_alloc exception or the program would terminate. That's not very graceful, so I prefer properly handling the error (and handling it in a way that is less strenuous on the calling function). To use this, you will need to include the <new> header (which is where nothrow is defined).

Is your class is a set or a list? If your class is a set, it mean there are no same numbers in your class
Example: a set {1, 2, 3}, a list: {1, 2, 3, 1, 3, 2}
About your add function, i have some comments:
You does not check new element exist in your set
You does not increase current size and set value for new element in your set
You can use memcpy function to copy old data to new data pointer
About remove function, i have some ideas:
At first, you must find the position of number which need to be delete in current set
After that, you remove that number by shift left all member from next position of number which need to be delete to the left position. And you must decrease current size by 1
Example: you have a set {1, 2, 3, 4}, current size is 4. And you want to remove a number "2"
First, you find the position of 2 in your set. It is 1 (because the start index of array is start from 0)
Second, you remove it by pushing back all the values from next position on the front of its in your set.
Ex: the value of position 1 replaced by value 3, the value of position 2 replaced by value 4
Finally, you decrease current size by 1. Now, current size is 3, and you have a new set {1, 3, 4}

Related

Delete Zero in ArrayList in C++

Inside the ArrayList I'm trying to delete all possible 0's that are appended as input, but for now it only deletes just one 0, no matter where it is located. But seems like I can't delete more than one zero at the time. How can I fix this?
void AList::elimZeros(){
int i;
int curr = 0;
for(i=0; i < listSize; i++) {
if ( (listArray[i] != 0 ) && (curr<listSize) ){
listArray[curr] = listArray[i];
curr++;
}
else if (listArray[i] == 0 )
{
listArray[curr] = listArray[i+1];
listSize--;
curr++;
}
}
}
This is the class for the ADT
class AList : public List {
private:
ListItemType* listArray; // Array holding list elements
static const int DEFAULT_SIZE = 10; // Default size
int maxSize; // Maximum size of list
int listSize; // Current # of list items
int curr; // Position of current element
// Duplicates the size of the array pointed to by listArray
// and update the value of maxSize.
void resize();
public:
// Constructors
// Create a new list object with maximum size "size"
AList(int size = DEFAULT_SIZE) : listSize(0), curr(0) {
maxSize = size;
listArray = new ListItemType[size]; // Create listArray
}
~AList(); // destructor to remove array
This is the input I'm testing with:
int main() {
AList L(10);
AList L2(20);
L.append(10);
expect(L.to_string()=="<|10>");
L.append(20);
expect(L.to_string()=="<|10,20>");
L.append(30);
L.append(0);
L.append(40);
L.append(0);
L.append(0);
expect(L.to_string()=="<|10,20,30,0,40>");
L.elimZeros();
expect(L.to_string()=="<|10,20,30,40>");
assertionReport();
}
It'd be helpful if you posted the class code for AList. Think you confused Java's ArrayList type, but assuming you're using vectors you can always just do:
for (int i = 0; i < listSize; i++) {
if(listArray[i] == 0) listArray.erase(i);
}
EDIT: Assuming this is the template of for the AList class, then there is simply a remove() function. In terms of your code, there are two issues.
You reference listSize in the for loop, then decrement it inside of the loop. Each iteration evaluates the value separately so you're reducing the number of total loop iterations and stopping early.
The other thing is if the entry is zero you shouldn't increment curr and set listArray[curr] = listArray[i+1]. This is basically assuming the next entry will not be a zero. So if it is, then you're copying the element and moving to the next. Your if statement can be cleaned up with:
if (listArray[i] == 0) {
listSize--;
} else {
listArray[curr] = listArray[i];
curr++;
}

Not able to double the size of an array

I want to resize the array when the rehash function is called, by copying the values of initial dictionary into it and then at last redifining the newdictionary as dictionary
void rehash ()
{
int newsize=2*Size;
node **newdictionary;
newdictionary= new node*[newsize];
//Initialising the dictionary
for (int i = 0;i < newsize;i++)
{
newdictionary[i]->name = "";
newdictionary[i]->value = -1;
}
node **temp=dictionary;
delete [] dictionary;
dictionary=newdictionary;
SIZE=newsize;
for(int i=0;i<SIZE;i++)
{
if(temp[i]->value!= -1)
insertvalue(temp[i]->name,temp[i]->value);
}
delete [] temp;
};
Earlier I have defined insertvalue as:
void insertvalue (string filedata, int code)
{
// tableindex is the position where I want to insert the value
dictionary[tableindex]->name= filedata;
dictionary[tableindex]->value=code;
};
You didn't actually explain what problem(s) you're having, but your code has several issues:
void rehash ()
{
int newsize=2*Size;
node **newdictionary;
newdictionary= new node*[newsize];
At this point, newdictionary is simply an array of uninitialized pointers.
//Initialising the dictionary
for (int i = 0;i < newsize;i++)
{
newdictionary[i]->name = "";
newdictionary[i]->value = -1;
}
So the loop above is trying to access the members of node objects that don't yet exist.
node **temp=dictionary;
delete [] dictionary;
These two lines don't make sense. dictionary and temp point to the same memory. So when you delete dictinoary you've deleted the memory that temp is pointing to.
dictionary=newdictionary;
SIZE=newsize;
for(int i=0;i<SIZE;i++)
{
if(temp[i]->value!= -1)
insertvalue(temp[i]->name,temp[i]->value);
}
Even if you hadn't just deleted the memory out from under temp, you're now trying to access temp from 0 to the new size, not the old size. In other words, this would access temp beyond its bounds.
Those are the major problems that I've noticed in the code so far. You at least need to correct all of them before there's any hope of this working. You probably need to spend some time really stepping through your logic to ensure it makes sense in the end.

Segmentation fault - new and delete have been used. Lots of arrays are being created during runtime (unbounded array)

I'm trying to implement an unbounded array: What is an unbounded array?
More details on this page:
http://www.cs.cmu.edu/~fp/courses/15122-s11/lectures/12-ubarrays.pdf
This is the code:
#include <iostream>
#include <cstdlib>
using namespace std;
class UBArray
{
public:
int *arr, *arrN, j, *pos; //Initial array is arr. The position of arr is stored in pos. arrN is the new array created when size = limit.
int size, limit; //size is the current size of the array and limit is the total size available untill a new array is created.
UBArray()
{
size = 0;
limit = 10;
arr = new int[10];
pos = arr;
}
private:
void increment()
{
// New array arrN is created and then the values in the old arrays is put into the new array.
// Limit is increased by 10 - this is the extra space the new array contributres.
// pos which carries the address of the current array now carries the address of the new array.
// Later when a new array is created its address will be on the heap which is empty. This address is replace the address stored
// in the arrN. The older array can still be accessed for the array updation process by using the variable pos.
// IMPORTANT: I had initially tried to delete the older array to space space but while trying to debug the segmentation fault, I have
// removed it. I will be adding it again once the error has been fixed.
arrN = new int[size + 10];
for (j = 0; j < size; j++)
{
arrN[j] = pos[j];
}
limit = limit + 10;
pos = arrN;
}
public:
void push(int n)
{
if (size<limit)
{
size++;
pos[size-1]=n;
}
else
{
increment();
push(n);
}
}
int pop()
{
int p = pos[size-1];
size--;
return p;
}
};
int main()
{
UBArray array;
int num;
cout << "Enter 36 elements: ";
for (int k = 0; k<36; k++)
{
cin >> num;
array.push(num);
}
cout << endl << "The last element is : " << array.pop();
}
I have tried to give comments in the code to make it understandable to the reader. I'm copying some of it here:
Initial array is arr. The position of arr is stored in pos. arrN is the new array created when size = limit.
size is the current size of the array and limit is the total size available until a new array is created.
New array arrN is created and then the values in the old array are put into the new array.
Limit is increased by 10 - this is the extra space the new array contributres.
pos which carries the address of the current array now carries the address of the new array.
Later when a new array is created its address will be on the heap which is empty. This address is replaced the address of arrN. The older array can still be accessed for the array updation process by using the variable pos which will be updated by the old values have been copied to the new one.
I get segmentation fault during execution. I have tried to use cout statements to debug the code but it seems really confusing. I could see loops both inside and outside the for loop inside the increment method. I'm unable to figure out much. Any help is appreciated.
UPDATE: As pointed out by jrok, I changed the code and the seg fault is gone. But I'm getting seg fault again at the creation of the 3rd array.
UPDATE 2 Everything fixed now. Thank you.
arr = new int(10*sizeof(int));
That creates a single int, initialized to the value of 10*sizeof(int). The loop you wrote right after this statement runs out of bounds and it's cause of segmentation fault.
What you want is the array form of new:
arr = new int[10]; // note 10 only, new expression knows the size
// of the type it allocates
Note that when you assign the pointer to the new array to the pointer to the old array you lose the handle to it and create a memory leak:
int* arr = new int[10];
int* new_arr = new int[20];
arr = new_arr; // original array at arr has leaked
You need to delete[] arr before you reassign it. Also, I see no use for the third (pos) pointer. Not even for arrN, for that matter. One will do. Create a local pointer inside increment and assign it to arr when you're done deallocating the old array.
Finally, what people have been telling you in the comments, unless this is a learning exercise, don't try to reinvent the wheel and use std::vector instead.
An unbounded array only needs 3 data members (rather than 6): the address of the beginning of the data buffer, the capacity of the buffer, and the actual size (of the part of the buffer used so far). When expanding, you will temporarily need to hold the address of the new buffer in an automatic variable. Also, you should avoid leaking the memory of previous buffers. A simple layout is like this:
struct ua
{
int size,capacity,*buff; // 3 data members only
ua(int n) // constructor: n = initial capacity
: size(0) // initially empty
, capacity(n<0?0:n) // guard against n<0
, buff(capacity?new int[capacity]:0) {} // only allocate if n>0
~ua() { delete[] buff; } // destructor: note: delete[] 0 is ok
void empty() const { return size==0; } // is array empty?
void push(int x) // add another datum at back
{
if(size==capacity) { // buffer is full: we must expand
if(capacity) capacity+=capacity; // double capacity
else capacity=1; // but ensure capacity>0
int*nbuff=new int[capacity]; // obtain new buffer
if(size)
memcpy(nbuff,buff,size*sizeof(int)); // copy data from old to new buffer
delete[] buff; // free memory form old buffer
buff=nbuff; // set member buff to new buffer
}
buff[size++]=x; // write; increment size (post-fix)
}
int pop() // ill-defined if empty()
{ return buff[--size]; } // read; decrement size (pre-fix)
int operator[](int i) const // ill-defined if i<0 or i>=size
{ return buff[i]; }
int&operator[](int i) // ill-defined if i<0 or i>=size
{ return buff[i]; }
// you may add more functionality, for example:
void shrink(); // reduces capacity to size
void reserve(int n); // extends capacity to n, keeping data
ua(ua const&other); // copy buffered data of other
void swap(ua&other); // swap contents with other (no copying!)
};

Removing int value in dynamic array and setting it to NULL

So my code is suppose to insert numbers into a dynamic array, add more capacity to the array if more is needed, remove numbers from the array and then make sure the only NULLS occur at the end of the array. It also tells the user how many numbers are in the array and what is the total size of the array. My problem is when I remove a number from the array, it sometimes prints out there is a number -33686019 in my array. This doesn't occur much, but I don't want it to occur at all.
#include <stdio.h>
#include <iostream>
int* gArray = NULL;
int gSize = 0;
int gCapacity = 0;
void Insert(int value);
void Remove(int value);
void Resize(int newCapacity);
void Print(void);
void main()
{
int input = 0;
while(input != 3)
{
printf(">=== Dynamic Array ===\n");
printf("What do you want to do?\n");
printf("1. Insert\n");
printf("2. Remove\n");
printf("3. Quit\n");
printf("Your choice: ");
scanf_s("%d", &input);
printf("\n\n");
int value = 0;
switch(input)
{
case 1:
{
printf("Enter a number: ");
scanf_s("%d", &value);
Insert(value);
Print();
break;
}
case 2:
{
printf("Enter number you wish to delete: ");
scanf_s("%d", &value);
Remove(value);
Print();
break;
}
case 3:
{
break;
}
default:
{
printf("Invalid selection\n");
}
}
}
}
void Insert(int value)
{
bool valueSet = false;
while(valueSet == false)
{
if(gArray == NULL)
{
Resize(1);
gArray[gSize] = value;
++gSize;
valueSet = true;
}
else if(gArray[gCapacity] == NULL)
{
gArray[gSize] = value;
++gSize;
valueSet = true;
}
else if(gArray[gCapacity] != NULL)
{
Resize((gCapacity + 1));
gArray[gSize] = value;
++gSize;
valueSet = true;
}
}
}
void Resize(int newCapacity)
{
int* tempArray = new int[newCapacity];
std::copy(gArray, gArray+(newCapacity-1), tempArray);
gArray = new int[newCapacity];
std::copy (tempArray, tempArray+(newCapacity-1), gArray);
gCapacity = newCapacity;
}
void Remove(int value)
{
for(int i = 0; i < gCapacity; ++i)
{
if(gArray[i] == value)
{
gArray[i] = NULL;
--gSize;
}
}
for(int i = 0; i < gCapacity; ++i)
{
if(gArray[i] == NULL)
{
gArray[i] = gArray[(i + 1)];
gArray[(i + 1)] = NULL;
}
}
}
void Print(void)
{
printf("Array contains: ");
for(int i = 0; i < gCapacity; ++i)
{
if(gArray[i] != NULL)
{
printf("%d, ", gArray[i]);
}
}
printf("size = %d, capacity = %d\n", gSize, gCapacity);
}
An option, since you are using the c++ standard library would be to remove all your code, and use std::list and its insert and remove methods. If you require the data to be in a dynamic array, then use std::vector and the erase remove idiom for removal.
I have to point out that, since your question is "Removing int value in dynamic array and setting it to NULL", that setting an int to NULL is essentially setting it to the value 0, since NULL tends to be a define for 0. So if your list were to contain zeroes, this setting to NULL and checking for equality with NULL would completely break the logic of your algorithm. C++11 has nullptr, an actual null type that cannot be assigned to an int, to deal with this kind of problem.
The concrete problem is that you don't initialize the new array (resp. tempArray) in your Resize function.
When calling
int* tempArray = new int[newCapacity];
the array can contain arbitrary values. Only newCapacity-1 values are copied from the old array, so the last value is undefined. It might be 0 but haven't to be. Use
std::fill(tempArray, tempArray+newCapacity, 0);
to initialize your array with zero.
Apart from that, there are a few other problems:
You don't delete the old array before allocating a new one. Use delete[] gArray for that. Also tempArrayisn't deleted!
You don't need to copy the values twice. Just to a gArray = tempArray (after deleting the old gArray, see above)
You assume that newCapacity is just larger by one than gCapacity (you copy newCapacity-1 values from the old array). It would be better to copy gCapacity values instead.
Dynamic arrays which only grow by one are inefficient, since adding a value takes linear time (you have to copy all the old values when inserting a single one). Usually, you double the size of the array every time you run out of space, this gives constant insertion time in average.
NULL is normally used only for pointers. For ints it is equal to zero which means, you cannot store 0 in your array (given your requirements)
In production code, I'd strongly recommend using std::vector instead of any home-grown solution.
EDIT
See #StackUnderflows answer for what is probably the real cause of the error. If you run in Debug mode, some compilers will automatically initialize the array for you, which might be the ccase here.
The gArray[i]=gArray[i+1] line in your Remove function is definitely wrong on the other hand, since it accesses a value which is beyond the limits of the array.
The problem occurs on the last iteration in the second loop of Remove when you do gArray[i] = gArray[i + 1]. On the last iteration, gArray[i + 1] is actually one past the end of your array, so you are now in undefined behavior territory. You are assigning this undefined value to the last element gArray[i].
I suggest using std::vector<int> instead. It manipulates an array under the hood which grows/resizes for you as you add more elements.

Dynamic tree in C++

I'd like to make a tree which can have some childrens in every node, but i don't know number of them. Tree have to be coded in small memory using (no extra data) with constant time to every node. I tought that i will make class Tree with value and children property (value is int, and children is stack) and array of pointers to every node in that Tree. My problem is to make this array. How can i make it with no extra data (std::vector sometimes allocate more memory than it needs) and constant time to every cell?
Everything's ok, but i also need constant time to every node. I know how many nodes will be, but i dont know how to make array of every node. It should work something like:
array[n];
A_Node *array[0]= new A_Node(16);
A_Node *n = new A_Node(1);
array[0]->addChild(n);
array[1]=n;
Or:
*(array+1)=n;
This is a possible example. It is not a full example solution but I hope you get the point. The point is that you can have a double pointer to nodes, which is basically an array of pointers to nodes of the tree.
Then you can reallocate the size yourself and to however much you want whenever there is a need to. But std::vector already does that for you so there is no real reason not to use it unless you want to control everything yourself or experiment, or are writing something in C. In any case hope this helps.
#include <stdio.h>
#include <stdlib.h>
// The initial buffer length of a node's children
#define BUFFER_LENGTH 5
// How much to multiply with if an addition of a child goes over the buffer
#define MULTIPLIER 2
///Your node class
class A_Node
{
public:
A_Node(int value,unsigned int childrenN=0)
{
this->value = value;
this->childrenN = childrenN;
//allocate BUFFER_LENGTH children for the node at first or childrenN if the childrenN is not initially 0
if(childrenN != 0)
{
this->children = (A_Node**) malloc(sizeof(A_Node*)*childrenN);
this->bufferLength = childrenN;
}
else
{
this->children = (A_Node**) malloc(sizeof(A_Node*)*BUFFER_LENGTH);
this->bufferLength =BUFFER_LENGTH;
}
}
//in the destructor of a node it would need some special care
~A_Node()
{
//for every child call the destructor of each child
for(int i = 0; i < this->childrenN; i++)
{
delete this->children[i];
}
//and only then free the buffer of the pointers to the children
free(this->children);
}
//adds a child
void addChild(A_Node* child)
{
//reallocate if needed
if(childrenN >= this->bufferLength)
{
realloc(this->children,sizeof(A_Node*)*MULTIPLIER);
}
this->children[childrenN] = child;
this->childrenN++;
}
A_Node* getChild(unsigned int i)
{
if(i >= this->childrenN)
{
return 0;
}
return this->children[i];
}
void printValue()
{
printf("%d\n",this->value);
}
private:
int value;
unsigned int childrenN;
A_Node** children;
unsigned int bufferLength;
};
///Your tree class
class A_Tree
{
public:
//constructor
A_Tree(int rootValue)
{
root = new A_Node(rootValue);
}
//destructor
~A_Tree()
{
//recursively kills all the nodes due to the destructor of node
delete root;
}
//your root node
A_Node* root;
};
int main()
{
A_Tree tree(16);
tree.root->addChild(new A_Node(42));
tree.root->printValue();
(tree.root->getChild(0))->printValue();
return 0;
}
Just keep track of the memory yourself rather than using a vector:
class Node {
public:
// In the constructor, initialize your array of children to NULL
// and the size of your children array to zero
Node() : mChildren(NULL), mSize(0) {}
void AddChild(Node* newChild) {
// allocate space for your new array
Node** newArray = new Node*[mSize + 1];
// copy over nodes from old array to new array
for (int i = 0; i < mSize; i++) {
newArray[i] = mChildren[i];
}
// add in our new child to the end of the array
newArray[mSize++] = newChild;
// if there was an old array (null check) free the memory
if (mChildren) {
delete [] mChildren;
}
// set our children array equal to our new array
mChildren = newArray;
}
Node* AccessChild(size_t index) {
// make sure it's a valid index and then return
assert(index < mSize);
return mChildren[index];
}
private:
Node** mChildren;
int mSize;
};
This will have no extra space for extra nodes, but it will require the size of an int in order to keep track of how many nodes you are storing. I don't see any way you could do it without this or having a constant number of children.
Please note, vectors double in size each time they need to reallocate because this is more efficient. While the solution above will be more efficient memory-wise, it will hurt a lot performance wise because it will require an allocation for every child addition, which is going to take O(N) allocations to add N nodes.
The performance of a vector will be O(log(N)) allocations to add N nodes, but again this solution sounds like it has the memory efficiency you're looking for.