Está en la página 1de 32

7 Informática (Teorı́a)

Python: Listas, Miscelanea

Joaquim Gabarro
gabarro@cs.upc.edu

Computer Science
Universitat Politècnica de Catalunya
Copias Frescas

Ordenación (Sorting)

Operaciones con matrices

Apéndice: Merge Sort


Copias Frescas
Cuidado con las asignaciones

Hay que ir con cuidado si queremos copiar el contenido de una


lista L en una ‘’nueva” lista M.
>>> L=[1,2,3]
>>> L
[1, 2, 3]
>>> M=L
>>> M
[1, 2, 3]
>>> M[0]=5 #Modificamos el contenido de M
>>> M
[5, 2, 3]
>>> L #el contenido de L tambien se ha modificado.
[5, 2, 3]

Si queremos conservar el contenido inicial de L = [1,2,3],


la assignación M=L no es una buena idea.
Copia (I)
Creamos una lista nueva vacia M=[ ] y añadimos los
elementos uno a uno con append (fichero copy.py)
def copy(L):
M=[]
for e in L:
M.append(e)
return M

Ejemplo:
>>> L=[1,2,3]
>>> M=copy(L)
>>> M
[1, 2, 3]
>>> M[0]=5
>>> M
[5, 2, 3]
>>> L
[1, 2, 3]
Copia (II)

Utilizar el for e in L en list comprehension:


>>> L=[1,2,3]
>>> M= [e for e in L]
>>> M
[1, 2, 3]
>>> M[0]=5
>>> M
[5, 2, 3]
>>> L
[1, 2, 3]

La notación M= [e for e in L] es “parecida” a la de teorı́a


de conjuntos. Por ejemplo, dado un conjunto A, si queremos
otro conjunto B con los mismos elementos escribimos
B = {e | e ∈ A}.
Copia (III)

Utilizar el extend:
>>> L=[1,2,3]
>>> M=[]
>>> M.extend(L)
>>> M
[1, 2, 3]
>>> M[0]=5
>>> M
[5, 2, 3]
>>> L
[1, 2, 3]
Ordenación (Sorting)
Build-in functions
https://docs.python.org/3/howto/sorting.html
For a simple ascending sort call sorted(). It returns a new
sorted list
>>> L= sorted([5, 2, 3, 1, 4])
>>> L
[1, 2, 3, 4, 5]

You can use list.sort(). It modifies the list in-place


(returns None).
>>> L = [5, 2, 3, 1, 4]
>>> M=L.sort()
>>> L
[1, 2, 3, 4, 5]
>>> M
>>> type(M)
<class ’NoneType’>
Both list.sort() and sorted() accept a reverse
parameter with a boolean value.
This is used to flag descending sorts.

>>> L= sorted([5, 2, 3, 1, 4], reverse=True)


>>> L
[5, 4, 3, 2, 1]
>>> L=[5, 2, 3, 1, 4]
>>> L.sort(reverse=True)
>>> L
[5, 4, 3, 2, 1]
Insertion sort
Queremos ordenar [44, 55, 12, 42, 94, 18, 06, 67]

[44 | 55, 12, 42, 94, 18, 06, 67]


[44, 55 | 12, 42, 94, 18, 06, 67]
[12, 44, 55 | 42, 94, 18, 06, 67]
[12, 42, 44, 55 | 94, 18, 06, 67]
[12, 42, 44, 55, 94 | 18, 06, 67]
[12, 18, 42, 44, 55, 94 | 06, 67]
[06, 12, 18, 42, 44, 55, 94 | 67]
[06, 12, 18, 42, 44, 55, 67, 94 |]

Tenemos:

[ parte ordenada | parte para ordernar ]


Como una lista con un solo elemento ya está ordenada,
comenzamos con:

[44 | 55, 12, 42, 94, 18, 06, 67]

con lo que el for tiene el rango range(1,len(L))

def insertion_sort(L):
for i in range(1,len(L)):
x = L[i]
insertar x en la posicion adecuada en L[:i-1]

No hay return L, modifica L directamente.


Como se dice in inglés: It modifies the list in-place. Usually it’s
less convenient - but if you don’t need the original list, can be
slightly more efficient.
Por ejemplo, cuando i=5, tenemos x = L[5] = 18. La frase

insertar x en la posicion adecuada en L[:i-1]

se traduce en

insertar 18 en la posición adecuada en [12,42,44,55,94]

lo que equivale a pasar de la lista:

[12, 42, 44, 55, 94 | 18, 06, 67]

a la lista:

