UNIVERSIDAD DE CARABOBO FACULTAD EXPERIMENTAL DE CIENCIAS Y TECNOLOGÍA DEPARTAMENTO DE COMPUTACIÓN ALGORITMOS Y PROGRAMACIÓN II TEMA 6 ESTRUCTURAS MULTIENLAZADAS Matrices Esparcidas Abril, 2005 Matrices Esparcidas: Definiciones y Conceptos Básicos En diversas aplicaciones que involucran matrices puede darse el caso que muchos elementos de la matriz sean no significativos. Este tipo de matrices, cuyo contenido está formado en su mayoría por elementos no significativos, se denomina matriz esparcida. Utilizando la representación enlazada es posible almacenar solamente los elementos significativos de la matriz, lo que resultaría en un ahorro de espacio en memoria. La estructura es la siguiente: Para permitir el acceso a cualquier fila o columna de la matriz, cada elemento significativo de la matriz aparece en dos listas, una para su fila y otra para su columna. Cada nodo contiene dos apuntadores, uno al elemento significativo siguiente en su fila y otro para el elemento significativo siguiente en su columna. Además, cada nodo contiene campos con el índice de su fila, el índice de su columna y el valor del elemento. Por lo tanto, cada nodo presenta la siguiente estructura: • • • • • elem: Valor del elemento en esa posición de la matriz. fila: Indice de la fila en esa posición de la matriz. col: Indice de la columna en esa posición de la matriz. sig_fila: apuntador al siguiente nodo en la misma fila. sig_col: apuntador al siguiente nodo en la misma columna. La representación gráfica de un nodo de una matriz esparcida puede apreciarse en la figura 1. El significado de cada campo es el descrito con anterioridad. fila sig_col col elem sig_fila Figura 1: Campos de un nodo Considere, por ejemplo, una matriz M de números reales en la cual la mayoría de sus elementos son iguales a cero. 0 2.5 0 1.0 0 0 0 1.3 2.1 0 M= 3.4 0 0 0.2 0 0 0 0 0 7.6 La matriz esparcida correspondiente a M se define gráficamente como se muestra en la figura 2. 1 1 1 2 1 1.0 2 2 3 3 3 1 3.4 2 1.3 2 4 1 4 2.5 3 4 0.2 5 3 2.1 4 4 5 7.6 Figura 2: Representación de una matriz M de números reales en forma encadenada ESPECIFICACIÓN ALGEBRÁICA Sintaxis vacía : agregar_elem : eliminar _elem: existe_elem : modificar_elem : consultar_elem : num_filas: num_cols: existe_fila: existe_col: Mat_Esp × Elemento × Natural × Natural Mat_Esp × Natural × Natural Mat_Esp × Natural × Natural Mat_Esp × Elemento × Natural × Natural Mat_Esp × Natural × Natural Mat_Esp Mat_Esp Mat_Esp × Natural Mat_Esp × Natural ESPECIFICACIÓN O PERACIONAL Semántica { Pre: } proc vacía (var M: Mat_Esp) { Post: M´es una matriz esparcida vacía } → → → → → → → → → → Mat_Esp Mat_Esp Mat_Esp Logical Mat_Esp Elemento Natural Natural Logical Logical { Pre: existe_fila(M,i) ∧ existe_col(M,,j) ∧ ¬existe(M, i, j) } proc agregar (var M : Mat_Esp; e : Elemento; i, j : Integer) { Post: M´ es una matriz esparcida tal que existe(M', i, j) ∧ (consultar(M', i, j) = e) } { Pre: existe(M, i, j) } proc eliminar (var M : Mat_Esp; i, j : Integer) { Post: M´es una matriz esparcida tal que ¬existe(M', i, j) } { Pre: } func existe (M : Mat_Esp; i, j : Integer) : Logical; { Post: existe ← ∃i ∃j (consultar(M, i, j) = elemento significativo } { Pre: existe(M, i, j) } proc modificar (M : Mat_Esp; e : Elemento; i, j : Integer) : Mat_Esp; { Post: M´es una matriz esparcida tal que (consultar(M', i, j) = e) } { Pre: existe(M, i, j) } func consultar (M : Mat_Esp; i, j : Integer) : Elemento; { Post: consultar ← Mij } Implementación de la class Mat_Esp Representación Estática En esta implementación se utilizan arreglos para manejar los índices de las filas y columnas de la matriz. Además, se supone que se cumplen todas las precondiciones planteadas en la especificación pre/post de cada operación. class nodo begin private: elem fila col sig_fila sig_col : : : : : elemento; integer; integer; pointer to nodo; pointer to nodo; public: nodo(); ~nodo(); end Func Func Func Func Func get_elem() get_fila() get_col() get_sig_fil() get_sig_col() proc proc proc proc proc set_elem(in e : elemento); set_fila(in ind : integer); set_col(in ind : integer); set_sig_fila(in p : pointer to nodo); set_sig_col(in p : pointer to nodo); : : : : : elemento; integer; integer; pointer to nodo; pointer to nodo; nodo::nodo() begin fila col sig_fila sig_col end = = = = 0; 0; NULL; NULL; Func nodo::get_elem() : elemento begin return elem; end Func nodo::get_fila() : integer begin return fila; end Func nodo::get_col() : integer begin return col; end Func nodo::get_sig_fil() : pointer to nodo begin return sig_fil; end Func nodo::get_sig_col() : pointer to nodo; begin return sig_col; end proc nodo::set_elem(in e : elemento) begin elem e; end proc nodo::set_fila(in ind : integer) begin fila ind; end proc nodo::set_col(in ind : integer) begin col ind; end proc nodo::set_sig_fila(in p : pointer to nodo) begin sig_fila p; end proc nodo::set_sig_col(in p : pointer to nodo) begin sig_col p; end const MAX_M = ? MAX_N = ? class MatEsp begin private: filas : array [1..MAX_M] of pointer to nodo; columnas : array [1..MAX_N] of pointer to nodo; public: MatEsp(); ~MatEsp(); func existe(in i, j : integer) : logical; func consultar(in i, j : integer) : elemento; func num_filas() : integer; func num_cols() : integer; proc agregar(in e : elemento; in i, j : integer); proc eliminar(in i, j : integer); proc modificar(in e : elemento; in i, j : integer); end MatEsp::MatEsp() begin i : integer; for i in [1..MAX_M] do begin filas[i] NULL; end end for i in [1..MAX_N] do begin columnas[i] NULL; end Agregar un elemento en la i−ésima fila y j−ésima columna Pasos a seguir: • Localizar en la lista asociada a la fila i el primer nodo que contenga un índice de columna mayor que j, referenciando también al nodo anterior si existe. • Insertar el nodo creado en la lista de la fila i en la posición adecuada. • Localizar en la lista asociada a la columna j el primer nodo que contenga un índice de fila mayor que i, referenciando también al nodo anterior si existe. • Insertar el nodo creado en la lista de la columna j en la posición adecuada. proc MatEsp::agregar(in e : elemento; in i, j : integer) begin P, ant, aux : pointer to nodo; log : logical; P ← filas[i]; log ← false; end while (P ≠ NULL) ∧ ¬log do begin if (j < P↑.get_col()) then log ← true else ant ← P; P ← P↑.get_sig_fila() end if end aux = new nodo; aux↑.set_elem(e); aux↑.set_fila(i); aux↑.set_col(j); aux↑.set_sig_fila(P); if (P = filas[i]) then filas[i] ← aux ; else ant↑.set_sig_fila(aux); end if; P ← columnas[j]; log ← false; while (P ≠ NULO) ∧ ¬log do if (i < P↑.get_fila()) then log ← true; else ant ← P; P ← P↑.get_sig_col(); end if end aux↑.set_sig_col(P); if (P = columnas[j]) then columnas[j] ← aux; else ant↑.sig_col ← aux; end if Queda como ejercicio el desarrollo del resto de las operaciones de la class MatEsp Representación Dinámica En esta implementación se utilizan listas para manejar los índices de las filas y columnas de la matriz. Además, se supone que se cumplen todas las precondiciones planteadas en la especificación pre/post de cada operación. class nodo_interno begin private: elem : elemento; sig_fila : pointer to sig_col : pointer to fila : pointer to col : pointer to nodo_interno; nodo_interno; nodo_fila; nodo_columna; public: nodo_interno(); ~nodo_interno(); func func func func func end get_elem() get_sig_fil() get_sig_col() get_fila() get_col() : : : : : elemento; pointer to pointer to pointer to pointer to nodo_interno; nodo_interno; nodo_fila; nodo_columna; proc set_elem(in e : elemento); proc set_sig_fila(in p : pointer to nodo_interno); proc set_sig_col(in p : pointer to nodo_interno); nodo_interno::nodo_interno() begin sig_fila = NULL; sig_col = NULL; end func nodo_interno::get_elem() : elemento begin return elem; end func nodo_interno::get_sig_fil() : pointer to nodo_interno begin return sig_fil; end func nodo_interno::get_sig_col() : pointer to nodo_interno begin return sig_col; end func nodo_interno::get_fila() : pointer to nodo_fila begin return fila; end func nodo_interno::get_col() : pointer to nodo_columna begin return col; end proc nodo_interno::set_elem(in e : elemento) begin elem e; end proc nodo_interno::set_sig_fila(in p : pointer to nodo_interno) begin sig_fila p; end proc nodo_interno::set_sig_col(in p : pointer to nodo_interno) begin sig_col p; end class nodo_fila begin private: info : info_fila; sig_fila : pointer to nodo_fila; prim_nodo : pointer to nodo_interno; public: nodo_fila(); ~ nodo_fila(); func get_info() : info_fila; func get_fila() : integer; func get_sig_fila() : pointer to nodo_fila; func get_prim_nodo() : pointer to nodo_interno; proc set_fila(in inf : integer); proc set_sig_fila(in p : pointer to nodo_fila); proc set_prim_nodo(in p : pointer to nodo_interno); end nodo_fila::nodo_fila() begin info 0; sig_fila NULL; prim_nodo NULL; end func nodo_fila::get_info() : info_fila begin return info; end func nodo_fila::get_fila() : integer begin return info.ind; end func nodo_fila::get_sig_ind() : pointer to nodo_fila begin return sig_fila; end func nodo_fila::get_prim_nodo() : pointer to nodo_interno begin return prim_nodo; end proc nodo_fila::set_fila(in inf : integer) begin info.ind inf; end proc nodo_fila::set_sig_fila(in p : pointer to nodo_fila) begin sig_fila p; end proc nodo_fila::set_prim_nodo (in p : pointer to nodo_interno) begin prim_nodo p; end class nodo_columna begin private: info : info_fila; sig_columna : pointer to nodo_columna; prim_nodo : pointer to nodo_interno; public: nodo_columna(); ~nodo_columna(); func func func func end get_info() get_columna() get_sig_columna() get_prim_nodo() : : : : info_columna; integer; pointer to nodo_columna; pointer to nodo_interno; proc set_columna(in inf : integer); proc set_sig_columna(in p : pointer to nodo_columna); proc set_prim_nodo(in p : pointer to nodo_interno); nodo_columna::nodo_columna() begin info 0; sig_columna NULL; prim_nodo NULL; end func nodo_columna::get_info() : info_columna begin return info; end func nodo_columna::get_columna() : integer begin return info.ind; end func nodo_columna::get_sig_ind() : pointer to nodo_columna begin return sig_columna; end func nodo_columna::get_prim_nodo() : pointer to nodo_interno begin return prim_nodo; end proc nodo_columna::set_columna(in inf : integer) begin info.ind inf; end proc nodo_columna::set_sig_columna(in p : pointer to nodo_columna) begin sig_columna p; end proc nodo_columna::set_prim_nodo (in p : pointer to nodo_interno) begin prim_nodo p; end class MatEsp begin private: filas : pointer to nodo_fila; columnas : pointer to nodo_columna; public: func existe(in i, j : integer) : logical; func consultar(in i, j : integer) : elemento; func num_filas() : integer; func num_cols() : integer; end proc agregar(in e : elemento; in i, j : integer); proc eliminar(in i, j : integer); proc modificar(in e : elemento; in i, j : integer); MatEsp::MatEsp() begin filas NULL; columnas NULL; end Queda como ejercicio el desarrollo del resto de las operaciones de la class MatESP