C/Traballar con listas encadeadas: Diferenzas entre revisións

Contido eliminado Contido engadido
Gallaecio (conversa | contribucións)
m Eliminadas unhas chaves innecesarias.
Gallaecio (conversa | contribucións)
Amplío (continuará...)
Liña 7:
Dende o punto de vista da memoria, a matriz resulta máis eficiente, pois precisa de menos memoria. Pero existen outros factores a ter en conta á hora de comparar matrices e listas encadeadas.
 
Por exemplo, imaxinemos que temotemos unha matriz que conta con, digamos, 30 datos. Agora pensemos que queremos meter un dato adicional tras o segundo dato. No caso da matriz, sería preciso ampliar a matriz e mover en memoria todos os datos que contén a matriz a partires do espazo en que queremos meter o novo dato. Porén, no caso dunha lista encadeada, abondaría con engadir en memoria o novo dato, e simplemente modificar o dato anterior de xeito que apunte ao novo dato, así como facer que o novo dato apunte ao seguinte dato.
 
É dicir, en casos en que se sabe que se van ir introducindo e borrando datos en distintas posicións que non van ser sempre a última (como se faría no caso das matrices), será máis eficiente traballar con listas encadeadas, pois este tipo de operacións con matrices resultarían, como mínimo, pouco útiles.
 
==Tipos==
Existen distintos tipos de listas encadeadas, que fundamentalmente consisten no mesmo, pero que difiren na súa función, e por tanto tamén difiren lixeiramente na forma en que se traballa con elas. Así, segundo o que vaiamos facer con elas, falaremos de:
 
;Lista encadeada simple
:Este tipo de lista sempre está ordenada por un dos datos dos seus elementos.
 
;Pila
:É un contedor de datos non ordenados, que simplemente se van introducindo ao principio da pila, en lugar de ao final ─que é como se faría no caso das matrices─. É por iso que nas funcións que traballar con pilas non se fornece nunca un dato a buscar, xa que sempre se traballa co primeiro dato da pila.
:As funcións das pilas son catro:
:*engadir elementos á pila,
:*borrar elementos da pila,
:*gravar a pila en disco e
:*eliminar a pila.
 
;Cola
:Ao igual que as pilas, tampouco está ordenada por ningún dos datos dos seus elementos. A diferencia con respecto ás pilas é que, mentres que nas pilas se traballa co último elemento engadido á mesma, no caso das colas sempre se traballará co último elemento, é dicir, se traballará cos seus elementos en orde de chegada.
:Isto significa que para traballar con colas teremos que ter non só o enderezo en memoria do primeiro elemento, senón tamén o enderezo do último dos seus elementos. O primeiro valerá para introducir novos datos, e o segundo para traballar cos datos e borralos unha vez se utilicen.
 
==Declaración==
Para declarar unha lista encadeada cómpre ter claro previamente o comportamento das [[{{BASEPAGENAME}}/Estruturas|estruturas]]. Cada elemento da lista ─elemento─ será unha estrutura conformada polos datos do elemento e un punteiro a unha estrutura do mesmo tipo, que será o que apunte ao seguinte elemento (salvo que se trate do derradeiroúltimo elemento da lista encadeada).
 
Por suposto, necesitaremos ademais dos elementos un punteiro solto que apunte ao primeiro elemento da lista encadeada., Estae en caso de que traballemos cunha cola, será anecesario únicatamén variableun localsegundo punteiro que sinale ao último elemento. Estes punteiros serán as únicas variables locais, é dicir, aas únicaúnicas que non se vaivan reservar en memoria dinámica. Cómpre ''inicializar'' esteestes punteiro ao primeiro elementopunteiros cocon valor nulo, de xeito que isto permita saber que a lista está, en principio, baleira.
 
==Traballo con listas==
Liña 30 ⟶ 48:
De xeito que se poida acceder a todos os elementos da lista, pero non se poida modificar o valor do punteiro da lista, é dicir, o punteiro ao primeiro elemento.
 
===Engadir unelementos elementoás á listalistas===
====Crear un elemento====
Para crear elementos para a lista, farase xeralmente un a un a través dunha función como a seguinte:
Antes de engadir un elemento a unha lista será necesario crealo, é dicir, facerlle espazo en memoria, xeralmente un a un a través dunha función como a seguinte:
<source lang=c>
estrutura * CrearUnElemento(void)
Liña 45 ⟶ 64:
</source>
 
O programa que chamase á función debería controlar o valor que devolvese a función, e en caso de ser o punteiro nulo, actuar en consecuencia. Agora imaxinemos que a estrutura dos elementos da lista, ademais de conter o punteiro que sinala ao seguinte elemento na lista encadeada, contén un <code>signed int</code>, que será o verdadeiro contido do elemento. Nese caso, para introducir novos datos na lista encadeada utilizaríase unha función como a seguinte:
 
