Aula de Rogério Júnior
Até agora vimos estruturas de dados simples, como vetores e matrizes. Nesta aula, vamos aprender a usar um vetor e alguma variáveis auxiliares para construirmos estruturas de dados mais complexas.
Pilha
A primeira estrutura que vamos ver é a pilha, pois só precisa de uma única variável auxiliar. Em uma pilha, o último elemento inserido é o primeiro a sair e, para implementar essa estrutura em C, só precisamos de um vetor e uma varável inteira que guardará o tamanho do vetor. Uma pilha tem a função "push", que coloca um elemento no topo da pilha, a função "pop", que retira o elemento do topo da pilha, a função top, que diz qual é o elemento no topo e a clear, que tira todos os elementos da pilha. Para implementarmos as funções vamos logo declarar as variáveis que usaremos. Vamos definir que o tamanho máximo da pilha, MAXT, será 1000100. Vamos criar uma pilha de inteiros e, para isso, vamos declarar o vetor "int pilha[MAXT];" e a variável "int tam;". Declare tam global para que ela comece com o valor zero. Vamos indexar o vetor pilha de 1 a n, assim, o elemento do topo sempre será "pilha[tam]". Para excluir o elemento do topo, basta que façamos a redução da variável tam em 1 unidade, pois agora, o tamanho da pilha realmente será uma unidade menor e o termo "pilha[tam]" agora se refere a um elemento uma posição atrás do antigo topo, que é o que ocorre quando tiramos o topo de uma pilha: o novo topo será o elemento abaixo do antigo. Para inserirmos o elemento x na pilha, basta que aumentemos tam em 1 unidade, com o comando "tam++;", e depois façamos o topo da pilha receber x, com o comando "pilha[tam]=x;". Para limparmos a pilha, basta zerarmos a variável tam, com o comando "tam=0;".
É bom saber que podemos reduzir esses dois comando a uma única linha: "pilha[++tam]=x;". Note que como o operador "++" vem antes de "tam", primeiro o computador adiciona 1 unidade a tam e depois realiza o comando "pilha[tam]=x;". Se invertermos a ordem e escrevermos "pilha[tam++]=x;", primeiro o computador irá executar o comando "pilha[tam]=x;" e só então o comando "tam++;". Essa regra de precedência de operadores se aplica em qualquer ocasião. Escrever "int n = i++;" irá fazer primeiro n receber o valor de i para só então aumentar i em uma unidade. O comando "int n = ++i;" aumentará primeiro o valor de i para só então fazer n receber seu valor.
Segue um código com uma pilha e suas três funções já implementadas. Note que, por precaução, a função pop só elimina o topo da pilha se houver algum elemento nela (tam > 0), para que não corramos o risco de ter uma pilha com tamanho negativo:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define MAXT 1000100 // defino o limite de tamanho como 1000100 | |
int pilha[MAXT], tam; // declaro o vetor pilha e a variável tam | |
// função top: retirar o elemento do topo | |
void pop(){ if(tam>0) tam--; } // se tam>0, basta reduzí-la em 1 unidade | |
// função push: insere um elemento no topo | |
void push(int x){ pilha[++tam]=x; } // basta aumentar tam e inserir x na posição tam | |
// função clear: tira todos os elementos da pilha | |
void clear(){ tam=0; } // basta zerarmos a variável tam | |
// função top: retrna o lemento do topo | |
int top{ return pilha[tam]; } // bast retornar o elemento na posição tam |
Agora que você já sabe implementar um pilha, tente resolver o problema Trilhos. Se não conseguir, segue a solução explicada, mas realmente tente fazê-lo sozinho antes de lê-la.
Note que quando os vagões entram na estação, ficam todos enfileirados em cima dos trilhos, e apenas o último vagão que entrou tem liberdade para sair, ou seja, é como se empilhássemos os vagões. Para resolver o problema basta que façamos um for que quer percorrerá toda a sequência dos vagões que devem sair, que estará salva no vetor saida. Olhando qual o próximo vagão que deve sair, verifico se ele está no topo da pilha. Se ele não estiver, vou empilhando os vagões que ainda faltam entrar, até que chegue o vagão esperado. Quando o vagão chega, eu o tiro da pilha (dou um pop), passo para o próximo vagão que deve sair e continuo o algoritmo. Se em algum momento eu precisar empilhar mais um vagão e não houver mais nenhum esperando para entrar, então é impossível que eles saiam na ordem desejada. Segue o código para melhor entendimento. Vale lembrar que o operador "!" representa negação, ou seja, (!condicao) retorna o oposto de condicao: se condicao for verdadeira, !condicao seria falsa, e vice-versa.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> // scanf e printf | |
#define MAXT 1000100 // defino o limite para o tamanho da pilha | |
int n, saida[MAXT], pilha[MAXT], tam; // declaro as variáveis que vou usar | |
//funções da pilha | |
void pop(){ if(tam>0) tam--; } | |
void push(int x){ pilha[++tam]=x; } | |
void clear(){ tam=0; } | |
int top(){ return pilha[tam]; } | |
int main(){ | |
while(scanf("%d", &n) && n!=0){ // para cada caso de teste | |
while(scanf("%d", &saida[1]) && saida[1]!=0){ // e para cada exemplo de saída | |
for(int i=2; i<=n; i++) scanf("%d", &saida[i]); // termino de ler a ordem de saída | |
clear(); // limpo a pilha | |
int j=1; // inicializo o int j, o próximo vagão que irá entrar | |
push(j++); // coloco o vagão j na ferrovia e aumento o seu valor | |
bool deu_errado=false; // variável controle, que guarda se não foi possível | |
for(int i=1; i<=n; i++){ // para cada vagão na ordem de saida | |
while(top()!=saida[i] && j<=n) push(j++); // espero os vagões entrarem até que chegue o esperado | |
if(top()==saida[i]) pop(); // se ele chegar, o tiro da ferrovia | |
else{ // se todos entrarem e não chegar o esperado | |
printf("No\n"); // imprimo "No" | |
deu_errado=true; // salvo que é impossível | |
break; // e fecho o for | |
} | |
} | |
if(!deu_errado) printf("Yes\n"); // se não deu errado, imprimo "Yes" | |
} | |
printf("\n"); // imprimo a quebra de linha ao fim de cada caso de teste | |
} | |
return 0; | |
} |
Fila
Agora que você já viu como funciona uma pilha, pense em como implementar um fila. Em uma fila, o primeiro que entra é o primeiro que sai, ou seja, na fila a função push não coloca um novo elemento no topo, como na pilha, mas no final da fila. A função pop não tira o último elemento que foi inserido, mas o que está na fila há mais tempo. Não temos a função top, mas as funções front, que retorna o primeiro elemento na fila, e back, que retorna o último elemento da fila. Como não teremos mais a variável tam, podemos implementar, também, a função size, que retorna o tamanho da fila. Para implementar a fila, precisarmos novamente de um vetor que a guardará, que chamaremos de fila, e as variáveis inteiras ini e fim, que guardam em qual índice do vetor estão o primeiro e o último elemento da fila, respectivamente. É fácil ver que a função front deve retornar fila[ini] e a função back deve retornar fila[last]. A função pop deve excluir o elemento do começo, fazendo com que o próximo elemento da fila se torne o primeiro, logo, ela deve aumentar o valor de ini em uma unidade. A função push deve receber o elemento x, que será inserido, e então aumentar o tamanho da fila, fazendo com que seu fim seja uma posição depois da que ele era ("fim++;") e lá colocar o valor a ser inserido ("fila[fim]=x;"). Logo, ela deve realizar o comando "fila[++fim]=x;". O tamanho da fila será o a quantidade de elementos entre ini e fim, ou seja, deve retornar fim-ini+1. Note que a fila deve começar com ini=1 e fim=0, para que todas as funções funcionem com os comandos aqui mostrados, logo, para zerarmos a fila, basta fazermos essas duas variáveis assumirem esses valores. Segue um código com a implementação de uma fila de inteiros. Note que a função pop só retira o elemento se ele estiver lá (size()>0), para não corrermos o risco de termos uma fila de tamanho negativo. Na implementação, definimos o tamanho máximo da fila, novamente, como 1000100.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define MAXT 1000100 // defino o tamanho limite da fila como 1000100 | |
int fila[MAXT], ini=1, fim; // declaro as variáveis que vou usar | |
// função front: retorna o primeiro elemento da fila | |
int front{ return fila[ini]; } // basta retornar o elemento na posição ini | |
// função back: retorna o último elemento da fila | |
int back(){ return fila[fim]; } // basta retornar o elemento na posição fim | |
// função size: retorna o tamanho da fila | |
int size(){ return fim-ini+1; } // basta retornar a diferença entre fim e ini mais 1 | |
// função push: insere um elemento no fim da fila | |
void push(int x){ fila[++fim]=x; } // faço fim receber a próxima posição e lá coloco o elemento x | |
// função pop: retira o primeiro elemento da fila | |
void pop(){ if(size()>0) ini++; } // faço o começo da receber a p´roxima posição | |
// função clear: retira todos os elementos da fila | |
void clear(){ ini=1; fim=0; } // basta fazermos ini e fim assumirem os seus valores iniciais |
Agora que você já sabe implementar um pilha, tente resolver o problema Jogando Cartas Fora. Se não conseguir, segue a solução explicada, mas realmente tente fazê-lo sozinho antes de lê-la.
A pilha de cartas será representada por uma fila, pois as cartas são inseridas no fim dela (primeira que entra é a primeira que sai). A primeira coisa a se fazer é limpar a fila ("clear();") e inserir nela, ordenadamente, todas as cartas de 1 a n, com um for: ("for(int i=1; i<=n; i++) push(i);"). No começo da saída vamos imprimir a linha "Discarded Cards:". Vamos abrir um while que rodará enquanto ainda houver duas ou mais cartas na fila ("size()>=2"). Agora, dentro do loop, basta que façamos estritamente o que manda o problema: vamos imprimir a carta que está em cima do monte (a primeira da fila, pois foi a primeira a ser inserida) precedida de espaço em branco, com o comando "printf(" %d", front());"; depois retiramos essa carta da fila ("pop();"); depois colocamos a nova carta que está no topo na parte de trás da fila ("push(front());") e, novamente, a tiremos do começo da fila. Por fim, se inda houver mais de uma carta na fila ("if(size()>=2)") imprima a vírgula que separa os números. No fim de cada caso de teste, imprimiremos, em outra linha, a carta que ficou na pilha, seguida da quebra de linha, com o comando "printf("\nRemaining card: %d\n", front());". Segue o código para melhor entendimento:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> | |
#define MAXT 1000100 // defino o tamanho limite da fila como 1000100 | |
int fila[MAXT], n, ini=1, fim; // declaro as variáveis que vou usar | |
// funções da fila | |
int front(){ return fila[ini]; } | |
int back(){ return fila[fim]; } | |
int size(){ return fim-ini+1; } | |
void push(int x){ fila[++fim]=x; } | |
void pop(){ if(size()>0) ini++; } | |
void clear(){ ini=1; fim=0;} | |
int main(){ | |
while(scanf("%d", &n) && n!=0){ // enquanto a entrada não for zero | |
clear(); // limpe a fila | |
for(int i=1; i<=n; i++) push(i); // coloque os inteiros de 1 a n nela | |
printf("Discarded cards:"); // imprima "Discarded cards:" | |
while(size()>=2){ // enquanto houver mais de uma carta na fila | |
printf(" %d", front()); // imprima a primeira carta | |
pop(); // tire ela da fila | |
push(front()); // insira nova primeira carta no fim da fila | |
pop(); // e a retire do começo novamente | |
if(size()>=2) printf(","); // se ainda houver mais de um elemento na fila, imprima a vírgula | |
} | |
printf("\nRemaining card: %d\n", front()); // imprima a carta restante | |
} | |
return 0; | |
} |
Um ponto a ser ressaltado, em filas e pilhas e em qualquer outro programa é que chamar uma função é um pouco lento. Até agora, realmente implementei as funções das filas e pilhas, mas somente por ser mais didático que vejamos as chamadas das funções push, pop, size, ... mas é muito melhor simplesmente executar, na linha em que chamávamos a função, o comando que ela realiza ao invés de chamá-la. É mais rápido, por exemplo, usar o comando "tam--;" em uma pilha do que o comando "pop;". Para melhor compreensão, segue o código do problema anterior sem a implementação das funções da fila:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> // scanf e printf | |
#define MAXT 1000100 // defino o tamanho limite da fila como 1000100 | |
int fila[MAXT], n, ini=1, fim; // declaro as variáveis que vou usar | |
int main(){ | |
while(scanf("%d", &n) && n!=0){ // enquanto a entrada não for zero | |
ini=1; fim=0; // limpe a fila ("clear();") | |
for(int i=1; i<=n; i++) fila[++fim]=i; // coloque os inteiros de 1 a n nela ("push(i);") | |
printf("Discarded cards:"); // imprima "Discarded cards:" | |
while(fim-ini+1>=2){ // enquanto houver mais de uma carta na fila ("while(size()>=2)") | |
printf(" %d", fila[ini]); // imprima a primeira carta ("printf(" %d", front());") | |
ini++; // tire ela da fila ("pop();") | |
fila[++fim]=fila[ini]; // insira nova primeira carta no fim da fila ("push(front());") | |
ini++; // e a retire do começo novamente ("pop();") | |
// se ainda houver mais de um elemento na fila, imprima a vírgula | |
if(fim-ini+1>=2) printf(","); // ("if(size()>=2) printf(",");") | |
} | |
printf("\nRemaining card: %d\n", fila[ini]); // imprima a carta restante ("front()") | |
} | |
return 0; | |
} |
Agora que você já sabe tudo iss, tente fazer o problema Banco. Se não conseguir, segue a resposta abaixo, mas realmente tente fazê-lo sozinho antes de lê-la.
Este é um problema da segunda fase da P2 da OBI 2012, mas precisaremos apenas de uma fila e três vetores auxiliares para resolvê-lo. Vamos definir MAXC como o limite de c, MAXN como o limite de n e MAXF como o tempo máximo que o banco levará para finalizar todos os atendimentos (o número máximo de pessoas multiplicado pelo tempo máximo de atendimento e somado ao instante máximo de chegada (1000 x 10 + 300 = 10300)). Como MAXF é pequeno (), podemos declará-lo com sobra e definir MAXF como 20000. O dois primeiros vetores auxiliares que vamos precisar são o int chegada[MAXN], que guardará o minuto em que cada pessoa da fila chegou (a pessoa chega no minuto ), e o int tempo[MAXN], que guardará a duração do atendimento de cada pessoa (o atendimento da pessoa terá duração de minutos). O terceiro é o int livre[MAXC], que vai guardar em qual minuto cada caixa vai ficar livre (o caixa ficará livre no instante ). Vamos guardar também uma variável auxiliar prox que guarda qual é a próxima pessoa que vai entrar na fila e a variável resposta, que guardará quantas pessoas vão esperar mais de 20 min na fila. No começo do programa vamos preencher os vetores chegada e tempo com as informações da entrada, indexando-os de 1 a n. O vetor livre deve ter todos os seus valores zerados (podemos declará-lo como global, por exemplo) pois, no começo, todos os caixas estarão livres no tempo 0. O valor de prox será 1, pois a primeira pessoa será a próxima a entrar na fila.
Para simular o andamento da fila, usaremos um for que representará a passagem do tempo, fazendo uma variável min variar de 0 até o tempo máximo que o banco levará para atender todos os clientes (MAXF). Para cada repetição do for, vamos simular o que acontece durante o minuto min. Vamos olhar quem é a próxima pessoa que vai chegar ao banco (prox) e verificar se ela já chega neste minuto, ou seja, se chegada[prox]==min. Se for, a insiro na fila com a função push e digo que a próxima pessoa que chegará será prox+1 (comando "prox++;"). Se prox for maior que n, então já chegaram todas as pessoas e não devo inserir ninguém. Vamos usar um while para repetir essa operação até que todas as pessoas que chegarão no minuto min entrem na fila. Feito isso, vou verificar se tem alguém na fila. Se tiver, vou procurar se já tem algum caixa vago, ou seja, percorrerei o vetor livre em busca de um caixa que está ficando livre agora ou que já ficou livre em um tempo anterior (livre[i]<=min). Se houver caixa livre, então essa pessoa será atendida, então devo olhar o tempo que ela esperou, que será o minuto atual subtraído do minuto em que ela chegou (min - chegada[front()]). Se esse tempo de espera for maior que 20 min, então adiciono uma pessoa a resposta (resposta++). Além disso, o instante em que o caixa , que irá atender esse cliente, ficará livre será o minuto atual somado da duração do atendimento do cliente ("livre[i]=tempo[front()];"). Feito isso, vamos tirar a primeira pessoa da fila com o comando "pop();" e executar o comando "break;" para sairmos do for que procurava um caixa livre. Novamente, usaremos um while para repetir o procedimento de atender uma pessoa enquanto houver caixas livres. Para isso, usaremos uma bool vaga, que indicará se há algum caixa vago. Ela sempre começará false, mas, se após percorrermos o vetor livre encontrarmos algum caixa vago, ela receberá true, fazendo com que ela somente termine o while como false se tivermos percorrido todos os caixas e nenhum deles estiver livre. Vale lembrar que se não houver ninguém mais na fila ("if(size()==0)") e ninguém mais for chegar ao banco ("if(prox>n)"), podemos acabar o for agora com um break, executando o comando "if(size()==0 && prox>n) break;". Ao final do programa, imprimimos o valor de resposta, seguido da quebra de linha. Segue o código para melhor entendimento. Note que nele não há a implementação das funções, mas apenas os comandos que elas devem executar.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> // scanf e printf | |
// deino os limites do problema | |
#define MAXT 1000100 | |
#define MAXN 1010 | |
#define MAXC 20 | |
#define MAXF 20000 | |
// declaro as variáveis que vou usar | |
int fila[MAXT], n, c, chegada[MAXN], tempo[MAXN], livre[MAXC], prox=1, ini=1, fim, resposta; | |
int main(){ | |
scanf("%d %d", &c, &n); // leio os valores de c e n | |
for(int i=1; i<=n; i++) scanf("%d %d", &chegada[i], &tempo[i]); // leio as informações dos clientes | |
for(int min=0; min<MAXF; min++){ // para cada minuto da simulação | |
// coloque na fila todos que chegarem no banco naquele minuto | |
while(prox<=n && chegada[prox]==min) fila[++fim]=prox++; | |
bool vaga=true; // diga que há vaga para que o while a seguir se inicie | |
while(fim-ini+1>0 && vaga){ // enquanto tiver gente na fila e caixas vagos | |
vaga=false; // suponha que não há mais caixa vago | |
for(int i=1; i<=c; i++) // para cada caixa | |
if(livre[i]<=min){ // veja se ele está vago | |
// se o cliente a ser atendido tiver esperado mais de 20 minutos | |
if(min-chegada[fila[ini]]>20) resposta++; // adicione 1 a resposta | |
livre[i]=min+tempo[fila[ini]]; // diga em que minuto o caixa ficará livre | |
ini++; // tire o cliente atendido da fila | |
vaga=true; // salve que encontrou um caixa vago | |
break; // saia do loop que procurava por caixas vagos | |
} | |
} | |
// se acabarem as pessoas da fila e ninguém mais for chegar no banco | |
if(fim-ini+1==0 && prox>n) break; // termine a simulação da fila | |
} | |
printf("%d\n", resposta); // imprima a resposta seguida de quebra de linha | |
return 0; | |
} |
Criando sua própria estrutura
Até agora você usou variáveis e funções apenas de tipos já salvos no C++, como int, double, char e bool. Entretanto, a linguagem permite que você crie o seu próprio "tipo", a sua própria struct. Uma struct é um objeto como outro qualquer, com suas próprios objetos salvos. Para declarar uma struct de nome objeto, usamos o comando "struct objeto{};". Entre as chaves, escrevemos os membros de objeto. Se quisermos, por exemplo, que objeto tenha duas variáveis, o int a e o int b, escrevemos isso entre as chaves, da forma: "struct objeto{ int a, b; };". Lembre-se que objeto não é o nome de uma variável, mas de um tipo, como int ou char, por exemplo. Ou seja, vamos declarar uma variável do tipo objeto. Ela teria que ter um nome assim como se fôssemos declarar uma do tipo int. Para declararmos a variável var do tipo objeto, usamos o mesmo comando que usaríamos em qualquer outro tipo: "objeto var;". Agora temos uma variável de nome var e do tipo objeto. Vamos, então, declarar a struct assim:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct objeto{ // declaro a struct objeto | |
int a, b; // declaro que um objeto tem dois inteiros: a e b | |
}; |
Como faço para acessar um membro de uma struct? Escrevo o nome da variável do tipo que criei (no caso var) seguido de um ponto (".") e então escrevo o nome do membro. Se quiséssemos acessar o valor de a do objeto var, escreveríamos "var.a". Se já tivermos declarado o objeto var e escrevermos os comandos "var.a=3; var.b=4;", então o valor da variável a de var receberá 3 e o de b receberá 4. Como atribuímos 4 ao valor de b, o comando "printf("%d", var.b);" imprimiria o inteiro 4 na tela.
Podemos usar uma struct para representar objetos que são definidos por mais de um valor, inclusive de tipos diferentes. Um ponto, por exemplo, no plano cartesiano, é determinado por dois valores: os das suas coordenadas x e y, respectivamente. Logo, poderíamos representá-lo como uma struct que contêm duas doubles, o coord_x e o coord_y. Veja:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct ponto{ // declaro a struct ponto | |
// declaro que um ponto tem duas doubles como membros | |
double coord_x, coord_y; // sua coordenada x e sua coordenada y | |
}; | |
Um aluno, por exemplo, pode ser representado por seu nome (um vetor de char) e sua nota (uma double). Veja:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct aluno{ // declaro a struct aluno | |
// e declaro seus dois membros: | |
char nome[30]; // o vetor de char "nome", de 30 posições | |
double nota; // e a double "nota" | |
}; |
Assim como em qualquer outro tipo, podemos declarar um vetor de uma struct. Para representar uma sala de aula, por exemplo, posso criar um vetor de aluno de 100 posições de nome classe, com o comando "aluno classe[100];". Para ordená-lo, posso usar a função sort, desde que use uma função de comparação para que o sort saiba ordenar os alunos, que será feita exatamente como vimos na aula de ordenação. Agora, entretanto, não acessaremos os elementos em um outro vetor, todos serão membros de um mesmo elemento do vetor classe. Além disso, a função de comparação não mais receberá inteiros como identificadores do alunos, para depois procurar os seus atributod, mas receberá estruturas que, sozinhas, contêm todos os dados dos estudantes: o tipo aluno. Segue o código para melhor compreensão:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> // scanf e printf | |
#include <algorithm> // sort | |
#include <cstring> // strcmp | |
// defino os limites de n e do tamanho da string | |
#define MAXN 100100 | |
#define MAXL 30 | |
using namespace std; // algorithm | |
struct aluno{ // declaro a struct aluno | |
// e declaro seus dois membros: | |
char nome[30]; // o vetor de char "nome", de 30 posições | |
double nota; // e a double "nota" | |
}; | |
int n; // declaro o inteiro n | |
aluno classe[MAXN]; // declaro o vetor de alunos | |
bool compara(aluno x, aluno y){ // declaro a bool compara, que recebe dois alunos | |
if(x.nota>y.nota) return true; // se a nota do primeiro for maior estão em ordem | |
if(y.nota>x.nota) return false; // se a nota do segundo for maior, não estão em ordem | |
// se o programa chegar nessa linha, então as notas são iguais, então olho para os nomes | |
if(strcmp(x.nome, y.nome)<0) return true; // se o nome do prieiro vier antes, estão em ordem | |
//se o programa chegar nessa linha, então o nome do primeiro não vem antes | |
return false; // então eles não estão em ordem | |
} | |
int main(){ | |
scanf("%d", &n); // leio o valor de n | |
for(int i=1; i<=n; i++) scanf(" %s %lf", classe[i].nome, &classe[i].nota); // leios os nomes e notas dos alunos da classe | |
sort(classe+1, classe+n+1, compara); // e o ordeno o vetor classe segundo a função compara | |
// depois imprimo os nomes dos alunos salvos ordenadamente no vetor | |
for(int i=1; i<=n; i++) printf("%s\n", classe[i].nome); // para cada aluno i, imprimo o membro nome de classe[i] | |
return 0; | |
} |
Agora que você já sabe tudo isso, tente fazer os problemas abaixo. Se surgir alguma dúvida teórica ou você não conseguir fazer algum deles, vá para a página inicial do curso e preencha o formulário para nos enviar sua dúvida.
Problema 1 - Ferry Loading III
Problema 2 - Ferry Loading IV
Problema 3 - Balanço de Parênteses 1
Problema 4 - Infixa para Posfixa
Problema 5 - Diamantes e Areia
Problema 6 - Parentheses Blance
Problema 7 - Bora Bora
Problema 8 - Trilhos Novamente... Traçando Movimentos
Clique aqui para voltar para a aula de ordenação e tentar resolver os problemas criando sua própria struct
As aulas do Curso Noic de Informática são propriedade do Noic e qualquer reprodução sem autorização prévia é terminantemente proibida. Se você tem interesse em reproduzir algum material do Curso Noic de Informática para poder ministrar aulas, você pode nos contatar por esta seção de contato para que possamos fornecer materiais específicos para reprodução.