Timing e notação em big O | Kurt Anderson | Skillshare

Velocidade de reprodução


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Assista a este curso e milhares de outros

Tenha acesso ilimitado a todos os cursos
Oferecidos por líderes do setor e profissionais do mercado
Os temas incluem ilustração, design, fotografia e muito mais

Assista a este curso e milhares de outros

Tenha acesso ilimitado a todos os cursos
Oferecidos por líderes do setor e profissionais do mercado
Os temas incluem ilustração, design, fotografia e muito mais

Aulas neste curso

    • 1.

      Vídeo de introdução

      1:42

    • 2.

      Introdução de Big O

      10:18

    • 3.

      Notação de N

      11:29

    • 4.

      Exemplo de notação de N

      4:18

    • 5.

      Big O

      12:58

    • 6.

      Mundo real

      9:51

    • 7.

      Exemplo de estrutura de dados

      7:41

    • 8.

      Projeto com vídeo

      1:19

  • --
  • Nível iniciante
  • Nível intermediário
  • Nível avançado
  • Todos os níveis

Gerado pela comunidade

O nível é determinado pela opinião da maioria dos estudantes que avaliaram este curso. Mostramos a recomendação do professor até que sejam coletadas as respostas de pelo menos 5 estudantes.

7

Estudantes

--

Projeto

Sobre este curso

Bem-vindo ao nosso abrangente programa de scaling e Big O! Neste programa envolvente, vamos desmistificar os fundamentos da escalabilidade computorizada, explorando como os sistemas lidam com cargas e demandas crescentes. Mergulhe nos princípios da escalabilidade, aprendendo a projetar soluções robustas e eficientes capazes de acomodar o crescimento.

Obter uma compreensão sólida da notação com o Big O, uma ferramenta poderosa para analisar e comparar a eficiência dos algoritmos. Por meio de aulas interativas, exemplos do mundo real e exercícios práticos, você descobrirá como assessar o desempenho do seu código e tomar decisões informadas sobre a seleção de

algoritmos. Se você é um iniciante em busca de uma base sólida em informática ou um desenvolvedor experiente com o objetivo de aprimorar suas habilidades de resolução de problemas, este programa fornece o conhecimento para otimizar seu código e criar soluções escaláveis que resistem ao aumento das cargas de

trabalho. Junte-se a nós em uma jornada pelos conceitos centrais de escalonamento de computagem e Big O Notation, e eleve sua experiência em programação a novos patamares!

Conheça seu professor

Teacher Profile Image

Kurt Anderson

Computer Scientist, Multi-Media Designer

Professor

Hello, I'm Kurt.

I am a self-taught multi-media designer and computer scientist who has helped bring the creative vision of clients all around the world to life. Having 8+ years of experience in the Adobe Production Suite has given me a strong tool-set to create anything from videos to websites. Along with this, having a degree in Computer Science has given me a strong analytical mind for dealing with complex problems. Through these two disciplines I create a unique blend of efficiency and creativity. I believe anyone can become a designer or programmer. All it takes is practice.

I am also a world traveler and have lived in and learned from many different countries. During a 6 month stay in Japan, I became fascinated with their people's drive and craftsmanship. I try to i... Visualizar o perfil completo

Level: All Levels

Nota do curso

As expectativas foram atingidas?
    Superou!
  • 0%
  • Sim
  • 0%
  • Um pouco
  • 0%
  • Não
  • 0%

Por que fazer parte da Skillshare?

Faça cursos premiados Skillshare Original

Cada curso possui aulas curtas e projetos práticos

Sua assinatura apoia os professores da Skillshare

Aprenda em qualquer lugar

Faça cursos em qualquer lugar com o aplicativo da Skillshare. Assista no avião, no metrô ou em qualquer lugar que funcione melhor para você, por streaming ou download.

Transcrições

