Las estructuras de datos determinan la eficiencia de las operaciones básicas. A continuación resumimos complejidad temporal (y cuando aplica, espacial) en escenarios típicos al trabajar con C.
O(1) por aritmética de punteros.O(1) si hay capacidad disponible; O(n) si requiere copiar a un buffer más grande.O(n) por corrimiento de elementos.O(n) por corrimiento; al final es O(1).void insertar(int *v, int *n, int pos, int valor) {
for (int i = *n; i > pos; i--) v[i] = v[i - 1]; // corrimiento
v[pos] = valor;
(*n)++;
}
O(n); hay que recorrer nodo a nodo.O(1) usando la cabeza.O(1); localizar el nodo es lo costoso.O(n) pero con sobrecosto por punteros.typedef struct Nodo {
int dato;
struct Nodo *sig;
} Nodo;
void push_front(Nodo **head, int valor) {
Nodo *nuevo = malloc(sizeof(Nodo));
nuevo->dato = valor;
nuevo->sig = *head;
*head = nuevo;
}
Pila (stack LIFO):
push/pop son O(1).O(n) puntual, pero amortizado O(1) si se duplica capacidad.Cola (FIFO):
enqueue/dequeue en O(1).O(1) si se mantiene puntero a cabeza y cola.h = O(log n), degenerado h = O(n).O(n) ya que visita cada nodo una vez.O(h), depende de la altura real.O(log n) para insertar, buscar y eliminar.O(n).O(1) por operación, por eso el orden amortizado se conserva.O(1) si la función hash distribuye bien y la tabla se redimensiona.O(n) si todas las claves colisionan; se mitiga con buena función hash y resize.O(n), pero ocurre cada varios inserts → amortizado O(1).typedef struct Entrada {
const char *clave;
int valor;
} Entrada;
int hash(const char *s, int mod) {
unsigned h = 5381;
for (; *s; s++) h = ((h << 5) + h) + (unsigned char)(*s);
return (int)(h % mod);
}
O(log n) por subir el elemento.O(log n) por bajar el elemento.O(1) porque está en la raíz.O(n) usando heapify de abajo hacia arriba.void sift_up(int *v, int idx) {
while (idx > 0) {
int padre = (idx - 1) / 2;
if (v[padre] <= v[idx]) break;
int tmp = v[padre];
v[padre] = v[idx];
v[idx] = tmp;
idx = padre;
}
}