Exercício de Estrutura de Dados 1. Considere a implementação de listas lineares utilizando apontadores e com célula cabeça. Considere que um dos campos do TipoItem é uma chave: TipoChave. Escreva uma função em C, cujo cabeçalho segue abaixo: int EstaNaLista(TipoChave Ch, TipoLista *Lista); que retorna 1 se Ch estiver na lista e retorna 0 se Ch não estiver na lista. Considere que não há ocorrências de chaves repetidas na lista. Determine a complexidade do seu algoritmo. 2. Um problema que pode surgir na manipulação de listas lineares simples é o de voltar atrás na lista, ou seja, percorrê-la no sentido inverso ao dos apontadores. A solução geralmente adotada é a incorporação à célula de um apontador para o seu antecessor. Listas deste tipo são chamadas de duplamente encadeadas. A Figura 1 mostra uma lista deste tipo com estrutura circular e a presença de uma célula cabeça. Figura 1: Lista circular duplamente encadeada. a) Declare os tipos necessários para a manipulação da lista. b) Escreva uma função em C para retirar da lista a célula apontada por p: void Retira(Apontador p, TipoLista *Lista, TipoItem *x); 3. Considere uma expressão matemática que inclui vários parênteses aninhados como, por exemplo: 7 - ((X * ((X + Y) / (J - 3)) + Y) / (4 - 2.5)) Para se assegurar que os parênteses estão aninhados corretamente, precisa-se verificar que: existe um número de parênteses à direita igual ao número de parênteses à esquerda; todo parêntese à direita é precedido por um parêntese correspondente à esquerda. Considere que cada parêntese à esquerda abre um escopo, enquanto cada parêntese à direita fecha um escopo. Sendo assim, duas condições devem ser satisfeitas, de forma que o uso de parênteses em uma equação seja feito corretamente: 1. o número de parênteses à esquerda menos o número de parênteses à direita da expressão deve ser zero. Isso significa que nenhum escopo foi deixado aberto. 2. o número de parênteses à esquerda menos o número de parênteses `a direita em cada ponto da expressão é positivo. Isso significa que nenhum parêntese `a direita é encontrado para o qual um correspondente parêntese à esquerda não tenha sido aberto previamente. Por exemplo, observe abaixo o número de parênteses à esquerda menos o número de parênteses à direita em cada ponto da expressão: 7 - ( ( X * ( ( X + Y ) / ( J - 3 ) ) + Y ) / ( 4 - 2.5 ) ) 00122234444334444322211222210 Uma pilha pode ser utilizada para averiguar se o uso de parênteses em uma equação está correto. Sempre que um escopo é aberto, um parêntese à esquerda é empilhado na pilha. Por outro lado, sempre que um escopo é fechado, a pilha é examinada. Se a pilha estiver vazia, o finalizador de escopo (parêntese à direita) não possui um correspondente parêntese à esquerda e, portanto, a string é inválida. Se, porém, a pilha não estiver vazia, deve-se desempilhar a pilha e verificar se o item desempilhado corresponde ao finalizador de escopo. Se ocorrer uma correspondência correta, continua-se o processo, caso contrário, a string é inválida. Quando se alcançar o final da string, a pilha deve estar vazia. Caso contrário, um ou mais escopos foram abertos e não fechados posteriormente, sendo a string inválida. Escreva e implemente um algoritmo em C para averiguar se o uso de parênteses em uma equação está correto ou não. 4. Uma fila com prioridades é uma estrutura de dados na qual a ordem intrínseca dos elementos determina os resultados das suas operações básicas. Uma fila de prioridades é uma estrutura de dados útil em problemas nos quais você precisa encontrar rápida e repetidamente o maior elemento de uma coleção de valores e removê-lo desta coleção. Um exemplo do dia-a-dia de uma fila de prioridades é a lista de tarefas a fazer que a maioria de nós tem para nos mantermos organizados. Alguns trabalhos, tais como "limpar a mesa", não são imperativos e podem ser postergados arbitrariamente. Outras tarefas, tais como "terminar o relatório para amanhã" ou "comprar flores para a aniversariante", são cruciais e devem ser realizadas mais rapidamente. Assim, ordenamos as tarefas a serem efetuadas pela ordem de sua importância (ou talvez baseado em uma combinação de suas importâncias críticas, seu benefício a longo prazo ou então realizar primeiro as que forem mais divertidas) e escolher a mais urgente. Desta forma, os elementos na fila com prioridades tem um número indicativo da sua prioridade. O Desenfileira deve procurar o próximo elemento da lista com a maior prioridade e retirá-lo. Considerando as informações acima, escreva uma função em C responsável por implementar a operação Desenfileira em tal fila.