====Engadir un elemento a unha lista simple====
Imaxinemos unha lista encadeada simple en que os seus elementos conteñen só un dato de tipo <code>signed int</code> ─ademais de conter o punteiro que sinala ao seguinte elemento da lista─. Isto simplificará o exemplo, pero valerá para ilustrar calquera caso. Para introducir novos datos nesta lista encadeada simple de exemplo utilizaríase unha función como a seguinte:
<source lang=c>
signed short int InserirUnDatoInserirUnElemento(estrutura ** punteiro, signed int dato)
{
// Declaración de variables
Liña 81 ⟶ 103:
</source>
 
Cómpre ter en conta que este é o programa base á hora de engadir novos datos a unha lista encadeada simple e, xa que logo, pode ser que o programador queira modificalo para personalizalo. E por suposto, será necesario facer polo menos as modificacións necesarias para que a función se adapte a un tipo de elemento distinto ─cuxo contido non sexa un simple <code>signed int</code>─.
 
====Engadir un elemento a unha pila====
===Borrar elementos da lista===
Imaxinemos unha pila en que os seus elementos conteñen só un dato de tipo <code>signed int</code> ─ademais de conter o punteiro que sinala ao seguinte elemento na pila─. Isto simplificará o exemplo, pero valerá para ilustrar calquera caso. Para introducir novos datos nesta pila de exemplo utilizaríase unha función como a seguinte:
Para borrar elementos da lista, utilizarase unha función como a seguinte (partindo do suposto anterior dunha estrutura con dato <code>signed int</code>):
<source lang=c>
signed short int BorrarUnDatoInserirUnElemento(estrutura ** punteiro, signed int dato)
{
// Declaración de variables
estrutura * pila = NULL;
estrutura * novo = NULL;
 
// Recíbese a pila.
pila = *punteiro;
 
// Créase espazo en memoria para un novo elemento (esta función viuse máis arriba).
novo = CrearUnElemento();
if(novo == NULL)
{
printf("Non se puido reservar espazo para un novo elemento.\n");
return -1;
}
// Almacénanse os datos no novo elemento (neste exemplo só un dato).
novo->dato = dato;
 
// Apúntase o enderezo do seguinte elemento no novo elemento.
novo->seguinte = pila;
 
// Facer que o punteiro da pila apunte ao novo elemento, que será o primeiro.
*punteiro = novo;
 
return 0; // Saída correcta da función.
}
</source>
 
Cómpre ter en conta que este é o programa base á hora de engadir novos datos a unha pila e, xa que logo, pode ser que o programador queira modificalo para personalizalo. E por suposto, será necesario facer polo menos as modificacións necesarias para que a función se adapte a un tipo de elemento distinto ─cuxo contido non sexa un simple <code>signed int</code>─.
 
====Engadir un elemento a unha cola====<!-- Sen completar. -->
Imaxinemos unha pila en que os seus elementos conteñen só un dato de tipo <code>signed int</code> ─ademais de conter o punteiro que sinala ao seguinte elemento na cola─. Isto simplificará o exemplo, pero valerá para ilustrar calquera caso. Para introducir novos datos nesta cola de exemplo utilizaríase unha función como a seguinte:
<source lang=c>
signed short int InserirUnElemento(estrutura ** punteiro, signed int dato)
{
// Declaración de variables
estrutura * pila = NULL;
estrutura * novo = NULL;
 
// Recíbese a pila.
pila = *punteiro;
 
// Créase espazo en memoria para un novo elemento (esta función viuse máis arriba).
novo = CrearUnElemento();
if(novo == NULL)
{
printf("Non se puido reservar espazo para un novo elemento.\n");
return -1;
}
// Almacénanse os datos no novo elemento (neste exemplo só un dato).
novo->dato = dato;
 
// Apúntase o enderezo do seguinte elemento no novo elemento.
novo->seguinte = pila;
 
// Facer que o punteiro da pila apunte ao novo elemento, que será o primeiro.
*punteiro = novo;
 
return 0; // Saída correcta da función.
}
</source>
 
Cómpre ter en conta que este é o programa base á hora de engadir novos datos a unha pila e, xa que logo, pode ser que o programador queira modificalo para personalizalo. E por suposto, será necesario facer polo menos as modificacións necesarias para que a función se adapte a un tipo de elemento distinto ─cuxo contido non sexa un simple <code>signed int</code>─.
 
===Borrar elementos das listas===
====Borrar un elemento dunha lista simple====
Para borrar un elemento dunha lista encadeada simple, utilizarase unha función como a seguinte, sempre partindo do exemplo anterior dunha estrutura cun único dato <code>signed int</code> ─ademais do punteiro ao seguinte elemento da lista─:
<source lang=c>
signed short int BorrarUnElemento(estrutura ** punteiro, signed int dato)
{
// Declaración de variables
Liña 118 ⟶ 211:
}
</source>
 
====Sacar un elemento dunha pila====
Para sacar un elemento dunha pila, que será sempre o primeiro elemento desta dada a súa natureza, utilizarase unha función como a seguinte, sempre partindo do exemplo anterior dunha estrutura cun único dato <code>signed int</code> ─ademais do punteiro ao seguinte elemento da lista─:
<source lang=c>
signed int BorrarUnElemento(estrutura ** punteiro)
{
// Declaración de variables
estrutura * pila = NULL;
signed int dato;
 
// Recíbese a pila en “pila”, o punteiro ao que apunta “punteiro”.
pila = *punteiro;
 
// Grávase o dato do elemento a borrar nunha variable local.
dato = pila->dato;
 
// Ponse o inicio da pila no seguinte elemento da mesma.
*punteiro = pila->seguinte;
 
// Libérase o espazo en memoria do elemento a borrar.
free(pila);
 
// Devolución do dato que contiña o elemento borrado.
return dato;
}
</source>
 
Nótese que nunha pila non ten sentido borrar un elemento se non é para traballar con el e logo borralo, emporiso que a operación de borrado devolve o dato borrado en vez de recibir o dato que se quere borrar.
 
==Véxase tamén==