Executando verificação de segurança...
21

Estrutura de Dados #0

Recentemente foi publicado aqui mesmo no Tabnews um conselho do Uncle Bob referente a quais tipos de programadores as empresas deveriam contratar, e eu realmente fiquei com essa notícia disparando na minha cabeça. Isso por que, o que mais a gente vê hoje em dia são pessoas preocupadas em aprender linguagens de programação e logo, o que mais a gente vê no mercado são pessoas vendendo cursos de como aprender a mexer em tal linguagem de programação...

MAS ISSO ACABA HOJE!

Nesse post eu quero te entregar uma breve introdução aos estudos de Estrutura de Dados, e digo breve, por que se tratando desse conteúdo há muitas coisas pra se falar que não cabem em somente um post, e pra isso eu vou deixar no desenrolar do assunto alguns links úteis pra facilar a sua pesquisa.

Sem mais delongas, bora lá:

Estrutura de Dados + Algoritmos

O estudo de estruturas de dados envolve mais do que esse nome indica, pois não se pode pensar em estruturas de dados sem pensar em algoritmos, é como se um não vivesse sem o outro. Não faz nenhum sentido termos estrutura de dados sem um algoritmo pra manipula-las e entregar um resultado, dá mesma forma que não podemos ter um algoritmo que não manipula dados, como somar, subtrair, comparar... Por isso é essencial estudar ambos em conjunto. As estruturas de dados servem basicamente para representar dados que abstraímos de situações ou objetos do mundo real que estamos interessados em processar. Isso pode ser exemplificado com numeral e número - numeral é um símbolo que representa a quantidade número. Quantidade é algo abstrato, algo que não conseguimos representar bem, portanto usamos símbolos para representar isso, por exemplo a quantidade cinco pode ser representada de diversas formas como, 5, V e até mesmo "cinco" or "five", são formas diferentes de representar a mesma quantidade. Na computação isso acontece também, nós representamos toda a abstração através dos binários (0 e 1). Entender bem como funciona o sistema binário, fazer operações aritméticas entre binários é importante porque tudo em um computador são números binários. Dá mesma forma que nós convencionalmente usamos a base decimal pra representarmos as coisas (Os conjuntos numéricos por exemplo), para o computador usamos a base 2. Caso, você não tenha familiaridade com operações em binário recomendo ver qualquer vídeo no Youtube que já ajuda, mas antes, vejam esse pra entender o porquê se usa o sistema binário nas máquinas Why Binary

Ótimo, agora que já entendemos que tudo em computador são 0 e 1 e que não há Estruturas de Dados sem algoritmos, podemos ir para o nosso próximo tópico:

O que são Estrutura de Dados

Para entendermos esse tópico vamos falar um pouco sobre matemática e seus conjutos numéricos. A teoria de conjuntos nos permite manipular qualquer tipo de elemento, e como a matemática lida com números seus conjuntos são basicamente numéricos, são alguns deles, o conjunto dos naturais, inteiros, reais, complexos e etc.... O que é importante pra nós aqui são os atributos que diferenciam os elementos de cada conjunto, por exemplo, no conjunto dos naturais nós precisamos somente do atributo valor (5), no conjunto do inteiros precisamos do atributo valor e do atributo sinal (-5), para os reais precisamos do atributo valor na parte inteira, do atributo sinal na parte inteira, e do atributo valor da parte fracionária (4.237)... ou seja, cada tipo de conjunto possui elementos com atributos diferente. Podemos ver também que cada conjunto possui algumas operações entre seus elementos. No conjunto do naturais por exemplo podemos ter, as operações de soma, subtração, multiplicação e de divisão, dá mesma forma para o conjunto dos inteiros e reais. Logo, cada conjunto têm seus elementos definidos por um combo de atributos e as operações que podem ser realizadas sobre esses elementos. Toda essa explicação serve como analogia para entendermos o que são estruturas de dados, que nesse ponto, nós podemos chegar na conclusão de que, estruturas de dados: guardam atributos de um elemento e que possuem uma relação direta com as operações/algoritmos que manipulam essas estruturas. Assim, com as estruturas e os algoritmos podemos dizer que um tipo de dado é definido por um conjunto de estrutura de dados e os algoritmos associados a eles, bem parecido com o conjunto numérico que vimos antes. A diferença são que os conjuntos numéricos são infinitos e precisos, duas limitações bem conhecidas em um computador. Um exemplo prático disso é pegarmos a linguagem C e entendermos seus tipos de dados através dessa explicação, podemos então chegar ao resultado que, um Int é um tipo de dado pois possui em sua estrutura atributos que definem o que é um "int" e possui operações/algoritmos que manipulam esse "int" como soma++, subtração--, RestoDaDivisao%.

c = a + b
Imaginemos que essas variáveis foram inicializadas usando o tipo Int, logo nesse código podemos dizer que a, b e c são estruturas de dados do tipo Inteiro e o "+" é o algoritmo que as manipulam.

