Ja saps què és una estructura de dades i per què triar bé importa. El següent pas natural és conèixer el catàleg: quines estructures existeixen i com es classifiquen? Aquesta lliçó és el mapa del curs: presentarem les grans famílies d'estructures (lineals i no lineals, estàtiques i dinàmiques, homogènies i heterogènies), veurem quin paper jugarà cadascuna a TaskFlow i repassarem les estructures que Python porta de sèrie, que seran el nostre punt de partida. No aprofundirem en cap —cadascuna té el seu propi mòdul—, però en acabar sabràs situar qualsevol estructura al mapa i entendràs l'itinerari que seguirem.
Contingut
- Classificació 1: lineals vs no lineals
- Classificació 2: estàtiques vs dinàmiques
- Classificació 3: homogènies vs heterogènies
- El catàleg del curs i el seu paper a TaskFlow
- Les estructures natives de Python: el nostre punt de partida
Classificació 1: lineals vs no lineals
La primera pregunta que pots fer a qualsevol estructura és: com es relacionen els seus elements entre si?
- En una estructura lineal, els elements formen una seqüència: cada element té (com a molt) un anterior i un següent. És la relació "l'un darrere l'altre".
- En una estructura no lineal, un element pot relacionar-se amb diversos alhora: jerarquies (un pare amb diversos fills) o xarxes (connexions arbitràries entre nodes).
graph TB
subgraph Lineal
A1[Tasca 1] --> A2[Tasca 2] --> A3[Tasca 3] --> A4[Tasca 4]
end
subgraph No lineal: jerarquia
B1[Feina] --> B2[Client A]
B1 --> B3[Client B]
B2 --> B4[Factures]
B2 --> B5[Reunions]
end
subgraph No lineal: xarxa
C1[Tasca A] --> C2[Tasca B]
C1 --> C3[Tasca C]
C2 --> C4[Tasca D]
C3 --> C4
end
A TaskFlow apareixen els tres patrons de manera natural:
- El tauler de tasques és lineal: les tasques van en ordre, l'una darrere l'altra.
- Les categories són jeràrquiques: "Feina" conté "Client A", que conté "Factures".
- Les dependències són una xarxa: la tasca D depèn de la B i de la C, que al seu torn depenen de l'A.
Són lineals les llistes, les piles i les cues (mòduls 2 a 4). Són no lineals els arbres (jerarquies, mòdul 6) i els grafs (xarxes, mòdul 7). Les taules hash (mòdul 5) són un cas a part: els seus elements no mantenen cap relació d'ordre entre si —ni seqüència ni jerarquia—; el que les defineix és l'associació directa entre cada clau i el seu valor.
La classificació importa perquè determina com es recorre l'estructura: una seqüència es recorre de principi a fi; una jerarquia o una xarxa exigeixen estratègies de recorregut més elaborades (les veurem als seus mòduls).
Classificació 2: estàtiques vs dinàmiques
La segona pregunta: pot canviar la mida de l'estructura durant l'execució?
- Una estructura estàtica té una mida fixa, decidida en crear-la. Ocupa un bloc de memòria de mida coneguda i no creix ni minva.
- Una estructura dinàmica creix i s'encongeix a mesura que s'insereixen o s'eliminen elements, adaptant el seu ús de memòria en temps d'execució.
| Aspecte | Estàtica | Dinàmica |
|---|---|---|
| Mida | Fixada en crear-la | Canvia durant l'execució |
| Memòria | Reservada de cop, contigua | Es demana i s'allibera sobre la marxa |
| Avantatge principal | Simplicitat i accés molt ràpid | Flexibilitat: no cal predir la mida |
| Risc típic | Quedar-se curta o malbaratar espai | Cost extra de gestió de memòria |
| Exemple clàssic | Array de mida fixa (C, Java) | Llista enllaçada, list de Python |
L'exemple canònic d'estructura estàtica és l'array de mida fixa, habitual en llenguatges com C o Java: demanes lloc per a exactament 100 elements i això tens. En Python gairebé tot el que faràs servir és dinàmic —una list creix sense que t'hagis de preocupar de res—, però la distinció continua sent crucial per dos motius:
- Les estructures dinàmiques de Python estan construïdes sobre mecanismes estàtics per sota, i aquest "per sota" explica els seus costos (ho veurem a la lliçó 01-05 amb els arrays i la memòria).
- Tan bon punt surtis de Python (bases de dades, sistemes encastats, altres llenguatges), les mides fixes tornen a aparèixer.
Per a TaskFlow: el nombre de tasques és imprevisible i canvia constantment, així que necessitarem estructures dinàmiques gairebé sempre. En canvi, una cosa com els tres estats possibles d'una tasca (pendent, en curs, feta) és un conjunt fix que no creix mai: una estructura estàtica i immutable (una tupla, com veurem més avall) el representa millor.
Classificació 3: homogènies vs heterogènies
Tercera pregunta: tots els elements són del mateix tipus?
- Una estructura homogènia només admet elements d'un mateix tipus: tots enters, tots cadenes...
- Una estructura heterogènia barreja tipus: un enter al costat d'una cadena al costat d'un objecte.
# Homogenia: ids de tasques, tots enters
ids_pendents = [4, 8, 15, 16, 23]
# Heterogenia: una tasca amb camps de tipus diferents
tasca = {
"id": 42, # enter
"titol": "Migrar el servidor", # cadena
"prioritat": "alta", # cadena
"completada": False, # boolea
"etiquetes": ["infra", "urgent"], # una altra estructura a dins!
}En llenguatges amb tipatge estricte (C, Java), els arrays són homogenis per obligació. Python és flexible: una list admet qualsevol barreja. Però que puguis barrejar no vol dir que hagis de fer-ho: en la pràctica professional, les col·leccions solen mantenir-se homogènies ("una llista de tasques", "un conjunt d'ids") i l'heterogeneïtat es reserva per representar registres amb camps amb nom, com el diccionari tasca de l'exemple. Aquesta disciplina fa el codi predictible: si saps que ids_pendents només conté enters, pots operar amb confiança sobre qualsevol dels seus elements.
Fixa't també en l'última línia de l'exemple: "etiquetes" conté una llista dins del diccionari. Les estructures es componen les unes dins de les altres, i les aplicacions reals —TaskFlow inclosa— són sempre composicions: una llista de diccionaris, un diccionari de llistes, un arbre els nodes del qual contenen cues...
El catàleg del curs i el seu paper a TaskFlow
Amb les tres classificacions a la mà, ja podem presentar el catàleg complet d'estructures que estudiarem, cadascuna amb la necessitat de TaskFlow que resoldrà:
| Estructura | Família | Idea en una frase | Ús a TaskFlow | Mòdul |
|---|---|---|---|---|
| Llista | Lineal, dinàmica | Seqüència d'elements en ordre | El tauler de tasques | 2 |
| Pila | Lineal, dinàmica | L'últim d'entrar és el primer de sortir (LIFO) | El "desfer" d'accions | 3 |
| Cua | Lineal, dinàmica | El primer d'entrar és el primer de sortir (FIFO) | El processament de notificacions | 4 |
| Taula hash | Associativa, dinàmica | Cada clau porta directament al seu valor | Cerca instantània per id | 5 |
| Arbre | No lineal (jerarquia), dinàmica | Nodes pare amb nodes fill | Categories i subcategories | 6 |
| Graf | No lineal (xarxa), dinàmica | Nodes connectats entre si lliurement | Dependències entre tasques | 7 |
Dues observacions sobre la taula:
- Els termes LIFO (Last In, First Out) i FIFO (First In, First Out) són l'única "argot" nova: descriu-los mentalment com la pila de plats i la cua del supermercat de la lliçó 01-01, i tindràs el 90 % de la intuïció.
- L'ordre dels mòduls no és casual: va del més simple al més ric. Les piles i les cues es construeixen a partir d'idees de les llistes; els arbres generalitzen la idea d'"element que apunta a d'altres"; els grafs generalitzen els arbres. Cada mòdul es recolza en l'anterior, igual que TaskFlow creixerà peça a peça.
El recorregut complet, vist com a itinerari:
graph LR
L[Llistes<br/>M2] --> P[Piles<br/>M3] --> C[Cues<br/>M4] --> H[Taules hash<br/>M5] --> A[Arbres<br/>M6] --> G[Grafs<br/>M7]
Recorda que aquesta lliçó és només el mapa: la definició precisa de cada estructura, les seves operacions, implementacions i costos es desenvolupen al mòdul corresponent.
Les estructures natives de Python: el nostre punt de partida
Python incorpora de sèrie quatre estructures de dades que farem servir constantment, tant per si mateixes com per construir les estructures del catàleg. Convé tenir clar el paper de cadascuna:
| Estructura | Sintaxi | Ordenada? | Mutable? | Duplicats? | Ús típic |
|---|---|---|---|---|---|
list |
[1, 2, 3] |
Sí (per posició) | Sí | Sí | Seqüències que canvien |
tuple |
(1, 2, 3) |
Sí (per posició) | No | Sí | Registres fixos, constants |
dict |
{"a": 1} |
Per inserció | Sí | Claus no | Associacions clau → valor |
set |
{1, 2, 3} |
No | Sí | No | Pertinença i unicitat |
("Mutable" significa que es pot modificar després de creada; "ordenada", que els seus elements mantenen un ordre definit.)
Vegem-les en acció amb dades de TaskFlow:
# list: l'esborrany del tauler — ordre i canvis constants
tauler = ["Dissenyar el logo", "Escriure l'informe", "Enviar la factura"]
tauler.append("Trucar al client") # creix dinamicament
# tuple: els estats possibles — un conjunt FIX que ningu no ha de tocar
ESTATS = ("pendent", "en curs", "feta")
# ESTATS.append("altre") -> AttributeError: les tuples no canvien
# dict: una tasca com a registre heterogeni amb camps amb nom
tasca = {"id": 7, "titol": "Enviar la factura", "estat": "pendent"}
print(tasca["titol"]) # acces per clau, no per posicio
# set: etiquetes uniques usades al projecte — sense duplicats
etiquetes = {"urgent", "client", "urgent"}
print(etiquetes) # {'urgent', 'client'} — el duplicat desapareixPunts que convé destacar de l'exemple:
tauler.append(...)mostra la naturalesa dinàmica delist: creix sense declarar mida.ESTATScom a tupla és la tria estàtica i immutable correcta per a dades que no han de canviar; si algú intenta modificar-la, Python llança un error, protegint el programa. La convenció d'escriure-la en majúscules assenyala "això és una constant".- El
setha eliminat el duplicat"urgent"automàticament: la unicitat forma part del seu contracte. - Aquestes quatre estructures són, en termes de la lliçó 01-01, implementacions molt polides de certs TAD:
listd'una seqüència dinàmica,dictd'una taula associativa,setd'un conjunt matemàtic. En els propers mòduls les farem servir tant directament com de "material de construcció" per implementar piles, cues, arbres i grafs.
I les estructures que Python no porta de sèrie (llistes enllaçades, arbres, grafs)? Les construirem nosaltres amb classes, exactament com vam fer amb PilaAmbLlista a la lliçó 01-01. Aquí hi ha bona part del valor del curs: no només usar estructures, sinó saber fabricar-les.
Errors Comuns i Consells
- Usar
listper a tot. És el vici número u del principiant en Python: la llista és tan còmoda que es converteix en martell universal. Abans d'escriure[], pregunta't: necessito ordre? (si no, potserset), hi accedeixo per nom? (potserdict), les dades són fixes? (potsertuple). - Confondre la sintaxi de
dictiset. Tots dos usen claus:{"a": 1}és un diccionari (téclau: valor),{"a", "b"}és un conjunt (només valors). I compte:{}a seques crea un diccionari buit; per a un conjunt buit cal escriureset(). - Creure que les classificacions són compartiments rígids. Són eixos d'anàlisi, no calaixos excloents: una mateixa estructura es pot descriure des dels tres eixos alhora (una
listde Python és lineal, dinàmica i potencialment heterogènia), i les taules hash no encaixen del tot en l'eix lineal/no lineal. - Consell: quan trobis una estructura nova en qualsevol llenguatge o llibreria (un
deque, unDataFrame, unTreeMapde Java...), situa-la en els tres eixos d'aquesta lliçó i busca a quin TAD respon. És la manera més ràpida de "llegir" una estructura desconeguda.
Exercicis
Exercici 1: classificar estructures
Classifica cada escenari segons els eixos vistos (lineal/no lineal; i on tingui sentit, estàtica/dinàmica i homogènia/heterogènia):
- Els mesos de l'any en una aplicació de calendari.
- L'organigrama d'una empresa.
- La cua d'impressió d'una oficina.
- Les connexions d'amistat d'una xarxa social.
Exercici 2: triar l'estructura nativa
Per a cada necessitat de TaskFlow, tria l'estructura nativa de Python més adequada (list, tuple, dict o set) i justifica-ho en una frase:
- Els dies de la setmana en què es poden programar recordatoris (de dilluns a diumenge, fixos).
- Els ids de les tasques que l'usuari ha marcat com a preferides (sense repetits, sense ordre rellevant).
- La correspondència entre cada usuari i la seva llista de projectes.
- L'historial de títols de tasques consultades, en ordre, amb possibles repeticions.
Exercici 3: compondre estructures
Escriu en Python la representació d'un minitauler de TaskFlow amb aquests requisits: hi ha d'haver tres columnes fixes d'estat (pendent, en curs, feta); cada columna conté les seves tasques en ordre; cada tasca té id, titol i un conjunt d'etiquetes sense duplicats. Crea el tauler amb almenys dues tasques i escriu una línia de codi que afegeixi una etiqueta a una tasca existent. Indica quina estructura nativa has usat per a cada nivell i per què.
Solucions
Solució 1:
- Mesos de l'any: lineal (seqüència amb ordre), estàtica (sempre són 12) i homogènia (tots cadenes). En Python, una tupla seria el més natural.
- Organigrama: no lineal, jeràrquic (cada persona té un responsable i pot tenir diversos subordinats): la forma d'un arbre. Dinàmica (la plantilla canvia).
- Cua d'impressió: lineal i dinàmica; l'ordre d'arribada és la relació essencial (FIFO). Homogènia (tot són treballs d'impressió).
- Amistats: no lineal, en xarxa (cada persona es connecta amb moltes altres sense jerarquia): la forma d'un graf. Dinàmica.
Solució 2:
tuple: col·lecció fixa i ordenada que no s'ha de modificar:DIES = ("dilluns", ..., "diumenge").set: unicitat garantida i pertinença ràpida; l'ordre no importa:preferides = {4, 8, 15}.dict: associació clau → valor, amb l'usuari com a clau i la seva llista de projectes com a valor:{"anna": ["web", "app"]}(fixa-t'hi: undictque contélist, composició d'estructures).list: seqüència ordenada, dinàmica i amb duplicats permesos: exactament el contracte de la llista.
Solució 3:
tauler = {
"pendent": [
{"id": 1, "titol": "Dissenyar el logo", "etiquetes": {"disseny", "client"}},
{"id": 2, "titol": "Enviar la factura", "etiquetes": {"admin"}},
],
"en curs": [],
"feta": [],
}
# Afegir una etiqueta a la tasca amb id 1 (primera de "pendent"):
tauler["pendent"][0]["etiquetes"].add("urgent")Justificació per nivells: un dict per a les columnes (accés per nom d'estat); una list per columna (les tasques mantenen un ordre i la col·lecció creix i minva); un dict per tasca (registre heterogeni amb camps amb nom); un set per a les etiquetes (unicitat automàtica). Quatre estructures natives component-se per modelar un domini real. Nota: les tres claus d'estat són fixes, però un dict és l'opció pràctica per accedir per nom; la immutabilitat de "només hi ha tres estats" la reforçarem amb altres tècniques més endavant.
Conclusió
Ja tens el mapa complet: les estructures es classifiquen segons com es relacionen els seus elements (lineals com llistes, piles i cues; no lineals com arbres i grafs; associatives com les taules hash), segons si la seva mida és fixa o variable (estàtiques vs dinàmiques) i segons si barregen tipus (homogènies vs heterogènies). Saps quin paper jugarà cadascuna a TaskFlow i comptes amb les quatre estructures natives de Python —list, tuple, dict, set— com a material de partida i de construcció.
Però al mapa li falta una dimensió: els números. Hem dit que la taula hash cerca "a l'instant" i que la llista "ho recorre tot"... com s'expressa això amb precisió, de manera que puguem comparar estructures rigorosament? Aquest és el propòsit de la propera lliçó: la notació Big O, el llenguatge universal per parlar d'eficiència que farem servir durant tota la resta del curs.
Curs d'Estructures de Dades
Mòdul 1: Introducció a les Estructures de Dades
- Què són les Estructures de Dades?
- Importància de les Estructures de Dades en la Programació
- Tipus d'Estructures de Dades
- Complexitat Algorísmica i Notació Big O
- Arrays i Memòria: la Base de les Estructures de Dades
Mòdul 2: Llistes
- Introducció a les Llistes
- Llistes Enllaçades
- Llistes Doblement Enllaçades
- Llistes Circulars
- Exercicis amb Llistes
Mòdul 3: Piles
- Introducció a les Piles
- Operacions Bàsiques amb Piles
- Implementació de Piles
- Aplicacions de les Piles
- Exercicis amb Piles
Mòdul 4: Cues
- Introducció a les Cues
- Operacions Bàsiques amb Cues
- Cues Circulars
- Cues de Prioritat
- Cues Dobles (Deques)
- Exercicis amb Cues
Mòdul 5: Taules Hash i Diccionaris
- Introducció a les Taules Hash
- Funcions Hash i Resolució de Col·lisions
- Diccionaris i Conjunts a la Pràctica
- Exercicis amb Taules Hash
Mòdul 6: Arbres
- Introducció als Arbres
- Arbres Binaris
- Recorreguts d'Arbres
- Arbres Binaris de Cerca
- Arbres AVL
- Arbres B
- Monticles (Heaps)
- Exercicis amb Arbres
Mòdul 7: Grafs
- Introducció als Grafs
- Representació de Grafs
- Algorismes de Cerca en Grafs
- Algorismes de Camins Mínims
- Arbres d'Expansió Mínima
- Aplicacions dels Grafs
- Exercicis amb Grafs
