Introdução as Técnicas de Desenvolvimento de Algoritmos
7 Matrizes
“ Vamos mudar a nossa atitude tradicional de construir programas. Em vez de imaginar que a nossa
tarefa principal é instruir um computador a fazer o que queremos, deveremos começar a pensar que
a nossa tarefa é explicar a seres humanos o que nós queremos que o computador faça”
- Donald E. Knuth -
Sumário:
6.1- Conceitos
6.2- Passagem de Parâmetros
6.3- Operações Iterativas com Matrizes
6.4- Operações recursivas com Matrizes
6.7- Recomendações Bibliográficas
6.8- Exercícios Propostos
6.1- Conceitos
Vimos que um vector era um conjunto finito de elementos do mesmo tipo. Mas
se cada elemento desse vector fosse um outro vector, teríamos necessariamente
um vector de vectores. Uma matriz é um vector de vectores, ou seja, um vector
bidimensional.
Como uma matriz é representada por um conjunto bidimensional, então
devemos especificar as duas dimensões na sua declaração, ou seja, o número
de linhas e o número de colunas. Por exemplo, uma matriz com elementos do
tipo inteiro com 4 linhas e 6 colunas é declarada como:
int a[M][N];
onde
#define M 4
#define N 6
Para aceder a qualquer elemento de uma matriz, utilizamos uma variável com
indexação dupla, denotada por a[i][j], para 0 ≤ i < M e 0 ≤ j < N.
Faculdade de Engenharia de Universidade Católica de Angola - Prof. Manuel Menezes 72
Introdução as Técnicas de Desenvolvimento de Algoritmos
Mas, para acedermos a todos os elementos de uma matriz, devemos utilizar
laços aninhados, ou seja, um laço dentro de outro laço. Se quisermos percorrer
por linhas, o laço externo percorre a matriz por linhas e, para cada linha, o laço
interno percorre a matriz por colunas. Um segmento de código para representar
esse percurso é descrito a seguir:
int i, j;
for ( i = 0 ; i < M ; i++) /* percorre por linhas */
for ( j = 0 ; j < N ; j++) /* percorre por colunas */
6.2- Passagem de Parâmetros
Como a memória do computador é linear, as matrizes são armazenadas na
memória do computador em linhas. Os primeiros espaços de memória, estão
associados a primeira linha, os espaços seguintes a segunda linha e por aí em
diante. Por esse facto, quando declaramos uma matriz como parâmetro de uma
função, apenas devemos especificar o número máximo de colunas.
6.3- Operações Iterativas com Matrizes
6.3.1- Imprimir os Elementos de uma Matriz
A operação para imprimir todos os elementos de uma matriz, é muito simples.
Ela consiste em percorrer a matriz por linhas e para cada elemento percorrido,
mostrar na tela o seu conteúdo.
void imprimirMatriz ( int a[ ][M] )
{
int i, j ;
for ( i = 0 ; i < M ; i++ )
for ( j = 0 ; j < N ; j++ )
printf ( “%d \n”, a[i][j]);
}
6.3.2- Somar os Elemento de uma Matriz
A operação para somar o conteúdo de todos os elementos de uma matriz,
também é muito simples. Ela consiste em percorrer a matriz por linhas, e por
cada elemento percorrido, acumular numa variável auxiliar o seu conteúdo. Essa
variável auxiliar deverá ser inicializada com zeros antes do iniciarmos esse
percurso.
Faculdade de Engenharia de Universidade Católica de Angola - Prof. Manuel Menezes 73
Introdução as Técnicas de Desenvolvimento de Algoritmos
int somaElementosMatriz( int a[ ][M] )
{
int i, j ; soma = 0;
for ( i = 0 ; i < M ; i++ )
for ( j = 0 ; j < N ; j++ )
soma += a[i][j];
}
6.4- Operações Recursivas com Matrizes
De forma análoga aos vectores, as matrizes são estruturas de dados
iminentemente recursivas, pois vejamos: seja a uma matriz retangular com n
linhas e m colunas. Essa matriz é igual a união do elemento qualquer a(i,j) com
todos os elementos de A menos esse elemento.
Em função dessa definição recursiva, vamos discutir a seguir, a implementação
de algumas operações com a estratégia de decrementar para conquistar.
6.4.1- Imprimir os Elementos de uma Matriz
A operação para imprimir todos os elementos de uma matriz, consiste em
fragmentar a matriz passada como parâmetro em duas submatrizes. Uma
unitária, cujo conteúdo será mostrado na tela, e outra de menor dimensão, que
sofrerá novamente um processo de fragmentação, até tornar-se unitária. A
solução do problema de imprimir todos os elementos de uma matriz, consiste em
imprimir o conteúdo das matrizes unitárias geradas pelo processo de
fragmentação.
void imprimirMatrizRec ( int a[ ][M], int i, int j )
{
if ( i < N )
{
if ( j < M )
{
printf (“ %d \n “, a[i][j] );
imprimirMatrizRec ( a , i , j + 1);
}
else
imprimirMatrizRec ( a , i + 1 , 0);
}
}
Vimos que quando executamos uma chamada recursiva, armazenamos numa
pilha em memória, os parâmetros da função e as variáveis locais. Quando
processamos uma matriz com um algoritmo recursivo, efectuamos muitos
Faculdade de Engenharia de Universidade Católica de Angola - Prof. Manuel Menezes 74
Introdução as Técnicas de Desenvolvimento de Algoritmos
chamadas recursivas. Logo, podemos concluir que a medida que o algoritmo vai
avançando, teremos a necessidade de alocar mais recursos de memória. Mas
como a velocidade de processamento é inversamente proporcional a quantidade
de memória alocada, concluímos que os algoritmos recursivos são inviáveis para
o processamento de matrizes.
6.4.2- Somar os Elementos de uma Matriz
A operação para somar todos os elementos de uma matriz, consiste em
fragmentar a matriz passada como parâmetro em duas submatrizes. Uma
unitária, cujo conteúdo será acedido e outra de menor dimensão que sofrerá
novamente um processo de fragmentação, até tornar-se unitária. A solução do
problema original consiste na soma das soluções das submatrizes unitárias
geradas pelo processo de fragmentação.
int somaMatrizRec ( int a[ ][M], int i, int j )
{
if ( i < N )
if ( j < M )
return a[i] + somaMatrizRec( a , i , j + 1);
else
return somaMatrizRec ( a , i+1, 0);
}
6.4.3- Multiplicação Rápida de Matrizes
Para multiplicar duas matrizes de forma eficiente, existe um algoritmo, baseado
no paradigma de Divisão e Conquista que executa essa multiplicação. Esse
algoritmo é mais eficiente do que o algoritmo padrão de multiplicação de matrizes
e deve-se ao matemático volker strassen.
6.5- Recomendações Bibliográficas
Para o leitor aprofundar os seus conhecimentos sobre matrizes,
recomendamos os seguintes livros:
Deitel H. M., Deitel, P. J.;- C How to Program, 8 th Edition, Pearson Education,
K. N. King. - C Programming – A Modern Approach, W. W. Norton & Company,
Inc., 2nd edition, 2008.
6.6- Exercícios Propostos
Faculdade de Engenharia de Universidade Católica de Angola - Prof. Manuel Menezes 75
Introdução as Técnicas de Desenvolvimento de Algoritmos
6.6.1-Desenvolva uma função iterativa e uma função recursiva que recebe uma
matriz retangular com n linhas e m colunas, cujos elementos são do tipo inteiro.
Verifique se essa matriz é simétrica.
6.6.2-Desenvolva uma função iterativa e uma função recursiva que recebe duas
matrizes retangulares com n linhas e m colunas, cujos elementos são do tipo
inteiro. Verifique se essas matrizes são iguais.
6.6.3- Desenvolva uma função iterativa que recebe uma matriz quadrada, com n
linhas e n colunas, cujos elementos são do tipo inteiro. Verifique se essa matriz
é um quadrado latino de tamanho n. Por definição, num quadrado latino de
tamanho n, em cada linha e em cada coluna aparecem todos os inteiros 1,2,3,
…, n, ou seja, cada linha ou coluna é uma permutação dos n primeiros inteiros.
Por exemplo: n = 3.
1 2 3
|2 3 1|
3 1 2
6.6.4- Desenvolva uma função iterativa e uma função recursiva que recebe uma
matriz retangular com n linhas e m colunas, cujos elementos são do tipo inteiro.
Devolva o valor mínimo e o valor mínimo dessa matriz.
6.6.5-Desenvolva uma função iterativa e uma função recursiva que recebe uma
matriz quadrada com n linhas e n colunas, cujos elementos são do tipo inteiro, e
um número inteiro qualquer. Substituir todas as ocorrências desse número por
zeros.
6.6.6-Desenvolva uma função iterativa e uma função recursiva que recebe uma
matriz quadrada com n linhas e n colunas, cujos elementos são do tipo real.
Verifique se essa matriz é uma matriz é identidade. Por definição, uma matriz
identidade é aqueles cujos elementos da diagonal principal são iguais a um e os
restantes iguais a zero.
6.6.7-Desafio de Programação: desenvolva uma função iterativa que recebe uma
matriz quadrada com n linha e n colunas, cujos elementos são do tipo inteiro.
Devolva essa matriz com os elementos ordenados em ordem crescente por
colunas. Por exemplo:
3 1 9 Depois → 1 4 7
7 6 2 ← Antes 2 5 8
5 8 4 3 6 9
6.6.8-Desafio de Programação: suponha que uma matriz quadrada M represente
a ligação entre um conjunto de n cidades, de tal forma que M[i,j] = 1 representa
uma estrada que sai da cidade i e chega a cidade j,, e M[i,j] = 0 no caso contrário.
Na teoria dos grafos, essa matriz recebe o nome de matriz de adjacência. Por
exemplo, na matriz a seguir, temos duas estradas que saem da cidade 0. Uma
chega a cidade 1 enquanto outra a chega a cidade 2; uma estrada que sai da
Faculdade de Engenharia de Universidade Católica de Angola - Prof. Manuel Menezes 76
Introdução as Técnicas de Desenvolvimento de Algoritmos
cidade 1 e chega a cidade 3; mas nenhuma estrada que sai da cidade 4 e chega
a cidade 2.
0110
0010
1101
1010
Desenvolva uma função recursiva que dada uma matriz M e uma cidade i,
determine todas as cidades que podem ser alcançadas a partir dessa cidade.
6.6.9-Desafio de Programação: desenvolva um programa que nos mostre o
percurso a fazer para atravessar um labirinto. O seu programa deve ser capaz
de percorrer o labirinto e de encontrar um tesouro que se encontra escondido,
encostado A à uma das paredes. Apôs encontrar a saída o seu programa deve
encontrar a saída. O percurso ao labirinto pode ser feito com base no algoritmo
deTremaux. Esse algoritmo baseia-se na seguinte estratégia: ao atravessar um
labirinto, sua mão direita ou esquerda deve ficar sempre em contacto com uma
das paredes. Dessa forma fica garantido que todas as paredes tenham sido
percorridas e, como consequência o tesouro será encontrado. O seu programa
deve aceitar como entrada a discrição de um labirinto, no qual está marcada a
posição do tesouro e da porta. Por exemplo, defina um labirinto como uma matriz
20x20 em que cada elemento pode ser: parede, tesouro e porta.
6.6.10- Desafio de programação: desenvola uma programa com funções para
colorir um mapa, de países reais ou imaginários, de forma que países com fron-
teira em comum tenham cores diferentes. Em 1852, Francis Guthrie conjecturou
que eram necessárias 4 cores para colorir qualquer mapa. Mas, só ao cabo de
mais de cem anos, em 1976, é que se conseguiu provar que essa conjectura
estava certa, obtendo-se o chamado Teorema das Quatro Cores.
Faculdade de Engenharia de Universidade Católica de Angola - Prof. Manuel Menezes 77