[12, 18, 42, 44, 55, 94 | 06, 67

veamos como lo hacemos


Comparamos el 18 con los elementos de
[12, 42, 44, 55, 94] y vamos invirtiendo mientras sea necesario

[12, 42, 44, 55, (94, 18) | 06, 67]


[12, 42, 44, (55, 18), 94 | 06, 67]
[12, 42, (44, 18), 55, 94 | 06, 67]
[12, (42, 18), 44, 55, 94 | 06, 67]
[(12, 18), 42, 44, 55, 94 | 06, 67]
[ 12, 18, 42, 44, 55, 94 | 06, 67]

En la página siguiente un código basado en esta idea:


Fichero insertion sort.py.

def insertion_sort(L):
for i in range(1,len(L)):
x = L[i]
j = i
while j>0 and L[j-1]>x:
L[j], j = L[j-1], j-1
L[j]=x

Atención: notad que no hay return.


El programa reordena la lista de entrada L.

>>> L = [54,26,93,17,77,31,44,55,20]
>>> print(L)
[54, 26, 93, 17, 77, 31, 44, 55, 20]
>>> M= insertion_sort(L)
>>> print(M)
None
>>>
>>> print(L)
[17, 20, 26, 31, 44, 54, 55, 77, 93]
No tocar L
Copiamos L en M y ordenamos M con insertion sort.py.
Fichero other insertion sort.py
def insertion_sort(L):
...

def other_insertion_sort(L):
M=[i for i in L]
insertion_sort(M)
return M

Ejemplo:
>>> L = [54,26,93,17,77,31,44,55,20]
>>> L1=other_insertion_sort(L)
>>> L1
[17, 20, 26, 31, 44, 54, 55, 77, 93]
>>> L
[54, 26, 93, 17, 77, 31, 44, 55, 20]
>>>
Operaciones con matrices
Ejemplo: Producto de Matrices

I Dadas dos matrices A = (ai,j ) de dimensiones p × q y


B = (bi,j ) de dimensiones q × r
I El producto se define como una matrix C = A ∗ B = (ci,j )
de dimensiones p × r tal que
X
ci,j = ai,k ∗ bk,j
k

Comentario: Es un clásico. Lo he encontrado en mi manual de


Fortran de los setenta.
Preguntad a vuestros padres y abuelos.
Dadas A = (ai,j ) y B = (bi,j ) de dimensiones 2 × 3 y 3 × 4
 
  1 2 1 0
1 2 1
A= , B= 0 1 1 0 
3 1 0
2 1 0 1

la matrix C = A ∗ B = (ci,j ) tiene dimensiones 2 × 4


 
3 5 3 1
C=
3 7 4 0

Por ejemplo:

 1
c1,2 = 3 1 0 ∗ 1 =3∗1+1∗1+0∗0=4
0
Solución (I)
Aplicando las ideas de mas uno.py de la clase anterior
obtenemos mat mult.py

def mat_mult(A,B):
p,q,r = len(A), len(A[0]), len(B[0])
C=[]
for i in range(p):
fila=[]
for j in range(r):
s=0
for k in range(q):
s=s+A[i][k]*B[k][j]
fila.append(s)
C.append(fila)
return C
Solución (II)

En lenguajes como C++ se declara y crea la matrix C antes de


comenzar con el triple for.
En mat mult withzeros.py nos inspiramos en esta idea.
Creamos inicialmente C llenandola de zeros.

def mat_mult (A, B):


p,q,r = len(A), len(A[0]), len(B[0])
C = [[0 for j in range(r)] for i in range(p)]
for i in range(p):
for j in range(r):
for k in range(q):
C[i][j] += A[i][k]*B[k][j]
return C
Ejemplo: transposición de matrices

Dadas M = (mi,j ) de dimensiones p × q

La matrix traspuesta MT = T = (ti,j ) tiene dimensiones q × p y


cumple ti,j = mj,i

Ejemplo:
 
  1 4
1 2 3
M= , MT =  2 5 
4 5 6
3 6
Solucion (I)

I Creamos una primera versión de MT = T de dimensiones


q × p y la llenamos con None.
I Recorremos T y le reasignamos el valor correcto.
Fichero mat-transposition.py
def transpose(M):
p,q = len(M), len(M[0])
T=[[None for j in range(p)] for i in range(q)]
for i in range(q):
for j in range(p):
T[i][j]=M[j][i]
return T
Solución (II)

The hecho podemos crear directamente la matriz traspuesta

Fichero mat transpositions list comp.py

def transpose(M):
p,q = len(M), len(M[0])
T=[[M[j][i] for j in range(p)] for i in range(q)]
return T
Apéndice: Merge Sort
merge sort(L)

When L has more than one item:


I Split L= [54,26,93,17,77,31,44,55,20] into two
sublists
left=[54,26,93,17], right= [77,31,44,55,20]
I merge sort(first) orders first in place. The result is
first =[17,26,54,93]
I merge sort(second) orders second in place. The
result is second= [20,31,44,55,77]
I merge first and second into

[17,20,26,31,44,54,55,77,93]
Fichero merge sort.py

def merge_sort(L):
print("split", L)
if len(L)>1:
mid = len(L)//2
left,right = L[:mid],L[mid:]
merge_sort(left)
merge_sort(right)
merge (left, right, L)

En la siguiente transparencia tenemos la definición de:

merge (left, right, L)


def merge (left, right, L):
i,j,k = 0,0,0
while i < len(left) and j < len(right):
if left[i] < right[j]:
L[k] = left[i]
i = i+1
else:
L[k] = right[j]
j = j+1
k = k+1

while i < len(left):


L[k] = left[i]
i = i+1
k = k+1

while j < len(right):


L[k]=right[j]
j = j+1
k = k+1

print("merge", L)
Ejecutando:
def main():
L = [54,26,93,17,77,31,44,55,20]
print(L)
merge_sort(L)
print(L)

Obtenemos la siguiente “traza”:


[54, 26, 93, 17, 77, 31, 44, 55, 20]
split [54, 26, 93, 17, 77, 31, 44, 55, 20]
split [54, 26, 93, 17]
split [54, 26]
split [54]
split [26]
merge [26, 54]
split [93, 17]
split [93]
split [17]
merge [17, 93]
merge [17, 26, 54, 93]
split [77, 31, 44, 55, 20]
split [77, 31]
split [77]
split [31]
merge [31, 77]
split [44, 55, 20]
split [44]
split [55, 20]
split [55]
split [20]
merge [20, 55]
merge [20, 44, 55]
merge [20, 31, 44, 55, 77]
merge [17, 20, 26, 31, 44, 54, 55, 77, 93]
[17, 20, 26, 31, 44, 54, 55, 77, 93]

También podría gustarte