As seguintes definições foram adotadas nesta solução:
1) as torres foram nomeadas de 'A' (origem), 'B' (destino) e 'X' (apoio);
2) os discos empilhados na torre de origem são identificados numericamente mantendo a relação
com os seus tamanhos, ficando sempre empilhados em ordem decrescente em uma determinada
torre: do maior na base ao menor no topo da pilha;
Exemplo para 3 discos:
| | |
1 | |
2 | |
__3__ __|__ __|__
Torre A Torre X Torre B
Conforme as regras desse problema, discos maiores não podem sobrepor discos menores em uma
determinada torre, sendo que a movimentação deles é livre entre as torres, desde de que
seja um disco por vez.
Para resolver o problema, a pilha de discos na torre de origem deve ser movida para a torre
de destino, usando uma torre extra para apoio à movimentação.
Um algoritmo aplicando recursividade facilita a solução, pois devemos mover uma possível
pilha de discos que esteja sobre um disco maior em uma determinada torre antes de poder
mover esse disco maior para outra torre:
função recursiva( disco, origem, destino, apoio ){
se ( disco > 1 )
{
// mover antes para a torre de apoio uma possível pilha sobre um disco
// que necessita ser movido para a torre de destino:
recursiva( disco - 1, origem, apoio, destino );
}
// agora podemos mover o disco para a torre de destino após a pilha sobre ele
// ter sido movida para a torre de apoio:
escreva( "mover disco ", disco, " da torre ", origem, " para torre ", destino );
se ( disco > 1 )
{
// mover a pilha de discos que está na torre de apoio para a de destino,
// ficando esta sobre o disco que foi movido antes:
recursiva( disco - 1, apoio, destino, origem );
}
}
função principal(){
recursiva( 3, 'A', 'B', 'X');
}
Após a execução do algoritmo acima, a disposição dos discos nas torres será:
| | |
| | 1
| | 2
__|__ __|__ __3__
Torre A Torre X Torre B
A seguir temos o programa escrito na linguagem C:
#include <stdio.h>
int passo, qtd;
void function( int disco, char origem, char destino, char apoio ){
if ( disco < 1 ) return;
if ( disco > 1 ) function( disco - 1, origem, apoio, destino );
printf( "\nPasso %d: mover disco %d de %c para %c", ++passo, disco, origem, destino );
if ( disco > 1 ) function( disco - 1, apoio, destino, origem );
}
int main(void) {
passo = 0;
qtd = 3;
function( qtd, 'A', 'B', 'X' );
return 0;
}
Saída produzida pelo programa acima:
Passo 1: mover disco 1 de A para B
Passo 2: mover disco 2 de A para X
Passo 3: mover disco 1 de B para X
Passo 4: mover disco 3 de A para B
Passo 5: mover disco 1 de X para A
Passo 6: mover disco 2 de X para B
Passo 7: mover disco 1 de A para B
Para testar o programa acima, utilize a plataforma ideone.com:
https://ideone.com/qtypyY
Bom estudo e até a próxima.
Notas de Aulas
sábado, 22 de fevereiro de 2020
Recursividade - Torre de Hanói
quarta-feira, 27 de maio de 2015
Usando Threads na plataforma Windows
O Código a seguir apresenta uma demonstração simples de uso de programação multi-thread
na linguagem C. A plataforma utilizada é a gcc em ambiente Windows 7.
//== Inicio do código ===================================================
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//== principal include para uso de threads na plataforma Windows ========
#include <windows.h>
//== uma função qualquer para ser acessada da thread secundária =========
double tarefa( int i, double j )
{
return (i * j);
}
//== estrutura de dados para passagem de argumentos ====================
typedef struct {
int a;
double b;
double (*task)( int, double );
} DataArgs;
//== função para a thread secundária ===================================
DWORD WINAPI MyThreadFunction( LPVOID lpParam )
{
DataArgs *args = (DataArgs *)lpParam;
int z;
FILE *fh = fopen( "k:/log.txt", "w" );
for ( z=0; z<1000; z++ )
{
double resultado = args->task( args->a+z, args->b );
fprintf( fh, "\nThread SECUNDARIA: %d\t%f", z,resultado );
}
fclose ( fh );
return 0;
}
//== thread main =======================================================
int main()
{
int x;
// declaração de estrutura de dados para servirem como argumentos
// para a função da thread secundária
DataArgs dados;
dados.a = 20;
dados.b = 3.141592;
dados.task = tarefa;
HANDLE hThreadArray;
DWORD dwThreadIdArray;
// criação da thread secundária
hThreadArray = CreateThread(
NULL, // default security attributes
0, // use default stack size
MyThreadFunction, // thread function name
&dados, // argument to thread function
0, // use default creation flags
&dwThreadIdArray ); // returns the thread identifier
if ( hThreadArray == NULL )
{
puts( "\nErro ao criar Thread.\n" );
return 1;
}
// outras coisas da thread main
for (x=0; x < 1000000; x ++)
{
printf( "\nThread MAIN: %f", sqrt( x ) );
}
return 0;
}
//== fim do código ====================================================
Links de referência:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682516(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682512(v=vs.85).aspx
Bom estudo e até a próxima.
quarta-feira, 11 de setembro de 2013
Tornando constante o ponteiro ou a memória apontada
O código a seguir apresenta a diferença entre tornar constante o valor do ponteiro ou valor na memória por ele apontada.
#include <stdio.h> // scanf(), printf()
#include <stdlib.h> // calloc(), free()
int main()
{
// declarar constante o conteúdo da memória apontada, mas
// o ponteiro poderá ser alterado
const int *x = (const int *) calloc( 1, sizeof(int) );
// aviso por modificar o conteúdo da memória apontada
scanf("%d", x);
// erro por tentar modificar o conteúdo da memória apontada
// *x = 3210;
// declarar constante o conteúdo do ponteiro, mas
// o conteúdo da memória apontada poderá ser modificado
int * const w = (int * const) calloc( 1, sizeof(int) );
// erro por tentar alterar o ponteiro
// w = x;
// modificando o conteúdo da memória apontada
*w = 123456;
printf("x: %d\n", *x );
printf("w: %d\n", *w );
// modificando o ponteiro
x = w;
printf("x: %d\n", *x );
free( (void*)x );
free( (void*)w );
return 0;
}
sexta-feira, 16 de agosto de 2013
Uso de array por meio de alocação dinâmica de memória
A proposta deste código é usar alocação dinâmica de memória para suprir a função de array bi-dimensional:
double ptr[100][2];
Para tanto, esta declaração é substituída pela alocação de memória:
double **ptr = (double **) malloc(100*sizeof(double*));
Para cada ocorrência de *(ptr+j), sendo j de 0 a 99, alocar memória:
*(ptr+j)=(double *) malloc(2*sizeof(double));
O acesso aos elementos do array bi-dimensional ou da memória alocada dinamicamente pode ser feita da mesma forma:
*(*(ptr+j)+k))
ou
ptr[j][k],
variando j de 0 a 99, k de 0 a 1.
Aproveitando este projeto, também são apresentadas as funcionalidades de acesso ao relógio do sistema e formatação de data e hora.
Para a geração de dados, foi usada a função de randomização com parâmetros de faixa de valores, casas decimais e escala desejada.
Na impressão de dados numéricos, foi usada a configuração do ambiente de execução por meio da função 'setlocale()', tornando as saídas com ponto decimal em vírgulas.
double ptr[100][2];
Para tanto, esta declaração é substituída pela alocação de memória:
double **ptr = (double **) malloc(100*sizeof(double*));
Para cada ocorrência de *(ptr+j), sendo j de 0 a 99, alocar memória:
*(ptr+j)=(double *) malloc(2*sizeof(double));
O acesso aos elementos do array bi-dimensional ou da memória alocada dinamicamente pode ser feita da mesma forma:
*(*(ptr+j)+k))
ou
ptr[j][k],
variando j de 0 a 99, k de 0 a 1.
Aproveitando este projeto, também são apresentadas as funcionalidades de acesso ao relógio do sistema e formatação de data e hora.
Para a geração de dados, foi usada a função de randomização com parâmetros de faixa de valores, casas decimais e escala desejada.
Na impressão de dados numéricos, foi usada a configuração do ambiente de execução por meio da função 'setlocale()', tornando as saídas com ponto decimal em vírgulas.
#include <stdio.h> // printf(), fflush(), getchar(), stdin
#include <stdlib.h> // malloc(), free(), srand(), rand(), RAND_MAX
#include <time.h> // time_t, struct tm, time(), localtime()
#include <locale.h> // setlocale()
int main(){
// dias da semana
char dia[][14] = {
"Domingo",
"Segunda-Feira",
"Terça-Feira",
"Quarta-Feira",
"Quinta-Feira",
"Sexta-Feira",
"Sábado"
};
// data/hora em milésimos de segundos desde zero hora de 1900
// ( time_t é um 'long long int' )
time_t agora;
// struct para relogio/calendario
struct tm *calendario;
// controle de loops
int j, k;
// declarar e alocar memória para 100 ponteiros de 'double'
double **ptr = (double **) malloc(100*sizeof(double*));
// para cada 1 dos 100 ponteiros de 'double' alocar memória para 2 'double'
for (j=0; j<100;j++){
*(ptr+j)=(double *) malloc(2*sizeof(double));
}
// inicializar a sequencia de randomização (semente) usando a hora corrente do sistema
srand( (unsigned) time( NULL ) );
// obter a hora corrente do sistema
time( &agora );
// converter a hora do sistema em estrutura 'hh:mm:ss, dd/mm/yy, weekDay, yearDay'
calendario = localtime( &agora );
// usar configurações regionais do sistema
setlocale( LC_ALL, "" );
// imprimir data e hora correntes
printf( "%s - %02d/%02d/%04d - %02d:%02d:%02d - %dº dia do ano",
dia[calendario->tm_wday], // dia da semana (0=domingo, ..., 6=sábado)
calendario->tm_mday, // dia do mês
calendario->tm_mon+1, // mês (0=janeiro, ..., 11=dezembro)
calendario->tm_year+1900, // anos decorridos de 1900
calendario->tm_hour, // horas do dia (00~23)
calendario->tm_min, // minutos da hora (00~59)
calendario->tm_sec, // segundos do minuto (00~59)
calendario->tm_yday+1 ); // dia do ano (0~365)
// inicialização dos dados no array bi-dimensional
for (j=0; j<100;j++){
for (k=0; k<2; k++){
*(*(ptr+j)+k) =
// gerar valores numéricos aleatórios
// de 0.0 a 10.0 em intervalos de 0.125
(int)(((double)rand() // 0 a RAND_MAX
/ (RAND_MAX+1)) // RAND_MAX
* ((10.125 - 0.0) * 8.0)// faixa desejada * Ajuste de escala e casas decimais
+ 0.0) // Deslocamento da faixa
/ 8.0; // Ajuste de escala e casas decimais
}
}
// impressão dos dados do array bi-dimensional
for (j=0; j<100;j++){
printf("\n");
for (k=0; k<2; k++){
printf( "%8.4lf\t",
//*(*(ptr+j)+k)
ptr[j][k]
);
}
}
// liberar a memória de 2 'double' para cada um dos 100 ponteiros
for (j=0; j<100;j++){
free(*(ptr+j));
*(ptr+j) = NULL;
}
// liberar a memória dos 100 ponteiros para 'double'
free(ptr);
ptr=NULL;
// aguardar que teclem ENTER para encerrar o programa
fflush(stdin);
getchar();
// return-code de encerramento do programa
return 0;
}
segunda-feira, 22 de julho de 2013
Passando referência de uma função como argumento na chamada de outra função
No código a seguir, a função opera recebe 3 argumentos:
Para testar, foi usado o site ideone.com
- 1º argumento: um ponteiro para uma função que recebe 2 argumentos inteiros;
- 2º argumento: um inteiro;
- 3º argumento: um inteiro;
A função desejada para ser executada é passada no 1º argumento. Os outros argumentos são repassados para a função que será executada.
#include <stdio.h>
// declaração da assinatura da função a ser passada como argumento para
// outra função
int (*f) (int, int);
int somar(int a, int b){
return a+b;
}
int subtrair(int a, int b){
return a-b;
}
int opera(int (*g) (int, int), int a, int b){
return g(a, b);
}
int main(){
printf( "\nsoma: %d\n", opera(somar, 25, 30 ));
printf( "\nsubtração: %d\n", opera(subtrair, 25, 30 ));
f = somar;
printf( "\noutra soma: %d\n", opera(f, 25, 230 ));
f = subtrair;
printf( "\noutra subtração: %d\n", opera(f, 25, 230 )
return 0;
}
Para testar, foi usado o site ideone.com
quarta-feira, 14 de novembro de 2012
Como separar os dígitos de um número inteiro
Mais uma pequena solução para um pequeno problema.
Agora a situação é para separar os dígitos de um numero inteiro, permitindo aplicações como cálculos de dígitos de verificação (DV) ou dígito para auto conferência (DAC) de identificações como RG, CPF, CNPJ, etc.
Vejam o código a seguir:
#include
int main()
{
long long int numero = 876543210987654321LL;
do{
printf( "\n%d" , (int)(numero % 10) );
} while ( numero /= 10 );
return 0;
}
Cópia de tela da execução:
Bom estudo e até a próxima.
Agora a situação é para separar os dígitos de um numero inteiro, permitindo aplicações como cálculos de dígitos de verificação (DV) ou dígito para auto conferência (DAC) de identificações como RG, CPF, CNPJ, etc.
Vejam o código a seguir:
#include
int main()
{
long long int numero = 876543210987654321LL;
do{
printf( "\n%d" , (int)(numero % 10) );
} while ( numero /= 10 );
return 0;
}
Cópia de tela da execução:
Bom estudo e até a próxima.
Como obter a parte inteira de um número real
Para um pequeno problema, uma solução também pequena.
Considere a situação onde se tenha um número real (double) e deseja-se separar a parte inteira da fracionada. Restrição: não usar qualquer biblioteca pronta.
Vejam o código a seguir.
#include
int main()
{
double areaAmbiente = 3.7999999999;
double areaEmbalagem = 1.8;
int qtdEmbalagensInteger = areaAmbiente / areaEmbalagem;
double qtdEmbalagensReal = areaAmbiente / areaEmbalagem;
printf( "\n %d %c %10.4f ",
qtdEmbalagensInteger,
(qtdEmbalagensInteger < qtdEmbalagensReal ?
'<' : qtdEmbalagensInteger > qtdEmbalagensReal ?
'>' : '='),
qtdEmbalagensReal );
qtdEmbalagensInteger +=
qtdEmbalagensInteger < qtdEmbalagensReal ? 1 : 0;
printf( "\nEmbalagens requeridas: %d",
qtdEmbalagensInteger);
return 0;
}
Bom estudo e até a próxima.
Considere a situação onde se tenha um número real (double) e deseja-se separar a parte inteira da fracionada. Restrição: não usar qualquer biblioteca pronta.
Vejam o código a seguir.
#include
int main()
{
double areaAmbiente = 3.7999999999;
double areaEmbalagem = 1.8;
int qtdEmbalagensInteger = areaAmbiente / areaEmbalagem;
double qtdEmbalagensReal = areaAmbiente / areaEmbalagem;
printf( "\n %d %c %10.4f ",
qtdEmbalagensInteger,
(qtdEmbalagensInteger < qtdEmbalagensReal ?
'<' : qtdEmbalagensInteger > qtdEmbalagensReal ?
'>' : '='),
qtdEmbalagensReal );
qtdEmbalagensInteger +=
qtdEmbalagensInteger < qtdEmbalagensReal ? 1 : 0;
printf( "\nEmbalagens requeridas: %d",
qtdEmbalagensInteger);
return 0;
}
Bom estudo e até a próxima.
