K08 Δομές Δεδομένων και Τεχνικές Προγραμματισμού
Κώστας Χατζηκοκολάκης
vector_get_at
, vector_set_at
are trivialvector_insert_last
?
vector_insert_last
size+1
elementssize
previous elementssize
Consider the geometric progression with ratio 2 $$1, 2^1, 2^2, \ldots, 2^n$$
Summing $n$ terms, we get the next one minus 1 $$1 + 2^1 + 2^2 + \ldots + 2^n = 2^{n+1}-1$$
So each term is larger than all the previous together!
vector_remove_last
?vector_remove_last
is clearly worst-case $O(1)$std::vector
in C++Better strategy
We can show that even a combination of insert+remove is $O(1)$ amortized-time
Types
// Ένα VectorNode είναι pointer σε αυτό το struct.
struct vector_node {
Pointer value; // Η τιμή του κόμβου.
};
// Ενα Vector είναι pointer σε αυτό το struct
struct vector {
VectorNode array; // Τα δεδομένα, πίνακας από struct vector_node
int size; // Πόσα στοιχεία έχουμε προσθέσει
int capacity; // Πόσο χώρο έχουμε δεσμεύσει
DestroyFunc destroy_value; // Συνάρτηση που καταστρέφει ένα στοιχείο
};
Vector vector_create(int size, DestroyFunc destroy_value) {
// Αρχικά το vector περιέχει size μη-αρχικοποιημένα στοιχεία, αλλά εμείς
// δεσμεύουμε xώρο για τουλάχιστον VECTOR_MIN_CAPACITY για να αποφύγουμε τα
// πολλαπλά resizes
int capacity = size < VECTOR_MIN_CAPACITY ? VECTOR_MIN_CAPACITY : size;
// Δέσμευση μνήμης, για το struct και το array.
Vector vec = malloc(sizeof(*vec));
VectorNode array = calloc(capacity, sizeof(*array)); // αρχικοποίηση σε 0
vec->size = size;
vec->capacity = capacity;
vec->array = array;
vec->destroy_value = destroy_value;
return vec;
}
Random access is simple, since we have a real array.
Pointer vector_get_at(Vector vec, int pos) {
return vec->array[pos].value;
}
void vector_set_at(Vector vec, int pos, Pointer value) {
// Αν υπάρχει συνάρτηση destroy_value, την καλούμε για
// το στοιχείο που αντικαθίσταται
if (value != vec->array[pos].value && vec->destroy_value != NULL)
vec->destroy_value(vec->array[pos].value);
vec->array[pos].value = value;
}
Insert, we just need to deal with resizes.
void vector_insert_last(Vector vec, Pointer value) {
// Μεγαλώνουμε τον πίνακα (αν χρειαστεί), ώστε να χωράει τουλάχιστον size
// στοιχεία. Διπλασιάζουμε κάθε φορά το capacity (σημαντικό για την
// πολυπλοκότητα!)
if (vec->capacity == vec->size) {
vec->capacity *= 2;
vec->array = realloc(vec->array, vec->capacity * sizeof(*new_array));
}
// Μεγαλώνουμε τον πίνακα και προσθέτουμε το στοιχείο
vec->array[vec->size].value = value;
vec->size++;
}