Se você entendeu até aqui o que são tipos de dados, podemos então partir para os tipos primitivos de dados. Um tipo primitivo de dado sempre está associado a uma linguagem de programação, isso porque, cada linguagem possui nativamente alguns tipos, como por exemplo a linguagem C que possui nativamente os tipos Int, Float, Char, Bool entre outros... As linguagens de programação podem vir a ter os mesmos tipos primitivos de dados, mas isso nem sempre acontece, muito pelo fato de que cada linguagem possui seus tipos primitivos baseado em um problema que ela quer resolver, seja ensinar programação, realizar cálculos científicos, processamento algébrico, gerência de banco de dados, processamento de matrizes, desenho vetorial e etc. Nesse caso, o criador da linguagem julga que seria interessante criar uma linguagem para ajudar as pessoas daquela área a produzir soluções de forma mais fácil e mais rápido, pra isso ele inclui nesta linguagem tipos de dados e outras estruturas para facilitar esse trabalho. Aprender a usar tipos primitivos é muito importante, mas, é essencial que em projetos grandes você aprenda a criar novas estruturas para representar os atributos relevantes dos seus objetos para problemas do mundo real. Nesses casos maiores então, você precisará desenvolver novas estruturas de dados e algoritmos que as manipulem, em outras palavras você precisa desenvolver novos tipos de dados.

Caso queiram, eu recomendo pesquisarem por diferentes tipos primitivos nas linguagens e tentaram chegar a uma conclusão do porque da existência desse tipo na linguagem.

Como um dado é visto pelo computador

Nesse tópico nós precisamos resgatar o que foi falado lá no começo do texto e entender como os bits são organizados pra representar um dado. Para fins didádicos vamo usar o Int como exemplo e entender quais foram os problemas no começo da computação que se tinham ao representar um inteiro.

Quando se trata dos inteiros nós temos dois problemas, os inteiros são infinitos e possuem em seu conjunto os números negativos. Se tratando do primeiro problema é meio óbvio de se imaginar o porquê isso é um problema para a computação, afinal, a memória do computador é finita. Por mais que o hardware tenha evoluido de tamanho ao longo dos anos é praticamente impossível de se criar uma memória infinita, pelo menos por agora. Portanto, vamos direto para o segundo problema. Para o nosso exemplo prático vamos escolher o número 7 e representá-lo em binário, fica assim -> 00111. Perceba que nesse nosso exemplo eu estou usando 5 bits sendo 4 bits usado para representar o valor (campo da magnitude) e 1 bit para o sinal, que é o bit mais a esquerda ou bit mais significativo (MSB). E é exatamente assim que as estruturas do tipo signed int funcionam. Voltemos ao nosso exemplo com 00111(7), perceba que o bit mais significativo é 0, logo, esse valor é positivo, caso fosse 1 seria negativo. "Ótimo, se agora quiserssemos representar o -7, bastaria então "flipar" ou inverter o bit do sinal? 10111 por exemplo", Não! Para representar os números negativos foi pensado num método chamado complemento de 1. No complemento de 1 a ideia é flipar todos os bits de um inteiro positivo e terá no fim um número negativo, vejamos no exemplo do 7 -> 00111, usando complemento de 1 ficaria -> 11000 e esse valor então seria usado para representar o -7. Esse método é até eficiente, porém ele possui um problema, dessa vez com a representação do 0.

Usando o complemento de 1 no número 0 nós teriamos o seguinte problema, o zero "positivo" seria representado assim -> 00000, porém usando o complemento de 1 o zero "negativo" ficaria assim -> 11111, ou seja, nós teriamos duas representações diferentes para o número 0. Imagina ter que fazer uma comparação se uma variável é != 0 e ter que se preocupar com as duas representações do 0, seria um problemão! Então para corrigir esse problema foi criado o complemento de 2. No complemento de 2 nós primeiro fazemos o complemento de 1 e adicionamos 1 no bit mais a direita ou bit menos significativo (LSB), então no nosso exemplo usando o 7 -> 00111, nós teriamos -> 11000 usando complemento de 1 e depois adicionamos 1 ao lsb ficando -> 11001 e assim nós representamos o -7 <-> 11001.

Antes de darmos a solução por completo, vamos ver se o problema com o 0 foi resolvido. Usando o complemento de 2 então teriamos 00000 -> 11111 -> 11111 + 1 -> 100000, basta ignorar o Carry 1 no MSB e voilá enfim então temos 00000 para o 0. Ótimo, temos agora somente uma representação para o 0 e o complemento de 2 se mostra eficiente para o conjunto dos inteiros :D, muito massa!!

Para os demais tipos eu deixo com vocês ir em busca de pesquisa ;)

Vou deixar aqui alguns links para referência
Float: Padrão IEEE 754
String: Tabela ASCII, EBCDIC, Unicode
Complemento de 2: Two's Complement
Notícia da Flávia Carvalho: Uncle Bob

Espero que não tenha ficado muito denso :D, e caso tenham alguma observação a fazer deixe aqui nos comentários e vamo que vamo turma!

Tem muito mais a ser feito :)

6

Muito bom! Faz poucos dias que postei um texto aqui no tabnews, abordando justamente essas bases da programação (3 vezes que a faculdade te ensinou a programar e você nao percebeu), com o objetivo de provocar a comunidade (principalmente os iniciantes) a sair da superficie das linguagens e frameworks e navegar em aguas mais profundas".

Seria muito legal ver a comunidade aqui se despertando pra isso e procurando aprofundar conhecimento!

Nao pare! Ansiosos pelos proximos textos!

4

Estrutura de dados foi uma das minhas disciplinas favoritas na faculdade. Tem muita gente usando Array para armazenar um conjunto de dados únicos enquanto que a linguagem muitas vezes oferece uma estrutura própria para isso, como o Set em JavaScript. Falta conhecimento de base para essas pessoas, e um pouco de estudo já resolve isso.

4

Aqueles que estavam lendo "Programaçào para iniciantes para quem não é iniciante" este post é um exelente complemento para ler em paralelo e começar a se aprofundar mais.

A o autor espero que continue e venha detalhando cada estrutura de dados, como funciona, caso de uso e seus algoritmos relacionados.