1. Vídeo de introdução: Olá a todos, bem-vindos a este curso sobre notação Big O. Esse é um ótimo tópico de ciência da computação que o ajudará a se tornar mais eficiente em seu trabalho. E também ajudará você a entender um pouco melhor a ciência da computação. Isso é ótimo para todos os tipos de profissões, incluindo programadores, bem como para qualquer pessoa na área de negócios Isso o ajudará a aumentar sua produtividade, pois você entenderá um pouco mais com o que está trabalhando, que lhe dará mais informações e ações as etapas necessárias para tornar as coisas mais eficientes. E é isso que abordaremos neste curso. Vamos abordar a notação por trás de como analisamos diferentes algoritmos e escalabilidade Queremos entender se estamos construindo um programa ou um trecho de código ou mesmo apenas uma unidade organizacional. Ele pode escalar? Se estivermos criando tarefas e procedimentos de natureza exponencial , eles nunca serão capazes de escalar E isso é o que queremos ser capazes de analisar: funciona da mesma forma se tivermos dez pessoas ou 100.000 pessoas? Pense se você deseja verificar cada arquivo em um armário de arquivamento Há uma maneira de extrair cada arquivo e examiná-lo individualmente, ou criar um procedimento em que ele seja organizado e classificado para que você saiba onde encontrar coisas E é isso que você também pode fazer no espaço de programação, mas também com as coisas ao nosso redor. Outro exemplo seria se precisássemos adicionar alguém a uma organização, mas para fazer isso, precisaríamos primeiro entrar em contato com todos os outros membros da organização. Essa é uma solução não escalável. É um procedimento não escalável. E queremos ser capazes de analisar isso, reformulá-lo e torná-lo um procedimento mais escalável Então, nós dois vamos nos concentrar no código, mas entendemos que esses princípios também se aplicam à vida diária. Eles se aplicam às coisas ao nosso redor. Então, vamos entrar nesse tópico de ciência da computação e dar uma olhada em algumas matemáticas realmente interessantes. 2. Introdução de Big O: Vamos falar sobre nosso primeiro assunto importante na análise de algoritmos, que será essa ideia de notação. Então, na verdade, vamos evoluir isso para algo chamado notação Big O, que será algo chamado notação Big O, mais ou menos assim , onde você tem um O, e então a notação in vai para dentro dela Mas antes que possamos fazer isso, precisamos descobrir o que exatamente está na notação. Então, na notação está esse tipo estranho de relacionamento, onde está uma função de Agora, fique comigo. Isso é confuso no começo Então, vamos ter que descompactar isso um pouco É esse tipo de forma em que saída é uma função da entrada e, por acaso , elas são a mesma coisa. Então, vamos criar uma espécie de modelo visual disso. Sempre que criamos um algoritmo ou um programa, o que estamos fazendo é criar esse tipo de caixa preta. Então, o que temos é que temos no lado esquerdo uma entrada. Temos coisas entrando na caixa. Talvez sejam seus amigos do Facebook, talvez seja seu Google Drive, todos os dados que você está enviando para ele. É a Internet. Quando você está fazendo upload de algo, essa é a entrada É enviado para algum tipo de lógica, algum tipo de programa. Então essa é, você sabe, a lógica ou a taxa do controlador aqui. E então ele tem algum tipo de saída. Algo acontece porque adotou essa lógica aqui. Algo aconteceu? Algo se moveu, algo foi salvo. Isso é realmente o que a lógica está fazendo. Então, por exemplo, digamos que estamos fazendo upload de fotos. A entrada são as imagens. Nós o enviamos para o controlador. Ele tira as fotos, talvez as reduza para facilitar o armazenamento. Em seguida, ele tira essas fotos e as salva em um banco de dados. Então, ele os coloca e os grava na memória física em um disco rígido. E então essa é a saída. Portanto, a entrada, as imagens, a saída são todas essas operações de salvamento em um disco rígido. Então, o que estamos tentando descobrir é dada a entrada. Então essa é a entrada de in. Qual será a nossa saída. Em relação a isso. E aqui está apenas uma variável. É só porque não sabemos quantos dados estão chegando. Se, por exemplo, tivéssemos um programa que fizesse amigos no Facebook, eu poderia ter talvez, você sabe, talvez eu tenha 182 amigos no Facebook Bem, talvez você tenha 1.373, e seu primo distante tenha 10.157 amigos no Facebook, você sabe, e assim por diante E digamos que não há limite. Eu acho que há um limite. Mas digamos que não haja limite de amigos no Facebook. Isso significa que você pode ter zero até o infinito. Então, não sabemos qual número vai entrar aqui. Então, em vez de tentar inventar apenas um número, dizemos que será apenas o valor do espaço reservado Então, vamos colocar uma entrada de aqui. Pode ser qualquer um desses números do zero ao infinito. Então, qualquer número. E então vai passar por nossa lógica. E então, no final, teremos um certo número de operações. Então, entre essa taxa de pontos aqui, teremos lógica e, em seguida, operações, e então ela produzirá. E queremos saber o que está acontecendo durante esse momento. Como isso se relaciona com isso? Então, isso aqui vai ser a saída da nossa função. Essa será a notação. E o que normalmente escrevemos é que, na verdade, também o escrevemos como um em. Mas escrevemos isso em função de, o que significa que não é a única coisa que colocamos aqui. Na verdade, há um monte de coisas diferentes que poderíamos colocar aqui. Então, o que poderíamos ter está dentro, e isso significa que sempre que inserimos, digamos, 1.000 dados, são necessárias apenas 1.000 operações. Por exemplo, algo assim é se você encontrar vários arquivos no seu disco rígido e quiser movê-los para outro local? Bem, não há mais nada que realmente precise acontecer. Pegamos um e o movemos. Pegamos um e o movemos. Isso está dentro. Para cada dado que você inclui, há apenas mais uma operação. Agora, há coisas diferentes, é claro. Então, em vez de, pode haver um quadrado. Existe algo chamado log of. Há apenas um pedaço de n. Há um cubo. Aí está a raiz quadrada de. E assim por diante e assim por diante. Então, tudo que estamos fazendo é pegar tudo isso e torná-los uma função da entrada. Isso sempre permanecerá o mesmo. Isso sempre vai aparecer. É a sua opinião. É a quantidade de dados que está chegando. À direita está apenas o relacionamento, e usamos apenas porque mostra que é disso que estamos fazendo uma função. Quero dizer, poderíamos usar x e o x ao quadrado e , em seguida, x log de x e coisas assim, e assim por diante e assim por diante Mas o problema é que você pode se confundir com, você sabe, o que exatamente é x. E então temos que colocar algo aqui que diga: Bem, x é igual a n, x é igual E então estamos pensando, por que não ficamos com N para fazer tudo isso. Então, essa é realmente a maior parte confusa da notação: N parece que pode ser a entrada e a saída Mas o importante é que seja a entrada e, em seguida, a saída seja apenas uma função de N. É uma representação de quanto tempo ou quantas operações N deve usar para superar. Para as saídas. Agora vamos dar uma olhada em um pequeno exemplo concreto. Vamos voltar à questão dos amigos do Facebook, porque isso é algo que todos nós podemos visualizar muito rapidamente Digamos que eu tenha um algoritmo aqui. Eu tenho um algoritmo que pega uma quantidade de amigos do Facebook e os insere em um banco de dados no momento ou no relacionamento de E digamos que eu tenha outro algoritmo aqui. Que faz exatamente a mesma coisa. Exceto que, em vez disso, recebe o mesmo valor de entrada, então recebe, mas produz ao quadrado Há um pouco menos de eficiência aqui. Então, agora podemos olhar para esses dois e compará-los um pouco. Qual desses algoritmos é mais rápido? Então, se prosseguirmos e fizermos algumas contas rápidas, digamos que vamos testar isso com 100 Facebook France. Então, neste primeiro, bem, serão apenas 100 entradas em nossa pequena caixa preta e sairá com 100 operações diferentes para fazer o que quer que faça. Bem, na parte inferior aqui, temos 100 entradas em nossa pequena caixa preta. Lembre-se de que sempre permanecerá o mesmo, mas nossa função é n ao quadrado, que significa que agora precisamos pegar 100 e elevar ao quadrado, que acaba sendo 100 vezes 100, que significa que nosso total será Opa, temos que colocar os zeros Quatro zeros ou 10.000. Então você pode ver que o primeiro levou apenas 100 operações, enquanto o segundo levou 10.000 operações. Nós vamos falar sobre isso um pouco mais tarde. No entanto, os padrões de crescimento deles são o que importa. Dentro do que temos na verdade, temos algo chamado linear e, em seguida, com o quadrado, temos algo chamado exponencial, que significa que o crescimento aumenta cada vez mais com o tempo Mas, como eu disse, falaremos sobre isso mais tarde. O que eu meio que queria te mostrar é como nós olhamos para isso. Portanto, temos um valor de entrada e um valor de saída. Temos outro valor de entrada e outro valor de saída, e há dois algoritmos diferentes, algoritmo A e algoritmo B. E podemos dizer rapidamente: Bem, é definitivamente mais rápido que B. A é que você poderia dizer que é maior que B, ou você poderia dizer que ele usa menos tempo do que B ou como você quiser compará-los. Mas este é rápido e este é lento por causa de quantas operações eles realizam. Então, qual é o objetivo? O que estamos tentando fazer aqui? Isso nos permite ver como um algoritmo é dimensionado com o tamanho da entrada. Se projetarmos um algoritmo, queremos saber se ele é eficiente com mais pessoas e informações? Queremos que nossos programas tenham sucesso. Então, queremos criar soluções que escalem. E isso é algo que você ouvirá muito. Queremos criar soluções escaláveis. E uma solução escalável é uma solução que não funciona apenas para a quantidade exata de pessoas que a estão usando atualmente Então, por exemplo, como eu disse, vamos continuar com esse exemplo do Facebook. Imagine se o Facebook usasse esse. Imagine se ele usasse o algoritmo quadrado porque não achava que eles iriam escalar Bem, o fato é que somos programadores. Estamos tentando tornar nosso produto o melhor produto possível. E isso significa que queremos que o produto tenha sucesso. E quando um produto é bem-sucedido, mais pessoas o usam, mais dados são inseridos e o algoritmo terá que usar essas novas peças Se não criarmos um programa que seja escalável, nos depararemos com todo o problema exponencial, onde sim, isso funcionará para 100 e talvez funcione para 1.000 e, ei, talvez funcione para Mas se você perceber que é uma parte muito pequena da população. Digamos que talvez 1 milhão de pessoas. Quer usar nosso programa. Bem, agora temos uma solução que não funciona para 1 milhão de pessoas. Se fizéssemos 1 milhão vezes 1 milhão. Bem, teríamos um número extremamente grande. Um número que nem mesmo é compreensível pelo nosso cérebro. E isso, na verdade, faremos algumas dessas contas um pouco mais tarde. Um número tão grande acaba levando dias ou até anos para ser executado. Então, um computador, o computador que pode, você sabe, conectar on-line e fazer todas essas contas rápidas levará dias ou anos para realizar uma tarefa simples, porque o programa não é escalável Então essa é a base da notação. É uma forma padronizada de notação que nos permite comparar dois algoritmos em um ambiente completamente estéril, o que significa que não precisamos implementá-los Podemos simplesmente olhar para eles. Isso nos permite compará-los e descobrir qual deles é mais escalável Qual deles será mais rápido sempre que adicionarmos mais pessoas, mais dados ou mais operações a ele E esse é o objetivo da notação. E na próxima aula, continuaremos mergulhando nisso e continuaremos descompactando a caixa que é a notação para que possamos obter essa base sólida para poder comparar 3. Notação de N: Vamos nos aprofundar um pouco aprofundar notação final e examinar alguns dos objetivos por trás do motivo pelo qual nós, cientistas da objetivos por trás do motivo pelo qual nós computação, usamos a notação final e o que estamos tentando extrair Porque a notação final pode ser usada de várias maneiras diferentes Há vários tipos diferentes de combinações ou informações que podemos extrair usando essa notação. Mas o que eu quero abordar é o núcleo, para o qual a maioria dos cientistas da computação o usa. E quais são alguns dos objetivos? Por que o usamos? Então, quando usamos a notação, o que estamos fazendo é procurar padrões grandes, e estamos procurando por esses padrões em uma espécie de espaço teórico, o que significa que não vamos realmente ter um programa implementado ou algo parecido Estamos apenas procurando por esses padrões grandes. Estamos procurando, por exemplo, se um gráfico é assim e o outro é assim. Não nos importamos se em algum momento temos esse gráfico na parte inferior, talvez seja assim , e então esse de cima fique assim ou algo assim? Neste momento, não nos importamos que, sim, haja um ponto aqui quadrado é, na verdade, um pouco mais eficiente Isso é essencial quando você realmente tem um algoritmo à sua frente e está tentando otimizá-lo Isso é o que talvez um otimizador de servidor possa fazer ou gerenciamento de banco de dados, coisas assim Só nos preocupamos com isso, com a teoria em geral. Estamos procurando qual equação piora com o tempo. Então, à medida que avançamos em direção ao infinito, à medida que avançamos em direção à quantidade desconhecida de dados que poderiam vir do algoritmo interno, o que acontecerá com nossa equação Vamos obter aquela equação que não pode ser concluída neste século por causa de quantos cálculos serão necessários, ou vamos obter algo assim, em que não importa quantos cálculos façamos. Só vai continuar funcionando. E é isso que queremos ver. Queremos ver essa grande mudança de eficiência entre diferentes algoritmos. Esse é o objetivo da notação e é por isso que usamos a notação. Portanto, por causa disso, há algumas regras que normalmente usamos com notação. E são apenas uma espécie de abreviatura que usamos para não nos confundir E, novamente, para chegar a esse panorama geral. Portanto, não passamos todo o nosso tempo nos detalhes. Na verdade, podemos simplesmente olhar para duas equações e dizer, sim, esta escala um pouco melhor A primeira é que não nos importamos com múltiplos. E o que isso significa é, por exemplo, se tivermos n ao quadrado e depois três n ao quadrado. Eles são, para todos os efeitos, iguais. Eles são basicamente iguais um ao outro. Nós não nos importamos. Quero dizer, três, você sabe, talvez você possa justificar para si mesmo Sim, três é bom, mas isso pode ser, você sabe, isso pode ser como 3 milhões, 3 bilhões, 30 bilhões, 30 trilhões Pode ser qualquer número que quisermos, e isso não importa. Pegamos esse múltiplo e o apagamos. Não nos importamos com os múltiplos. E isso se resume, novamente, à grande coisa geral, não importa quão grande seja esse número em algum ponto entre zero e Em algum momento, n ao quadrado fará com que esse número nem seja efetivo Imagine se em algum momento fosse igual a, eu não sei. 300 Google, e o Google é 100 zeros no final. Então você tem 100 zeros no final disso. Você acha que os 3 milhões que estão sendo multiplicados realmente importam nesse momento Quero dizer, vai ser uma diferença muito, muito pequena no resultado final. Estamos falando como, você sabe, vai ser a diferença de um número parecido com este ou entre um número que tem isso nele. Você sabe, um pouco mais sobre isso. Isso não importa em nada. É por isso que, em teoria, sempre que vamos do zero ao infinito, não nos importamos com os múltiplos Então, para comparar dois algoritmos, pode ser de 3 milhões ao quadrado, e estamos comparando isso com “não , não importa Ainda estamos apenas comparando n ao quadrado com n ao cubo. Então você sempre remove os múltiplos no começo. Agora, como obtemos esses múltiplos? Bem, digamos que temos uma equação que faz isso. Nós temos a caixa preta, então temos as entradas vindo aqui Temos uma operação quadrada. Em seguida, trazemos todas essas entradas para outra caixa preta, outra operação quadrada Ok. E digamos que, no final, temos outra, mas essa é apenas uma operação de login. Então, com um algoritmo como esse, na verdade, criamos uma pequena equação aqui. Nós fazemos algo assim. Entramos ao quadrado mais quadrado mais o login. E então podemos realmente combiná-los em um múltiplo. Então, isso é dois n ao quadrado mais login. E é assim que criamos um múltiplo, e você sabe que o que estamos dizendo aqui é que realmente não nos importamos com o múltiplo. Eu posso fazer isso quantas vezes quisermos. Estamos apenas analisando esse grande fator de mudança. Então, isso se torna quadrado mais o login. Então, isso chega à nossa segunda regra. Pegamos a maior equação. Então, sempre que temos uma equação como essa, novamente, ela não vai escalar tão rápido quanto isso. Quando entramos nesses números gigantes com 50 zero, 1 bilhão de zeros no final, quero dizer, dois e terminamos, então em algum momento pode haver 1 bilhão de zeros Pode haver 1 bilhão de zeros no final disso, não o número bilhão Estou falando de 1 bilhão de zero real. Seria um número tão longo que, você sabe, você não poderia encaixá-lo em toda a Terra. Pode haver um número como esse. Quero dizer, estamos indo para o infinito aqui. Então, em algum momento, isso vai se tornar tão maior do que esse número que não nos importamos Este é apenas um pequeno obstáculo no caminho para qualquer que seja esse número Isso só vai afetá-lo em talvez 0,000.000 1% em algum momento Em algum momento, é afetado por quase nada. Vai ser um número muito pequeno. É quase zero. E por causa disso , também o removemos do final e deixamos uma equação como essa para dizer: Ei, todo esse algoritmo aqui, todo esse algoritmo aqui é na verdade, apenas quadrado Portanto, há algumas regras de escalonamento. Agora, se você quiser ser técnico, se estivermos otimizando o servidor ou qualquer outra coisa em que realmente temos uma equação à nossa frente, sim, isso provavelmente é algo que queremos analisar, porque se estamos olhando para um servidor real e temos uma equação que pode executá-lo n quadrado mais login, em vez de dois quadrados mais n login queremos fazer isso porque será mais rápido na prática real. Mas, novamente, isso não é prática. Isso é teoria. Estamos tentando descobrir apenas as diferenças das aplicações de grande escala. Então, nesse sentido, fazemos essas duas regras, dividimos em apenas o que é o grande tempo de execução disso. E, na verdade, temos pequenos modificadores de O grande, pequeno O e Beta falaremos sobre eles daqui a pouco , o que tornará isso um pouco mais fácil de entender. Então, vamos dar uma olhada em alguns gráficos aqui. Vamos dar uma olhada, você sabe, no que venho detalhando aqui com todos os números, eles superarão seus parceiros, eles superarão seus parceiros, então só nos importamos realmente com os grandes Então, aqui, temos uma espécie de representação de um gráfico aqui. Temos todas as coisas sobre as quais estamos falando. Este é um, que é o tempo constante. Isso significa que podemos colocar 1.000, podemos colocar 1 bilhão, podemos colocar qualquer número que quisermos, e isso exigirá apenas um número constante de operações. Então, talvez sejam necessários apenas três. Talvez sejam 62 operações diferentes. Não importa o número que coloquemos , são necessárias 62 operações. Então é isso que é o tempo constante. E então obtivemos esse tempo de login, e você pode ver que tem esse tipo de gráfico que é assim. Então, temos apenas a raiz quadrada de N, que é semelhante ao login, mas aumenta com o tempo. Temos linear ou. Linar é apenas uma linha reta em um ângulo. No login, parece um pouco assim, mas depois entra em uma linha linear, talvez com pequenas tendências para cima Então chegamos ao quadrado, o que é exponencial. Então temos dois fatoriais n, que são ainda mais exponenciais e quase que vão direto para o ar E então entramos em fatorial, que pode muito bem ser assim Ele vai quase direto para o ar e cria números tão grandes que, se algum programa for executado em fatorial, está errado Isso tem que ser feito de uma maneira melhor. entanto, vamos dar uma olhada nos exemplos do que tudo isso aconteceria se adicionássemos números a eles, quais seriam os tempos de execução. Então, nessa situação, estamos dizendo que podemos ver aqui, é o número de entradas, e em capital, aqui está o número de operações Então, aqui, esses são os pequenos. Isso é o que estamos inserindo. Estamos inserindo 100.000 ou 10.000 ou 1110 ou um. E essa é a saída quanto tempo levaria para ser executado. E você percebe que na primeira linha, na verdade, é meio interessante que com apenas uma peça, não importa o que você tenha, ela sempre funcionará basicamente ao mesmo tempo. Claro, pode haver algumas pequenas diferenças, por exemplo, talvez um tempo constante. Talvez seja uma vez em que, se constantes vezes 62, tudo isso funcionaria um pouco mais rápido Mas, novamente, isso está no âmago da questão e realmente não nos importamos Queremos analisar essas tendências à medida que elas avançam com o tempo. Então, se formos para fatorial, o E mais no final aqui, isso significa quantos zeros estão no final Então isso significa que isso é 9,3 ou nove três com 157 ou 156 zeros se você De qualquer forma, há muitos zeros no final desse. E este é, você sabe, é quatro com 2567350000, 456.000 E você pode perceber o quanto isso muda com o tempo. E então temos dois aqui. Isso é dois e depois dois, algum fatorial. Então, você sabe, nessa situação, dois décimos ou dois para 100 e assim por diante e assim por diante Mas de qualquer forma, você pode notar que até mesmo esses dois. Esses dois estão basicamente no ar. Há uma grande diferença. É a diferença de 400 a 56 mil zeros e 300 ou 30.000 zeros e 300 ou 30.000 E então seguimos em frente cada vez mais e mais. E o que temos é que reduzimos até n ao quadrado, o qual estamos falando, mostramos o quão ineficiente é E isso, na verdade, parece muito pequeno em comparação com dois dos fatoriais n e n quando aumenta cada vez mais. Então, temos N login. Na verdade, estamos obtendo números legíveis aqui, apenas 1.660.000, depois apenas n, o que, é claro, será equivalente a quantos colocarmos porque N sempre vai para N. É isso que está representando E então começamos a entrar nesses aqui embaixo, onde você percebe que eles são realmente legais. Eles são algoritmos eficientes aqui. Colocamos 100.000 e fazemos apenas 316 operações. Há uma mudança cada vez menor à medida que avançamos com o tempo. E isso, você pode perceber como poderíamos fazer algum tipo de algoritmo se tornasse realmente muito eficiente. Quero dizer, olha isso. Então, temos a diferença entre 90 aqui. E nessa diferença, aumentamos em três operações. Agora, temos a diferença de 900 aqui. E quanto subimos? Bem, apenas por cerca de três operações. Então, temos a diferença de 9.000 novos dados. Quanto vamos subir? Bem, cerca de três operações. E então aumentarmos em 90.000 é o próximo passo. E quanto temos? Bem, apenas três operações. É exatamente o oposto. Quanto mais adicionamos, menos ele sobe. Aumenta cada vez menos com o tempo. E, na verdade falaremos sobre algoritmos ao longo deste curso que funcionam assim. Ele usa algo chamado dividir e conquistar, onde na verdade nos separamos Informações como essa, e dessa forma, podemos acessá-las muito, muito rápido, em vez de ter que examinar cada peça para chegar ao que queremos. Mas de qualquer forma, isso é apenas outro resumo da notação, como ela escala e, em seguida, alguns dos termos que usamos com notação Na próxima palestra, vamos dar um exemplo do mundo real, talvez adicionar um pouco do lado teórico e examinar as diferenças delas se realmente aplicarmos, você sabe, 0,01 segundo a cada operação Podemos ver o quão massivos esses números se tornam e as diferenças entre eles. 4. Exemplo de notação de N: Vamos colocar alguns números que estamos falando para colocar isso um pouco de respeito que todos possam entender. Então, vamos analisar esse problema aqui e dar uma olhada nas diferenças entre a aparência de seu login e do quadrado Na última palestra, analisamos esse tipo de taxa gráfica aqui Então, o que estamos vendo é essa taxa aqui, logada e quadrada E nesse tipo de pequena taxa gráfica aqui, quero dizer, eles parecem muito próximos um do outro, certo? Parece que não haveria muita diferença entre eles. E isso é o que eu quero mostrar é que existem grandes diferenças até mesmo entre eles aqui, e a mudança de eficiência é muito importante. Então, vamos dar uma olhada neste exemplo. Vou simplesmente rever isso e espero que mostre as diferenças Portanto, temos ou dizemos que cada ciclo de um programa leva aproximadamente 0,001 segundos, que acredito ser um milissegundo Então, o que estamos dizendo é quanto mais rápido login será obtido do que o quadrado, se 1.000 dados forem inseridos e, mais abaixo, se 25.000 dados forem inseridos E então, com isso, o que vamos fazer é simplesmente conectar isso. Vamos calcular quantas operações são necessárias, multiplicar por um milissegundo e, em seguida, obter quanto tempo um programa que fosse executado dessa forma levaria Então, nosso primeiro exemplo, temos isso logado. Multiplicamos 1.000 por log de 1.000, e estamos usando log baseado em dois, lembre-se Então, todos esses são baseados em registros dois. Então, o que obtemos é 9.960 vezes milissegundos, e tudo isso resulta Então, se formos com o quadrado, vamos fazer 1.000 ao quadrado Isso vai ser 1.000 vezes 1.000, o que acaba nos dando o número 1 milhão aqui. E com 1 milhão, multiplique os milissegundos e obtemos 1.000 segundos ou 16 minutos Portanto, a diferença entre usar esses dois algoritmos é que um deles levará 9,96 segundos. Então, você sabe, 10 segundos. Não é muito longo, e o outro levará 16 minutos para ser concluído. Imagine se você estiver on-line e enviar um formulário, e um deles usar o login n , enquanto outro formulário usa n quadrado, muitas pessoas poderiam esperar 10 segundos para que um formulário fosse enviado Mas se tivéssemos que esperar 16 minutos, isso não aconteceria. Ninguém vai fazer isso. Então, vamos dar um exemplo um pouco mais alto. Digamos que temos 25.000 dados. Então, fazemos as 25.000 peças. É 25 vezes baseado em registros, dois de 25.000. Recebemos 365.000 vezes milissegundos. Isso então resulta em 6 minutos e 5 segundos. Observe aqui que é importante observar que, mesmo com $25.000 ou 24.000 a mais de dados. Isso ainda leva 10 minutos a menos do que se usássemos n ao quadrado no anterior De qualquer forma, agora vamos dar uma olhada aqui no quadrado n. Então, fazemos 25.000 vezes 25.000. Isso nos dá 625 milhões multiplicando por milissegundos, e temos algo Temos sete dias e 5 horas para fazer isso. Então, são apenas 25.000 dados Agora passamos de 6 minutos para sete dias E, por exemplo, se fizéssemos 250.000 dados, essa taxa aqui seria algo em anos ou milhares de anos Seria algo em que não seria realizado em nossa vida, ou na vida de nossos netos, ou na vida de nossos netos, o sol poderia se apagar antes de chegarmos à conquista, antes que o programa realmente termine a Então, espero que este pequeno exemplo aqui, apenas com essa pequena matemática e adicionando os milissegundos aqui, você possa ver a grande diferença, mesmo que pareçam iguais aqui e talvez até um pouco aqui embaixo Quando aumentamos para mais e mais números, começamos a ter inconsistências gigantescas E essas inconsistências gigantescas são a essência do teorema da ciência da computação É disso que trata o currículo de ciência da computação. Se estamos apenas tentando descobrir que tipo de estrutura de dados ou técnicas devemos usar em cada situação específica para que possamos criar os algoritmos mais eficientes possíveis para que acabemos realizando as coisas rapidamente, em vez de gastar mais tempo, recursos ou nem mesmo sermos capazes de realizar anúncios porque isso levaria muito tempo Então, isso é apenas um pequeno exemplo disso. Ok. 5. Big O: Então, agora que temos uma boa compreensão de N e de como exatamente ele funciona, e isso está ligado à nossa análise de algoritmos, podemos começar a adicionar algo a isso. Então, sabemos que é uma forma de classificar a rapidez com que um algoritmo é executado, dado um determinado número dado um determinado número, em quanto tempo levará em relação a esse número? Então, vai levar na hora certa? Então, se fosse 1.000, seria igual a 1.000 ou seria necessário algo como n vezes ao quadrado, onde quando for 1.000, será igual a 1 milhão E esse é um tipo de classificação muito importante. No entanto, os programas não são tão fáceis. Eles não funcionam apenas na hora exata o tempo todo. Muitas vezes eles têm um vínculo. Então, por exemplo, talvez quando estiver carregando, ele execute um n ao quadrado, mas execute um in e, em seguida, exporte o login no login Então, temos que ser capazes de analisar isso, analisar o programa e dar uma classificação do programa como um todo. Então, por exemplo, neste programa, sempre analisaríamos o pior caso sempre indo para o pior caso, considerando o quadrado No entanto, em determinadas etapas, ele será executado mais rápido. E por causa disso, na verdade temos esse tipo de taxa de sistema aqui, que classificará os limites em nossa notação Então, vamos isso e dar uma olhada nisso. Esses aqui em cima são chamados de Omicron. Você tem Theta no meio e depois Omega, e este é Omega minúsculo aqui embaixo Então você pode ver que eles são alfabetos gregos, mas muitas vezes, em matemática, usamos grego porque o alfabeto fica confuso Então, usamos o grego para representar simbolicamente as coisas. E neste caso, cada um desses símbolos gregos representa simbolicamente um limite Então, o que você tem aqui é desenhar, por exemplo, um limite bem no meio aqui. E aqui em cima é mais rápido. Então eu vou dizer que aqui em cima vai ser mais rápido, e aqui embaixo vai ser mais lento Então, nossa primeira notação é pequena O, e você pode ver que simplesmente não gostamos de dizer Omicron, como uma grande notação Omicron Então, dizemos um pequeno grande O. E tão pouco aqui. Significa apenas que será mais rápido, que significa que o programa sempre será mais rápido do que esse limite. Então, por exemplo, se nosso limite fosse quadrado, aqui mesmo, se tivéssemos um pequeno O de n ao quadrado. Aqui, veríamos que isso significa que nunca tocará n ao quadrado Na verdade, sempre será mais rápido do que n ao quadrado. Então, sempre estará logo acima dessa linha, mas mais rápido do que n ao quadrado Então, o que podemos fazer é usar isso para descobrir o limite. Então, o próximo que temos é que temos o grande O. E o grande O significa que será mais rápido ou igual a. Isso significa que ele tocará essa linha ou será mais rápido. Então, na pior das hipóteses, isso é algo muito importante aqui. Isso significa, na pior das hipóteses. Vai ficar em quadrados. O próximo que temos é Theta, o que significa que não vai tocar em nenhum desses dois Não vai baixar e não vai subir. O que vai acontecer está nesta linha. Portanto, não importa o que seja em quadrado, estará ao longo desta linha em algum lugar E então a próxima descida que temos é mais lenta ou igual a. Então, temos este é Omega, e este é mais lento ou igual a. Então, ele toca essa linha e é sempre mais lento. Então, você sabe, temos n para o terceiro n para o quarto aqui embaixo, aqui em cima, talvez tenhamos. Portanto, é sempre mais lento do que isso, ou igual a n ao quadrado. Então, na melhor das hipóteses. Então, este é, na melhor das hipóteses. Vai funcionar assim se você colocar isso. Então, por exemplo, se escrevermos de n ao quadrado assim. Vamos cortar um pouco aqui, mas se n ao quadrado assim, entendemos que esse programa sempre funcionará da melhor forma, será executado com n ao quadrado O que significa que pode funcionar pior do que isso. E, abaixo disso, temos mais lento que, o que significa que sempre funcionará pior do que n Nunca tocará ao quadrado, mas funcionará pior do que o nSquared E então, por que isso é importante? Por que queremos nos concentrar nesse de todos esses? E isso porque Big O dita o pior cenário possível E estamos preocupados com o pior cenário possível porque, dadas as probabilidades e as estatísticas, nosso programa pode abordar o pior cenário possível em um ponto, e queremos saber, sem dúvida, qual é o pior cenário possível? É por isso que usamos o grande O. É, na pior das hipóteses, o que vai ser. E você pode ver, eu vou abrir o gráfico novamente aqui. Quando temos essa ideia, quando temos a capacidade de dizer qual será nosso programa, podemos realmente começar a preencher isso. Então, se tivermos, por exemplo, talvez um grande O de N. Entendemos que, na pior das hipóteses, ele estará dentro. Então, pode estar dentro, mas também pode ser algo maior do que dentro. Assim, podemos preparar todos os nossos diagramas de tempo e esboços e qualquer coisa assim, partindo do pressuposto de que nunca vai ficar desse lado da linha Sempre vai ficar desse lado. E isso é muito poderoso porque agora podemos começar a comparar os piores casos de programas, e podemos começar a ver que talvez quando um programa é escalado, por exemplo, se tivéssemos um programa de login versus um programa de login, poderíamos ver que quando este for escalado, será pior do que este. Então, vamos analisar isso um pouco, e podemos ver por que algumas delas não têm sentido Então, temos um programa que roda em Little O n quadrado, que significa que é mais rápido do que n quadrado. Isso significa que pode ser de n ao quadrado até Basicamente, tem que ser apenas mais rápido do que isso Portanto, não será quadrado, mas pode ser qualquer coisa mais rápida do que quadrado E este é como o grande O. Mas o problema é o que nos é dado, então é o pequeno O de N. Na verdade, não podemos tocar nisso. Então, isso só torna tudo um pouco confuso. Isso nos dá um limite, mas não facilita a nossa visão. Não podemos olhar imediatamente para isso e dizer : Oh, isso vai durar. Temos que olhar para isso e dizer: Oh, vai correr mais rápido do que, mas não sabemos realmente onde. E isso realmente não nos dá muito espaço de manobra. E então temos nossa grande notação O. E isso é o que acabamos de ver, é que podemos ver isso e dizer: Oh, na pior das hipóteses, ele será executado no login. Theta seria ótimo se pudéssemos sempre usar theta. Isso é igual ou às vezes é usado como média, mas na maioria das vezes, significa igual a. Então, isso seria ótimo. Mas o problema é que os programas nem sempre funcionam exatamente de acordo com uma linha. Às vezes, eles podem ser executados em um ponto, ele executa um, mas em um ponto, ele é executado e faz login, e vai para qualquer lugar entre isso. Então, Theta é muito específico para que possamos realmente gostar. E então, eles são praticamente insignificantes porque não nos fornecem muitas informações Pense sobre isso. Esse aqui, que é Omega Então Omega ao quadrado. Isso significa que será mais lento ou igual ao Omega quadrado, o que é como você está dizendo, nosso programa será executado ao quadrado ou será mais Como devemos planejar com isso em mente? Porque mais devagar poderia ir para o infinito. Pode ser o mais lento possível, e nunca seríamos capazes de nos preparar para isso, porque nunca teríamos um limite. Nós diríamos: Ok, então vamos ver o quão rápido pode levar n ao quadrado, pode levar em fatorial, pode levar o infinito Isso não nos ajuda a analisar o programa porque há esse lado infinito nele. E exatamente a mesma ideia com o pequeno Omega aqui também, é que ele vai para o infinito do lado ruim, o que não nos ajuda Então, isso nos ajuda porque o lado ruim é, deixe-me correr um pouco disso aqui e abrir um pouco mais de espaço. Então, isso nos ajuda porque o lado ruim. Então, digamos que aqui está indo para o infinito. Isso nos dá um limite. Então, qualquer coisa, será na pior das hipóteses aqui, mas poderia ser melhor. E não nos importamos. Tipo, se ele voltar e funcionar tão constantemente, tudo bem. Isso está perfeitamente bem. Isso significa que nossos programas estão funcionando muito bem. Claro. Mas podemos planejar isso. Significa apenas que nosso programa será executado mais rápido do que esperávamos. Então, o que podemos fazer é planejar o pior cenário possível. No entanto, se você for do outro lado dessa linha, não poderá planejar o infinito. É por isso que Big O é tão importante , pois é a mais útil de todas essas notações Isso nos dá o pior cenário possível. Então, vamos dar um exemplo de como podemos aplicar isso a um problema específico. Então, normalmente, o que você sempre faz é usar o pior cenário possível, seja, em que ponto do programa ele será o mais ineficiente Então, aqui, por exemplo, digamos que temos um grande O de n ao quadrado Tivemos um grande número de login. Grande O de N e depois grande O de tempo constante. E então esses aqui embaixo são ótimos. Mas o fato é que, não importa o que aconteça, sempre seremos asfixiados por esse cara aqui E isso é porque nosso tempo de carregamento aqui em cima está em quadrados, o que significa que esse programa vai aumentar em quadrados mais o login, mais, mais o primeiro, o me permite mantê-lo meio que Vamos mais um. E você pode estar pensando, por que estou fazendo isso? E isso porque você pode realmente somar cada parte das etapas. Então, porque você faz essa parte, então, você faz essa parte, então você faz essa parte, então você faz essa parte. Então, você pode realmente adicioná-los todos juntos. E eu me lembro do que estávamos fazendo antemão quando falávamos sobre como tentamos ver um programa à medida que ele vai até o infinito Então, se olharmos para esse número, qual deles vai superar os outros quando chegarmos ao infinito Bem, por exemplo, vamos colocar em 1 milhão. Quão significativo é 1 milhão, que será verso 1 milhão, será verso, talvez algo em torno de 3 milhões, talvez algo em torno de 3 milhões, será verso 1 quatrilhão ou talvez 1 trilhão, seis um e Este vai ser substancialmente maior. Essas serão uma porção cada vez menor do número à medida que ele vai para o infinito. Até o ponto em que eles chegarão perto de zero como significância. Então você vai começar a ter, você sabe, um número do Google, que é 100 zero mais talvez 8 milhões aqui ou algo parecido. E isso significa que essa parte aqui é completamente insignificante neste momento Então, o que fazemos é eliminar os inferiores e o tempo de execução desse programa está em quadrados E então, vamos meio que cimentar isso com outro exemplo aqui. Digamos que tivéssemos uma grande palavra, tivéssemos um grande O de n ao quadrado. Grande O de n ao quadrado. Big O ou eu tenho que desenhar o s aqui. O grande O de n ao quadrado novamente, e então digamos que agora temos um grande O de n terceiro. E agora o que temos aqui é que temos n ao quadrado mais n ao quadrado mais n ao quadrado mais E então podemos realmente combiná-los até três n ao quadrado mais n no terceiro E agora, lembre-se do que falamos na última palestra sobre a notação final Esses não importam. A taxa constante aqui não importa porque, à medida que avançamos para o infinito, ela se torna cada vez menos significativa até que, quando chegamos a um número suficientemente alto, ela se torna basicamente zero Então, podemos riscar esse. E agora temos n ao quadrado mais n terço. E então, é claro, este vai decolar muito mais alto do que o outro. Então, nosso programa acaba ficando em terceiro lugar. E agora, como todas essas são grandes notações O, sabemos que, na pior das hipóteses, nosso programa será executado em terceiro, que significa que agora temos esse limite de terceiro e o infinito do tempo de execução é executado dessa E agora podemos planejar que, na pior das hipóteses, teremos a terceira, e podemos planejar tudo até o tempo constante, porque agora tudo o que temos é exatamente esse limite aqui. Entendemos que, você sabe, se colocarmos 1 milhão de dados, isso pode não funcionar. Talvez possamos tentar trazer isso de volta, mas isso nos dá um lugar para começar. Isso nos dá um lugar para compará-lo com os outros. Então essa é uma grande notação O. Muito importante e, com o tempo, você começará, basicamente, isso se tornará natural só de ser capaz de ver isso. Você realmente nunca verá esses outros com muita frequência. Às vezes, você verá este. Se disser que um determinado ponto de um programa é igual a esse tempo de execução , você verá este. Mas, além disso, esses dois provavelmente nunca verão e você provavelmente nunca verá o pequeno mercão dois Então, essas anotações aqui meio que as memorizam, entendem o que significam, e você deve estar pronto para começar Você começará a entender muito mais documentos de ciência da computação. 6. Mundo real: Agora, aprendemos muita teoria. Vamos dar um passo atrás e examinar algumas análises de código do mundo real. Agora, não vou usar código complexo ou qualquer tipo de código que você precise saber aqui. É tudo pseudocódigo, e vou explicar isso em cada etapa do processo, como se você nunca tivesse tocado em código antes porque é assim que eu quero explicar todo esse tipo de curso, é que estamos analisando a teoria por trás de tudo, não o No entanto, aplicá-lo a algo real pode ajudá-lo a conhecer , a descobrir alguns dos conceitos, e é por isso que estamos fazendo isso. Então, vamos dar uma olhada no nosso primeiro trecho de código. Eu vou seguir em frente e passar por isso aqui. Então, o que temos é que diz, eu escrevi em pseudo, que meio que é lido diretamente da língua, algo que você pode ver e entender o que está acontecendo Então, diz, para cada dado na lista de dados. Então, vamos criar uma lista de dados aqui em um segundo, imprimir os dados na tela. Ok, fácil o suficiente. Digamos que inserimos aqui um dado, uma lista aqui que talvez seja três, dois, dez. E depois vamos para Buffalo. Então, são três números inteiros e uma string. É assim que seria tecnicamente classificado, mas nem vamos analisar isso Esses são quatro dados. Então, o que estamos dizendo é que, para cada dado, para cada dado em nossa lista, vamos imprimir esses dados na tela. Então, em nossa situação aqui, o que está acontecendo? Bem, nesta situação aqui, em iguais, um, dois, três, quatro, porque temos quatro dados Então, nessa situação, n é igual a quatro. Então, agora vamos ver qual seria o tempo de execução disso. Então, temos para cada dado e depois imprimimos na tela. Então, ok, vamos ver a lista aqui. Vamos usar nosso primeiro dado. Portanto, nosso primeiro dado é três. Pegamos três da nossa taxa de documentos aqui. Então isso é zero em uma matriz ou, se você quiser pensar sobre isso, isso é um, dois, três, quatro. Os computadores geralmente usam zero, um, dois, três, é apenas a maneira como eles funcionam. Então, vamos pegar nosso primeiro dado aqui e depois imprimi-lo na tela. Então pegamos nossos três e imprimimos na tela. Então, isso é um tempo de execução. Portanto, nosso tempo de execução agora é um. E agora vamos pegar os dois porque estamos analisando a lista. Então, para cada dado, abordamos esse. Então, agora vamos para este. Agora pegamos dois e imprimimos na tela. Então, agora nossa tela se parece com isso. Então, esse é um tempo de execução adicional. Esse é um tempo de execução. E agora imprimimos nosso próximo dado , que é dez. Então agora temos três, dois, dez. Esse é o tempo de execução adicional aí mesmo. E agora imprimimos búfalos, que seriam três, dois, dez búfalos. Assim. E isso é um tempo de execução adicional. Porque tudo o que estamos fazendo é pegar os dados e imprimi-los Não há nenhum processo de pensamento especial acontecendo aqui. Estamos apenas pegando, imprimindo, pegando, imprimindo, pegando, imprimindo E agora, se somarmos tudo isso, veremos que resulta em um mais um mais um mais um, o que é igual Portanto, nosso tempo de execução nessa situação é quatro, e você verá que nosso tempo de execução igual à quantidade de taxa E se pudéssemos pensar nisso teoricamente por um segundo, se tivéssemos 1 milhão de dados aqui, haveria em nenhum momento do programa que precisaríamos tocar em mais de 1 milhão de dados Então, não importa o que façamos aqui, execução será qualquer que seja o nosso n, o que significa que o que temos aqui é um tempo de execução de N. Nessa situação específica, poderíamos realmente usar Theta como n porque na verdade igual a n. Não há nenhum tipo de espaço de manobra aqui, mas vamos dizer que, na pior das hipóteses, estará dentro, porque essa é a notação que gostamos de Então, este é um exemplo de um in, que é chamado de quatro loops. Portanto, quatro loops são normalmente um exemplo de entrada em uma situação Vamos abordar um problema um pouco mais complexo aqui. Então, deixe-me detalhar isso também. O que temos aqui é que diz, para cada dado em uma lista de dados. Então, isso significa que, em vez de chamá-lo de data agora, cada dado em uma lista entrará. Verifique se os dados estão na lista. Então, vamos usar cada dado na lista de dados, se n for igual a W, imprima verdadeiro Então, vamos detalhar isso um pouco também. Vamos usar o mesmo exemplo anterior, que foi três, dois, dez búfalos. Assim. E nessa situação, nossa entrada ainda é igual a quatro. E agora o que vamos fazer é analisar o primeiro problema aqui. Então, vamos dar uma olhada, certo. Agora, digamos que vamos pegar cada um desses dados, então vamos pegar os três, e agora estamos prontos. Agora, para cada dado nessa lista de dados, você pode ver que esses nomes são exatamente os mesmos. Então isso significa que essa é a lista de dados. Estamos verificando os dois. Então, temos nossos três. Pegamos nossos três. E agora estamos tentando verificar se esses três aqui são equivalentes a qualquer coisa aqui em cima. E a única maneira de fazer isso é a força bruta. Então, vamos pegar esses três. Vamos verificar isso com o primeiro. Vamos verificar isso com o segundo. Vamos verificar isso com o terceiro. Vamos verificar isso com o quarto. Então, isso vai ser uma, duas, três, quatro operações. Então, vamos quebrar isso, tipo, bem longe aqui embaixo. Nós temos nossos três. Pegamos nossos três e agora estamos verificando se é igual Deixe-me fazer isso um pouco menor , porque será um gráfico um pouco maior. Então, estamos dizendo que três igual ao primeiro pedaço de nossos dados, é igual ao primeiro pedaço de nossos dados, que será o três novamente porque não dissemos que ele começasse um número que não fosse ou qualquer coisa sofisticada desse tipo Estamos apenas verificando essa lista pela segunda vez. Então, temos nossos três e estamos verificando se é igual ao primeiro. Então, é igual a três? Sim, é verdade. Então, isso imprimirá uma mensagem verdadeira. E isso exigiu uma operação. Agora, nossos três são iguais a dois, não é? Portanto, não imprimimos nada. Essa é uma operação. Nossos três são iguais a dez? Isso não acontece. Então essa é uma operação. Nossos três são iguais a Buffalo? Isso não acontece. Então essa é uma operação. E agora terminamos com os três. Então, seguimos em frente. Nós cuidamos dos três. Então, vamos criar um segundo aqui embaixo. Vamos ver que T one será aquele com quem estamos verificando. Eles são exatamente iguais, mas eu só quero tornar isso um pouco mais visual para todos vocês. Então, terminamos com os três. Então, vamos passar para os dois agora. Então, dois é igual a três? Isso não acontece. Essa é uma operação. Dois é igual a dois? Faz. Essa é uma operação. Dois é igual a dez? Isso não acontece. Essa é uma operação. Dois são iguais a Buffalo Isso não acontece. Essa é uma operação. E então vamos ver a lista mais uma vez. Dez é igual a três? Não tem? Essa é uma operação. Dez é igual a dois, não é? Essa é uma operação. Dez é igual a dez? Faz. Essa é uma operação. Dez é igual a Buffalo? Isso não acontece. Essa é uma operação. Faz Buffalo? Vou apenas abreviá-lo como B aqui, então não quero continuar escrevendo Buffalo é igual a três? Isso não acontece. Então essa é uma operação. Buffalo é igual a dois Isso não acontece. Então essa é uma operação. Buffalo é igual a dez? Isso não acontece. Então essa é uma operação. Buffalo é igual a Buffalo? Faz. Então essa é uma operação. E agora, se somarmos todas essas taxas aqui, o que vamos ver é que isso vai ser um, dois, três, quatro, cinco, seis, sete, oito, nove, dez, 11, 12, 13, 14, 15, 16. Então, nessa situação, nossa entrada foi quatro, mas nosso tempo de execução foi aproximadamente 16. E o que isso acaba sendo? Bem, isso acaba por ser quadrado. Então, vamos considerar que se pegássemos quatro e elevássemos ao quadrado, seria igual a 16 E podemos teoricamente pensar sobre isso também. Se expandirmos isso para cinco, teríamos não apenas mais cinco aqui, mas teríamos que multiplicá-lo porque agora também teríamos que verificar um adicional Então, em cada instância, teremos cinco e teremos outras cinco inteiras, o que equivale ao quadrado Então, nessa situação, nosso tempo de execução está ao quadrado E a razão para isso é embora tenhamos dois quatro loops, existe o que é conhecido como aninhamento Nós aninhamos um loop de quatro dentro de outro quatro loop. Então, essa parte aqui. Vamos desenhar isso em vermelho. Essa parte aqui está dentro. Embora essa parte interna também esteja dentro. Então, o que fazemos é absorver o que está do lado de fora. Nós multiplicamos pela entrada do lado de dentro e chegamos ao quadrado E esse será nosso tempo de execução final para essa situação. Então, como eu disse, este curso não é muito específico para escrever código ou superação, mas ainda assim define a teoria, mas achei que isso poderia ajudar a mostrar do que estamos falando esse tempo todo, como o código pode ser realmente analisado para que possamos entender essas E você pode ver que, não importa o que aconteça, acabamos de aprender algo muito importante. Sempre haverá quatro loops, mas quatro loops aninhados sempre existirão quantos aninhados existirem Então, se este aqui aninhasse um terceiro, essa seria uma fórmula de n ao quadrado, e você começa a formar números muito grandes para começar a verificar todas essas coisas Então, espero que esse exemplo prático ajudado você a entender esse conceito um pouco melhor. 7. Exemplo de estrutura de dados: Então, agora vamos discutir um exemplo um pouco mais concreto. E vamos discutir a diferença entre uma matriz e uma lista e como isso vai se relacionar com o que estamos aprendendo? E o que estamos aprendendo é escalabilidade, armazenamento de informações e como isso reage com o tempo de execução à medida que obtemos mais e mais Então, com esses dois exemplos aqui , analisaremos uma matriz e veremos uma lista e veremos seu acesso e adicionaremos aos tempos de retorno dessas matrizes Então, com isso, o que vamos ver é como isso se expande ao longo do tempo com essas duas maneiras diferentes de armazenar dados? Como podemos usar essa análise para descobrir qual solução gostaríamos de usar no futuro. Vamos dar uma olhada rápida. Vamos fazer uma visão geral do que essas estruturas de dados são, uma visão geral muito leve. Você não precisa saber muito de ciência da computação para acompanhar esta lição, mas será muito importante adicionar um elemento concreto ao que estamos aprendendo. Então, a primeira estrutura de dados que vamos examinar aqui é a matriz. Então, com uma matriz, o que estamos basicamente fazendo é pegar uma parte dos dados contínuos da nossa memória Agora, o processador basicamente nos dirá onde vamos pegar isso Pode ser a memória RAM , pode ser o cache. Pode ser o disco rígido. Isso não importa. Nesse caso, é a memória, e isso é tudo o que precisamos saber. Então, com a memória, basicamente, estamos separando toda a nossa memória em pequenos blocos de dados Quando pedimos ao processador uma matriz, ele encontra um pequeno pedaço de memória para nós. Isso é contínuo e pode se encaixar no que estamos solicitando. Nesse caso, estamos solicitando quatro dados aqui Portanto, é um tamanho de matriz de quatro. Agora, quando fazemos isso, estamos criando, é contínuo, mas por outro lado, não temos acesso a eles, que significa que, se precisarmos aumentar o tamanho dessa matriz, precisamos criar uma nova matriz e copiar coisas para ela. E essa será a desvantagem. Então, vamos examinar nossos dois aqui, nosso acesso e nosso anúncio. Então, sempre que estivermos acessando dados em uma matriz, o melhor é que eles serão em tempo constante, porque sempre que solicitamos isso, é contínuo. Portanto, podemos solicitar dados muito específicos aqui. Então, se precisarmos descobrir, se precisarmos pegar algo da segunda ou dessa posição, o terceiro lugar na matriz, que é indexado por dois Isso significa apenas que tudo na ciência da computação tem índice zero, então a primeira coluna é zero, não um. Podemos usar essa pequena taxa de fórmula aqui, que funciona basicamente em todas as linguagens de programação. Significa apenas pegar aquele elemento ali mesmo. Ele vai devolvê-lo para nós em tempo constante. Basicamente, exibirá o que está lá em tempo constante Poderíamos ter toneladas e toneladas de informações. Isso pode durar 2000. Isso pode ter 3.000 de comprimento. Isso poderia ser 20.000 $30.000 e assim por diante. E se colocarmos isso aqui, vamos recuperá-lo constantemente todas as vezes. E é isso que permite que nossa matriz tenha acesso ao pior cenário possível, em tempo constante. Sempre será constante. Agora, aqui está o problema. Lembra quando eu disse que, ao adicionar ao final disso, se atingirmos nosso limite de matriz, preenchemos a matriz, precisamos solicitar uma nova matriz, o que significa que o módulo de memória basicamente eliminará nossa matriz antiga e, em seguida, encontrará um conjunto maior no qual possamos colocar informações. Bem, para garantir que não percamos nossos dados antigos, temos que copiar cada peça. Mais de um de cada vez. Então, se temos 300.000, 3 milhões, 3 bilhões de entradas, todas elas precisam ser copiadas e cada dado aqui precisa ser E isso é muito, muito importante porque significa que , à medida que o tamanho da nossa matriz, à medida que o número de entradas que temos aumenta, o número de operações que precisamos usar também aumenta E aumenta de forma linear, o que significa que temos o pior cenário de O ao adicionar a uma matriz. Então, agora, cobrimos a matriz muito bem. Vamos dar uma olhada aqui em nossa outra estrutura de dados. A lista. A lista é interessante porque o que estamos fazendo com uma lista é basicamente acessar nossos dados aqui. Estamos solicitando isso. E, em vez de nos fornecer dados contínuos , basicamente nos fornece um elemento por vez. Então, podemos solicitar um, ele estará aqui. Solicitamos outro. Ele cria um ponteiro e depois vai para aquela peça. Queremos outro. Bem, vai passar por aqui, e assim por diante. E você pode ver que não há uma maneira realmente definida de fazer isso. Tenho certeza de que, você sabe, os módulos de memória avançados e tudo mais têm uma forma eficiente, mas não serão contínuos. Eles estarão em todo lugar da maneira mais eficiente que acharem melhor. Ou seja, se estamos tentando acessar nossas informações e queremos pegar essa informação aqui, bem, veja essa bagunça aqui Temos que seguir o ponto. Então, temos que começar aqui e ir aqui. Então aqui, depois aqui, depois aqui. E, Oh, aí está nosso dado. E isso significa que, quando acessamos nossos dados, se estamos tentando encontrar algo no final da lista, algo mais distante, e, você sabe, pode ser algo como um número, uma letra, uma frase, uma imagem, qualquer coisa Vamos colocar PE aqui. Para chegar a P, precisamos executar toda a lista vinculada para encontrá-la. Então, qual é o nosso tempo de acesso? Bem, isso não parece constante. Parece que, à medida que o número de elementos aumenta, nosso tempo de acesso também aumenta, que parece ser o acesso, na pior das hipóteses, seja, um tempo linear até a entrada. Agora, a lista tem a vantagem da matriz com a adição, desde que mantenhamos o que é conhecido como ponteiro para trás, que é essencialmente apenas um dado que atualizamos, de forma que seja uma seta direta para trás Então, se adicionarmos uma nova peça, basicamente pegamos aquela flecha e a movemos para a nova peça. Se mantivermos isso atualizado, o que é apenas uma única operação constante, bem, adicionar dados a isso é tempo constante. Sempre será exatamente a mesma operação. Apontamos para trás e adicionamos à próxima. Na verdade, neste caso, não temos. Sim, sim, temos. Então, temos o ponteiro traseiro aqui. Portanto, se precisarmos adicionar na parte de trás, seguimos o ponteiro de volta até o final da lista de links e, em seguida, adicionamos um novo elemento e atualizamos o ponteiro para o novo É uma operação constante. Mesmo que haja algumas etapas, sempre será a mesma coisa. Se houver 1 bilhão de peças ou uma peça, exatamente as mesmas coisas precisam acontecer. Seguimos o ponteiro traseiro, adicionamos um novo e depois colocamos nossos dados nele Então isso significa que nosso tempo de adição realmente sairá constante. Agora podemos ver que, com essas duas estruturas de dados, temos duas possibilidades diferentes de solução aqui. Se precisarmos de um tempo de acesso rápido, pense na lista em seu telefone, sua lista de contatos em seu telefone. Precisamos de um tempo de acesso rápido com isso. Você não quer encontrar alguém na lista de contatos e ter que esperar que ela pesquise todos os outros dados. Isso não parece nem um pouco eficiente. Isso seria bobagem. E não adicionamos nada a isso com muita frequência. Você sabe, adicionamos um contato aqui e ali, mas não é algo que adicionamos continuamente. Portanto, a matriz pode ser a melhor solução para esse problema específico. Agora, com uma lista, talvez tenhamos uma operação que precise armazenar muitos e muitos elementos ao longo do tempo, mas quase nunca precisa acessá-los. Portanto, precisamos de tempo constante, você sabe, adicionar tempo, mas na verdade não precisamos de muito tempo de acesso. Bem, então estaríamos analisando uma lista dessa solução. Então, o que estamos aprendendo nisso pode ser usado para descobrir melhores soluções para nossos problemas. E neste caso em particular, são problemas de armazenamento na programação de computadores. Mas isso pode se aplicar a outras áreas do mundo da computação e também à vida real. A solução que você tem é escalável. E com isso, podemos ver quais são e quais não são. 8. Projeto com vídeo: Agora que examinamos a notação, a intolerância e toda a escala que acontece O projeto aqui será pegar tudo o que você aprendeu e analisar algo em sua vida e nos dizer qual é o procedimento e, em seguida, qual é o cronograma. Então, isso pode estar relacionado à ciência da computação. Você pode criar um algoritmo, um algoritmo de busca ou pensar em, você sabe, como uma solicitação de amizade no Facebook pode funcionar ou algo parecido, mas também pode ser apenas observacional ao seu redor Pode ser como eu disse no início do curso, como um arquivo ou como alguém pode se juntar a um membro da sua organização ou como você pode pesquisar e encontrar algo em um grande conjunto de dados ou em um grupo de pessoas ou qualquer coisa dessa natureza Eu quero que você seja criativo e apenas analise o mundo ao seu redor com o conhecimento que você aprendeu e compartilhe. É um exercício muito divertido, e é muito legal ver que basicamente o que estamos fazendo é apenas matemática aplicada sempre que estamos programando ou trabalhando com esse tipo de teoria da matemática em si Se estamos aplicando isso, estamos aprendendo como o mundo funciona e opera e, em seguida, estamos interagindo com ele. E é disso que trata este projeto. Para criar um pensamento crítico e depois analisá-lo e reforçar o que aprendemos Estou muito empolgada em ver o que todos inventam e estarei na seção de projetos respondendo a eles. Então, pronto, obrigado a todos por participarem deste curso.