Utilizando API JavaScript no Oracle APEX

Este será um artigo curto em uma série de postagens mostrando como utilizar a API JavaScript disponibilizada para o Oracle Application Express (APEX).

É comum que sistemas precisem de mensagens de alerta e confirmação quando certas ações ocorrem. Podemos querer avisar o usuário que a assinatura dele está para expirar ou queremos garantir que ele não está apagando um registro sem querer.

Solução com JavaScript puro

A um tempo atrás, seria usado o alert e confirm:

alert(“teste”);

confirm(“Você tem certeza que deseja excluir este item?”);

Que fazem o papel desejado, no entanto são um tanto simples e não se adaptam ao layout da página. Mas se estes itens te atendem ao seu projeto, você pode parar de ler aqui e acessá-los diretamente por ações dinâmicas no sub-item notification conforme a imagem abaixo:

Solução com Region e Ação Dinâmica:

Além da opção com JavaScript puro, no Apex você pode:

  • Criar uma Region;
  • Dar a posição Inline Dialog a ela;
  • Definir seu template como Inline Dialog ou Inline Popup;
  • Criar ou adicionar a uma ação dinâmica do tipo Open Region.

Então isso vai permitir abrir uma tela em branco que você precisa tratar:

Para telas simples e repetitivas como um alert e um confirm é muito trabalho que acaba sendo multiplicado pelo tamanho do seu sistema e necessidade. Mas novamente, se você tem uma necessidade mais sofisticada, ai acima está a solução

Solução com a API JavaScript

Uma solução muito boa que é disponibilizada para podermos chamar uma tela de aviso é através da API JavaScript para o APEX. Neste caso, podemos nos valer de diversas chamadas com efeitos visuais diferentes que ajudam a dar uma cara melhor e a padronizar a sua aplicação.

apex.message.alert(mensagem, callback)

Através desta função podemos chamar em tempo de execução um alert pronto para exibir qualquer mensagem. Caso você queria executar alguma coisa após o alert ser fechado pelo usuário, basta passar um callback como segundo parâmetro. Senão nem precisa informá-lo.

apex.message.alert(“Olá Mundo”);

apex.message.confirm(mensagem, callback)

Similar ao alert, o confirm tem a mesma estrutura e parâmetros. Como ele espera que o usuário clique em OK ou Cancelar, é mais importante termos uma função de callback para verificar o que foi clicado.

apex.message.confirm("Você concorda?\n Clique em OK para continuar.", function( okPressed ) {
    console.log(`Pressionou no OK: ${okPressed}`);
});

apex.message.showPageSuccess( mensagem )

Caso você queira algo menos intrusivo e que seja apenas uma mensagem na tela para seus usuários, vale a pena testar a função showPageSucess que precisa apenas de uma string para saber qual texto exibir. O mesmo deverá aparecer no canto superior da tela (se você não alterou o CSS dele).

apex.message.showPageSuccess("Algo aconteceu com sucesso!!");

Encerrando

Então era isso ai. Essas são algumas das formas mais simples de mostrar informações dentro do apex. Elas não são as únicas e caso você tenha duvidas ou precisa de algo mais especifico, vale a pena conferir a documentação neste link:

https://docs.oracle.com/database/apex-5.1/AEAPI/apex-message-namespace.htm

Gostou deste artigo? Comente abaixo!

Angular vs ReactJS: Qual o Framework Front-End mais requisitado de 2020

Olá pessoal, o primeiro semestre de 2020 foi uma época cheia de mudanças. Ainda assim, permanece a eterna batalha entre Angular e React. Antes de iniciar a comparação, esclareceremos alguns pontos sobre ambas as tecnologias:

Angular:

Desenvolvido pelo Google e lançado pela primeira vez em 2010, é um framework de desenvolvimento front-end com uma boa estrutura, um ecossistema próprio, regras rígidas e um estilo de código declarativo. Possui uma profunda curva de aprendizado, bastante difícil, mas depois de possuir todas as possibilidades do Angular, ele auxiliará a criação do seu projeto.

Baseado na arquitetura MVC (Model-View-Controller), fornece aos desenvolvedores as peças fundamentais que são necessárias para projetar aplicativos móveis e da web.

React

React foi criado em 2011 e foi criado pelo Facebook. É uma biblioteca front-end que oferece uma oportunidade de construir uma excelente UI. Fácil de ler, escrever e integrar com outras estruturas JavaScript. Com React, você não utiliza somente a lógica do desenvolvedor, mas também a imaginação. Possuindo um ambiente de desenvolvimento flexível, amplia os horizontes de pensamento do desenvolvedor.

Oportunidades

Angular:

Desenvolvido para facilitar a criação de aplicativos nativos e híbridos ricos em recursos, como um SPA ou MPA.

React:

Tem por objetivo expandir as interfaces de usuário complexas, principalmente em apps web e móveis para Android e iOS.

Template Language

Angular:

Utilizando TypeScript, é adequado para desenvolvimento de apps complicados e você não queira perder seu tempo detectando bugs, pois o TypeScript ajuda a detectá-los mais cedo.

React:

Escrito em JavaScript, pode ser utilizado com diversos tipos de aplicações devido ao suporte e integração em outras linguagens.

Performance

Angular:

Funcionando de maneira mais devagar que o React, mas ainda com velocidade satisfatória, o Angular inclui todas as etapas, desde a criação de um projeto até a otimização de código.

React:

Rápido devido à forma como foi concebido, adiciona eficiência e simplicidade ao desenvolvimento de apps.

E qual escolher para ser um desenvolvedor sob demanda?

Escolha o Angular quando precisar:

  • Desenvolver aplicativos ricos em recursos;
  • Estrutura confiável e estável;
  • Desenvolver um app em tempo real, com base em bate-papo ou mensagens;
  • Aplicativos nativos, híbridos ou web que deveriam ser projetos de investimento substanciais;
  • Código em TypeScript;
  • Programação orientada a objetos.

Escolha o Angular quando precisar:

  • Desenvolver app’s modernos e leves a nível empresarial em um curto espaço de tempo;
  • Estrutura flexível, fornecendo soluções seguras de desenvolvimento de sites;
  • Aplicativos de plataforma cruzada ou SPA;
  • Expander a funcionalidade do aplicativo existente;
  • Forte apoio da comunidade.

Tendências:

De acordo com o NPM Trends, o React é mais popular em 2020:

Tendências NPM

O StackOverflow Trends oferece uma visão diferente da situação. De 2014 a 2019, o React e Angular tiveram quase a mesma popularidade, mas o React se tornou um líder nesta corrida:

Tendências de estouro de pilha

Conclusão:

Levando em consideração as estatísticas, o React é a estrutura mais demandada em 2020. Mesmo assim, escolha o seu framework ou biblioteca de acordo com sua necessidade de trabalho e experiência.

Gostou deste artigo? Comente abaixo!

Referências: https://techstory.in/angular-vs-reactjs/

Introdução ao gRPC com Node.js

Introdução

Muitos desenvolvedores estão comentando e utilizando gRPC no seu dia dia, mas o que ele realmente ele é? e quais as vantagens de se utilizar ele?

Em um breve resumo nós temos:

gRPC foi desenvolvido pelo Google com foco em ser um serviço de alto desempenho para atender chamadas RPC (Remote Call Procedures) ou no português “Chamada de protocolo Remoto”. Ele é open source e pode ser executado em qualquer ambiente, independentemente de linguagem de programação ou plataforma. O gRPC tem suporte a load balancetracinghealth-check autenticação.

Mas o que é exatamente o RPC (Remote Call Procedures)?

RPC (Remote Procedure Call) é uma tecnologia para desenvolvimento de programas distribuídos client/server de comunicação de alto nível no sistema operacional. (deinfo.uepg.br)

gRPC trabalha com Protobuf (Protocol buffers), método criado e utilizado pelo Google para serializar dados estruturados, tornando a comunicação entre serviços mais eficiente. Ele é uma forma simples e agnóstica com relação a linguagem de se definir uma estrutura de dados como XML, só que mais rápido e mais simples.

Agora falando sobre os benefícios de se utilizar o gRPC:

  • A estrutura RPC é mais leve e de alto desempenho
  • Ele esta disponível para várias linguagens de programação
  • Tem suporte a chamada bidirecional de streaming entre client/server
  • Com a serialização do Protobuf, nós temos uma redução no trafego de dados na rede

Agora para ficar mais claro, vamos criar um exemplo prático de gRPC utilizando o Node.js

Exemplo prático

Para que você possa ter uma visão geral sobre esse assunto eu irei criar dois exemplos, um demonstrando o gRPC rodando no lado do servidor e um outro no lado do cliente.

O primeiro passo será a criação de um novo projeto. Para isso, abra um terminal no seu computador, escolha um diretório e execute o comando abaixo:

npm init -y

Esse comando deve criar um arquivo chamado package.json com as informações iniciais do seu projeto.

Com essa etapa OK e ainda no seu terminal, execute o comando abaixo para importar a biblioteca grpc para o seu projeto:

npm install --save grpc

Conforme comentado na introdução desse artigo, para trabalhar com gRPC nós precisamos criar os nossos arquivos Protobuf . Crie um novo arquivo chamado notes.proto na raiz do seu projeto e atualize ele com o seguinte trecho de código:

syntax = "proto3";

service NoteService {
    rpc List (Empty) returns (NoteList) {}
}

message Empty {}

message Note {
   string id = 1;
   string title = 2;
   string content = 3;
}
message NoteList {
   repeated Note notes = 1;
}

Analisando o trecho de código acima nós temos:

  • syntax: versão do protocol buffer language que nós estamos utilizando
  • note: model com 3 propriedades (id,title e content). Obs.: Os valores 1,2 e 3 são os indixes de cada propriedade
  • NoteService: método aceitando Empty em caso de mensagem vazia e retornando NoteList
  • NoteList: mensagem que sera retornada. No nosso exemplo deve retornar um array de note

Com o arquivo .proto criado, vamos criar o arquivo de configuração do nosso server. Para isso, crie um novo arquivo na raiz do seu projeto chamado index.js e atualize ele com o trecho de código abaixo:

const grpc = require('grpc')
const notesProto = grpc.load('notes.proto')

const notes = [
    { id: '1', title: 'Note 1', content: 'Content 1' },
    { id: '2', title: 'Note 2', content: 'Content 2' }
]
const server = new grpc.Server();

server.addService(notesProto.NoteService.service, {
    list: (_, callback) => {
        callback(null, notes)
    },
})
server.bind('127.0.0.1:50051', grpc.ServerCredentials.createInsecure())
console.log('Server running at http://127.0.0.1:50051')
server.start()

Analisando o trecho de código acima nos temos:

  • 1: chamada do pacote ‘grpc
  • 2: estamos carregando o arquivo .proto
  • 4 a 7: Objeto que iremos enviar para o nosso server. Note que ele tem as mesmas propriedades do nosso arquivo .proto (id, title e content).
  • 8: criação do server gRPC
  • 10 a 13: estamos passando o arquivo .proto para o server
  • 15 a 17: subindo o server na porta 50051

Com o arquivo .proto definido e o server OK, vamos criar o nosso client. Para isso, crie um novo diretório no seu projeto chamado client e dentro dele dois novos arquivos: client-grpc.js e get_notes.js, em seguida atualize eles com os seguintes trechos de código:

client-grpc.js

const grpc = require('grpc')
const PROTO_PATH = '../notes.proto'
const NoteService = grpc.load(PROTO_PATH).NoteService

const client = new NoteService('localhost:50051',
    grpc.credentials.createInsecure())
    
module.exports = client

Analisando o trecho de código acima nos temos:

  • 2: estamos passando o arquivo do arquivo .proto
  • 5: criando uma chamado com o server

get_notes.js

const client = require('./client-grpc')

client.list({}, (error, notes) => {
    if (!error) {
        console.log(notes)
    } else {
        console.error(error)
    }
})

Analisando o trecho de código acima nos temos:

  • 1: importando o modulo criado no passo anterior
  • 3 a 9: chamando o metodo List RPC e retornando os dados na console

Obs.: o método list e o mesmo que foi definido no arquivo .proto e na criação do service no arquivo index.js

Agora para testar os passos anteriores, abra dois terminais no seu computador e execute os comandos abaixo:

para executar o server:

node index.js

para executar o client:

cd client 
node .\get_notes.js

Abaixo você tem um print do projeto executando no meu computador, com o retorno esperado:Image for post

Bom, com isso nos finalizamos mais um artigo 😉 caso tenha interesse em clonar a versão final do projeto demonstrado aqui, segue link dele no meu GitHub: node-grpc.

Espero que tenham gostado e até um próximo artigo pessoal.

Referências: https://medium.com/xp-inc/introdu%C3%A7%C3%A3o-ao-grpc-com-node-js-98f6a4ede11

O que é necessário para ser um Desenvolvedor JavaScript Senior?

Ainda é totalmente possível se tornar um desenvolvedor JavaScript sem possuir alguma graduação. Mas geralmente, os empregadores preferem indivíduos que possuam qualificações em ciência da computação. Para se tornar um desenvolvedor JavaScript sênior, algumas coisas podem se tornar necessárias, como:

  • Uma graduação com foco em desenvolvimento de software. Extremamente adequado para quem deseja se tornar um desenvolvedor de sucesso, apesar de não-obrigatório;
  • Consiga um estágio. Um estágio auxiliará você a obter experiência e orientação de desenvolvedores experientes;
  • Conclua um curso online ou presencial de JavaScript. Existem cursos muito bons que ensinam os fundamentos e conceitos avançados da linguagem que serão úteis no desenvolvimento de sua carreira de desenvolvedor JavaScript.

Carreira:

Existem degraus de carreira no desenvolvimento JavaScript. Em cada degrau, há uma fase de transição que requer a construção de conhecimento e experiência em uma área específica.

Júnior:

Um desenvolvedor júnior é alguém que acabou de ser inserido no mercado de trabalho e trabalha com diversos profissionais para resolver as demandas de uma organização. Como o JavaScript é principalmente (mas não em todo) para desenvolvimento do front-end, o desenvolvedor JavaScript provavelmente trabalhará em aplicativos web, adicionando funcionalidades adicionais ao código base existente ou corrigindo aplicações já existentes.

Pleno:

O desenvolvedor pleno é um colaborador competente da equipe, e já aprendeu as habilidades necessárias para criar um sistema básico, como aplicações ou aplicações web. Neste período, o desenvolvedor aprenderá habilidades como:

  • Arquitetura básica de um sistema;
  • Uso profissional de ferramentas;
  • Padrões de design, code smells.

Sênior:

Altamente qualificado e experiente, outros desenvolvedores consideram-no um mentor. Possuem um bom histórico de soluções de problemas avançados e construção de sistemas complexos usando técnicas avançadas. Algumas características do desenvolvedor JavaScript sênior são:

  • Padrões de design, refatoração de código;
  • Sólida compreensão de paradigmas arquitetônicos de sistemas;
  • Experiência com implantações de servidores e manutenção de infraestrutura.

O caminho para se tornar um desenvolvedor JavaScript sênior:

Já foram mostrados os estágios da carreira de desenvolvimento em JavaScript. Agora, as transições na carreira:

De um simples criador de scripts a um desenvolvedor Júnior:

Um criador de scripts não é pago pela codificação, mas a faz em seu tempo livre por diversão. A transição ocorre quando você obtém sua primeira posição paga como desenvolvedor. Como desenvolvedor JavaScript júnior, você transformará os requisitos de negócios em aplicações e usará as ferramentas necessárias para resolver problemas do mundo real.

  • Comunique claramente suas metas a cada dia de trabalho;
  • Desenvolva uma estratégia antes de tocar em códigos. Divida os problemas em pequenas partes;
  • Documente o que você aprendeu.
  • Leia livros e artigos da sua área, realizando pesquisas diárias;
  • Participe de comunidades de desenvolvedores, contribuindo em projetos de código aberto e participando de conferências.

De júnior para pleno:

Você sabe que chegou neste nível quando conhece tudo o que precisa saber para arquitetar um sistema. Você sentirá que JavaScript é a única linguagem que você precisará utilizar.

Os desenvolvedores plenos levam o conhecimento e habilidade do desenvolvedor júnior para o próximo nível, ganhando experiência no processo. Neste ponto você irá:

  • Ingressar em um projeto de alta visibilidade, ganhando experiência rapidamente, criando reputação dentro da sua empresa;
  • Estar pronto para enfrentar desafios além da zona de conforto, criando confiança e reputação;
  • Encontrar um bom mentor para auxiliá-lo quando necessário;
  • Aprender e testar novas ideias e conceitos.

De pleno para sênior:

Fluente em JavaScript, lida com preocupações e projetos de arquitetura de alto nível. Possui anos de experiência na criação de aplicativos Web e orienta outros desenvolvedores em sua equipe. É necessário muita prática e experiência para se acostumar com a variedade de problemas do mundo real e suas soluções. Você precisará:

  • Encontrar sua stack de tecnologia, utilizando todos os serviços da tecnologia escolhida para criar e executar um único aplicativo, com o qual você desejará ter conhecimentos e aprendê-lo em profundidade;
  • Ter coragem de assumir projetos desafiadores oferecidos a você;
  • Sair da zona de conforto e trabalhar em diversos projetos – mesmo aqueles fora de sua experiência;
  • Acompanha suas habilidades de crescimento e determine quais você deseja expandir;
  • Compreenda bem os padrões de design e saiba quais problemas cada padrão resolve. Garanta sempre que você está aprendendo coisas novas no seu trabalho. Caso fique estagnado, talvez seja hora de seguir em frente.

Palavras finais:

Os desenvolvedores estão hoje com uma demanda maior que nunca, tendo muitas oportunidades para desenvolvedores sênior JavaScript. O JavaScript é a habilidade de TI mais requisitada (Segundo o Top 2020 Skills Report) e mais de 72% das empresas procuram desenvolvedores JavaScript. Com a crescente popularidade, há muita necessidade de desenvolvedores JavaScript agora e futuramente. Agora é a hora de começar a planejar a carreira de desenvolvedor JavaScript e trabalhar nessa direção. Dependendo da sua determinação, você pode subir rapidamente na carreira e torna o desenvolvedor JavaScript sênior que está se esforçando para se tornar mais rápido que o esperado.

Referências: https://www.itpro.co.uk/business-strategy/careers-training/356608/how-to-become-a-senior-javascript-developer

Criando Auto-Refresh com Live-Server (NodeJS)

Olá pessoal,  neste artigo criaremos um servidor com NodeJS que atualizará a sua página web automaticamente sempre que houver uma alteração no código. Para isso, utilizaremos o Live-server, um pacote para Node que auxilia na criação de um servidor em tempo real.

O Live-Server é um pequeno servidor para desenvolvimento com a capacidade de atualizar a página ao vivo, dispensando a necessidade de instalação de plug-in para o navegador ou adicionar códigos para inicializar a função de atualização de página.

Para instalar o live-server, você precisa do npm. Utilize o seguinte código para instalação:

npm install -g live-server

Começando:

Crie uma pasta com o nome do seu projeto. Neste tutorial, criarei uma pasta chamada Live_node. Precisamos criar o nosso arquivo package, que conterá os dados de nosso projeto. Utilize o seguinte comando para criar o seu package de forma rápida:

npm init --yes

Com nosso package criado e dependência instalada, vamos começar criando um arquivo index.html. Esse arquivo será nossa página principal.

<!DOCTYPE html>
<html lang="pt-br">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Live_node</title>
<link rel="stylesheet" href="main.css">
</head>
<body>
  <h1> Olá Mundo </h1>  
</body>
</html>

Criaremos também um main.css para estilizar nossa página. Adicione os seus arquivos index.html e main.css dentro de uma pasta chamada public.

No nosso arquivo main.css, adicionaremos um background-color no nosso body e também, alteraremos a cor das letras:

body{
    background-color: black;
    color: #fff;
}

Com isso, temos nosso Body na cor preta e as letras na cor branca.

Agora, no seu terminal, adicione o seguinte comando:

live-server public

Esse comando fará nosso código rodar, atualizando o navegador automaticamente. É importante salientar que este comando deve ser executado em modo administrador no seu powershell/prompt/terminal. Pode acontecer de ocorrer a necessidade de adicionar o npm em suas variáveis de ambiente no windows. Caso você não saiba como fazer isso, este link pode ajudá-lo a realizar este procedimento.

Caso você não queria adicionar o live-server globalmente na sua máquina, e sim somente no seu projeto, retire o -g na instalação do server. Caso você opte por esta opção, um procedimento deve ser feito para que ocorra a execução e atualização em tempo real da sua página. No seu arquivo package.json, altere o seguinte:

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1"
},

Para:

"scripts": {
  "dev": "live-server public"
},

E, por fim, no seu terminal, execute o comando:

npm run dev

Este comando iniciará o script “dev” que inserimos no nosso package.json e, com isso, iniciará o live-server! O live-server inicia por padrão na porta 8080, mas você pode alterá-lo incluindo no seu script do package.json:

"scripts": {
  "dev": "live-server public --port=3000"
},

Com isso, você pode escolher a porta a ser utilizada. Para mais detalhes sobre o live-server, acesse a documentação em:

https://www.npmjs.com/package/live-server

Gostou deste artigo? Comente abaixo!

Criando sistema de login com NodeJS parte 1

Neste artigo, começaremos a criar um sistema de login básico utilizando JavaScript. Utilizaremos a ferramenta NodeJS para criar o BackEnd. Utilizaremos as dependências Express, que realiza a parte middleware de nossa aplicação; EJS, para gerar os templates HTML e Nodemon + dotenv, que atualiza a nossa aplicação ao alterar os arquivos.

Então vamos lá:

Para inicializar o projeto, crie uma pasta com o nome Nodejs_Login. Abra essa pasta com o Visual Studio Code ou com seu editor favorito. No terminal, iniciaremos a aplicação com o comando:

npm init

Pressione enter até terminar de configurar o package.json. Não entraremos nos detalhes de configuração do arquivo package.json.

Para instalar as dependências, utilize os seguintes comandos:

npm i express ejs

Para instalar o nodemon e o dotenv:

npm i –save-dev nodemon dotenv

Agora, crie um arquivo chamado .env, que conterá as nossas variáveis de ambiente que poderemos carregar no nosso servidor. Crie também um arquivo chamado .gitignore, que ignora arquivos, não comprometendo nosso ambiente.

Dentro do arquivo .gitignore, adicione:

.env
node_modules

Fazemos isso pois esses arquivos possuem informações confidenciais, que não poderão er compartilhadas.

Dentro do seu package.json, criaremos um script chamado devStart que conterá o nodemon server.js. Isso fará nosso atualizar a cada vez que alterarmos algo no nosso código.

"scripts": {
    "devStart": "nodemon server.js"
}

Começaremos agora a criar o nosso sistema de login!

Crie um arquivo chamado server.js. Esse arquivo conterá o código que iniciará o servidor. Precisamos importar o express:

const express = require('express');
const app = express();

app.set('view-engine', 'ejs');
app.get('/', (req, res) => {
    res.render('index.ejs', {nome: 'João'});
})
app.listen(3000);

Dentro da sua pasta principal, crie uma subpasta chamada views e, dentro dela, um arquivo chamado index.ejs. Esse arquivo conterá o seguinte código:

<h1>Olá <%= nome %></h1>

Continue lendo “Criando sistema de login com NodeJS parte 1”

Aplicativo MundoJS

Olá pessoal. Estamos com uma novidade que vai facilitar muito para você continuar acompanhando os conteúdos disponibilizados no nosso site! Agora, o MundoJS possui um aplicativo disponível para Android. Neste aplicativo, você poderá acompanhar todo o conteúdo, ver vídeos e interagir nos comentários diretamente do seu smartphone. Para baixar, é muito simples:

  • Acesse a Google Play Store no seu dispositivo Android;
  • Faça a pesquisa do app MundoJS;
  • Baixe, instale e divirta-se!

O aplicativo é leve e muito fácil de utilizar. Esperamos que aproveitem e aprovem essa novidade que preparamos para você. Você também pode realizar o download diretamente através do link:

Download aplicativo MundoJS

Gostou desta novidade? Conte-nos nos comentários!

 

Estrutura de Dados e Classes JavaScript: Binary Search Tree

Dando sequência aos nossos artigos de Estruturas de Dados com JavaScript, hoje implementaremos uma Árvore de Busca Binária (Binary Search Tree). Uma árvore é uma coleção de nós conectados por arestas e é uma estrutura não-linear. Uma das principais características de uma árvore binária é que os nós com menor valor são armazenados na sua esquerda, e os nos de valor mais alto são armazenados na direita.

Para começar, criaremos uma classe chamada nó, que servirá de apoio para a criação da nossa Árvore Binária:

class No{
    constructor(data, esquerda = null, direita = null){
        this.data = data;
        this.esquerda = esquerda;
        this.direita = null;
    }
}

Você pode perceber que o nó que criamos possui um dado e mais duas propriedades: esquerda e direita, que possuem valor nulo.

Agora, vamos criar a nossa Árvore:

class ArvoreBuscaBinaria{
    constructor(root = null){
        this.root = null;
    }
}

A nossa árvore possui um nó raiz, que é definido como tendo valor nulo pelo construtor.

Também teremos os métodos principais da nossa árvore binária, que são:

  • Insercao(data);
  • InserirNo(no, novoNo);
  • Remover(data);
  • RemoverNo(no, key).

E os métodos auxiliares, que são:

  • EncontrarMenorNo();
  • EncontrarNoRaiz();
  • EmOrdem(no);
  • PreOrdem(no);
  • PosOrdem(no);
  • Pesquisar(no, data).

Insercao(data) e InserirNo(no, novoNo):

Com o método Insercao(data), inseriremos um novo nó na nossa árvore binária com o valor especificado. Esse método cria um nó a ser inserido e chamará o método InserirNo para isso. Então precisamos: Criar um novo nó e inicializá-lo com o dado a ser utilizado e, se a raiz estiver vazia, esse novo dado será a raiz da árvore. Senão, chamaremos o método InserirNo para achar a posição correta na árvore e adicionar o nó.

Insercao(data){
    let novoNo = new No(data);
    
    if (this.root === null){
        this.root = novoNo;
    } else {
        this.InserirNo(this.root, novoNo);
    }
}

O método InserirNo(no, novoNo) verifica em qual parte da árvore o nó deve ser inserido e coloca-o no lugar correto. Se o dado a ser inserido for menor que o nó raiz, o novo dado deve ir para a esquerda. Senão, o novo dado deve ir para a direita. O mesmo vale para os outros nós que já estão posicionados, ou seja, acontece uma comparação dos dados fornecidos com os dados do nó atual, movendo-se para a esquerda ou para a direita e recorrendo até encontrar um nó correto para qual o novo nó possa ser adicionado.

InserirNo(no, novoNo){
    if (novoNo.data < no.data){
        if (no.esquerda === null){
            no.esquerda = novoNo;
        } else {
            this.InserirNo(no.esquerda, novoNo);
        }
    } else {
        if (no.direita === null){
            no.direita = novoNo;
        } else {
            this.InserirNo(no.direita, novoNo);
        }
    }
}

Remover(data) e RemoverNo(no, key):

Para remover dados da nossa árvore binária, utilizamos os métodos Remover(data) e RemoverNo(no, key). O método Remover chama o método RemoverNo passando o nó raiz e dados fornecidos, atualizando a raiz da árvore com o valor que é retornado pela função. O método RemoverNo procura um nó com o dado passado e executa as etapas para excluí-lo. Podemos excluir um nó passando por três cenários diferentes:

  • Apenas um nó folha, que é um nó que não possui filhos. Eles são facilmente removidos.
  • Um nó com filho, que se o nó tiver um filho na parte esquerda, atualizaremos o ponteiro (referência) do nó pai para o filho esquerdo do nó a ser excluído. O mesmo acontece com o filho da parte direita.
  • Um nó com dois filhos, onde encontramos o nó com valor mínimo na parte direita e substituímos esse nó pelo nó com valor mínimo e removemos da árvore.
Remover(data){
    this.root = this.RemoverNo(this.root, data);
}

RemoverNo(no, key){
    if (no === null){
        return null;
    } else if (key > no.data){
        no.direita = this.RemoverNo(no.direita, key);
        return no;
    } else {
        if (no.esquerda === null && no.direita === null){
            no = null;
            return no;
        } 
        if(no.esquerda === null){
            no = no.direita;
            return no;
        } else if (no.direita === null){
            no = no.esquerda;
            return no;
        }
        let aux = this.EncontrarMenorNo(no.direita);
        no.data = aux.data;
        no.direita = this.RemoverNo(no.direita, aux.data);
        return no;
    }
}

Agora, precisamos percorrer a nossa árvore, e isso pode ser feito de diversas formas. Começaremos com o método:

EmOrdem(no):

Esse método percorre a árvore a partir de um nó. Percorre a subárvore esquerda, visita a raiz e percorre a subárvore direita.

EmOrdem(no){
    if (no !== null){
        this.EmOrdem(no.esquerda);
        console.log(no.data);
        this.EmOrdem(no.direita);
    }
}

PreOrdem(no):

Esse método percorre a árvore visitando primeiro o nó raiz e, então, percorre a subárvore esquerda. Após percorrer o lado esquerdo, o método percorre a subárvore direita.

PreOrdem(no){
    if (no !== null){
        console.log(no.data);
        this.PreOrdem(no.esquerda);
        this.PreOrdem(no.direita);
    }
}

PosOrdem(no):

Começa percorrendo a subárvore esquerda, depois, percorre a subárvore direita e por último, visita o nó root.

PosOrdem(no){
    if (no !== null){
        this.PosOrdem(no.esquerda);
        this.PosOrdem(no.direita);
        console.log(no.data);
    }
}

Agora, precisamos declarar métodos auxiliares.

EncontrarMenorNo(no):

Procura o nó com menor valor na árvore binária. Esse método começa a busca a partir de um nó e move-se pela subárvore esquerda até encontrar um nó cujo filho esquerdo é nulo. Uma vez encontrado, retornamos.

EncontrarMenorNo(no){
    if (no.esquerda===null){
        return no;
    } else {
        return this.EncontrarMenorNo(no.esquerda);
    }
}

EncontrarNoRaiz():

Retorna o nó raiz de nossa árvore:

EncontrarNoRaiz(){
    return this.root;
}

Pesquisar(no, data):

Pesquisa o nó com dados que tenham o valor em toda a árvore:

Pesquisar(no, data){
    if (no === null){
        return null;
    }

    else if (data < no.data){
        return this.Pesquisar(no.esquerda, data);
    } else if (data > no.data){
        return this.Pesquisar(no.direita, data);
    } else {
        return no;
    }
}

Agora, precisamos criar uma nova árvore e implementar seus métodos:

let arvoreBinaria = new ArvoreBuscaBinaria();
arvoreBinaria.Insercao(20);
arvoreBinaria.Insercao(25);
arvoreBinaria.Insercao(15);
arvoreBinaria.Insercao(10);
arvoreBinaria.Insercao(28);
arvoreBinaria.Insercao(27);
arvoreBinaria.Insercao(9);
arvoreBinaria.Insercao(7);
arvoreBinaria.Insercao(2);
arvoreBinaria.Insercao(28);

let raiz = arvoreBinaria.EncontrarNoRaiz();

arvoreBinaria.EmOrdem(raiz);
arvoreBinaria.Remover(2);

arvoreBinaria.PosOrdem(raiz);
arvoreBinaria.PreOrdem(raiz);

E nossa saída será:

Gostou deste artigo? Comente abaixo!

Referências: https://www.geeksforgeeks.org/implementation-binary-search-tree-javascript/

Estrutura de Dados e Classes JavaScript: Lista Duplamente Encadeada

A Lista Duplamente Encadeada permite que seja percorrida em duas direções, direita e esquerda, diferentemente da Lista Encadeada simples, que permite que seja percorrido em apenas uma direção. Na Lista Duplamente Encadeada, cada elemento possui uma referência para o próximo elemento e para o elemento anterior, se esse elemento estiver disponível. Assim, podemos viajar para trás e para frente de cada elemento da lista.

Para criar nossa Lista, precisaremos de uma classe principal chamada ListaDuplamenteEncadeada e um classe que nos servirá de apoio, evitando reescrever código, chamada Node. A nossa lista terá um contador, que começará em 0 e, também, uma cabeça (head) e uma cauda (tail), que inicialmente terão o valor null:

class ListaDuplamenteEncadeada {
    constructor(head = null, tail = null, count = 0){
        this.head = head;
        this.tail = tail;
        this.count = count;
    }
}
class Node{
    constructor(data, next = null, previous = null){
        this.data = data;
        this.next = next;
        this.previous = previous;
    }
}

Precisamos também implementar os métodos getHead, getTail e getCount:

getHead(){
    if (this.head) {
        return this.head.data;
    }
    return null;
}

getTail(){
    if (this.tail) {
        return this.tail.data;
    }
    return null;
}

GetCount(){
    return this.count;
}

A nossa lista terá os seguintes métodos:

  • MostrarTudo();
  • MostrarFimInicio();
  • VisualizarEm(index);
  • AdicionarInicio(data);
  • AdicionarFinal(data);
  • AdicionarEm(data, index);
  • RemoverInicio();
  • RemoverFinal();
  • RemoverEm(index).

Vamos lá!

MostrarTudo():

Como o próprio nome já diz, esse método nos mostrará todo o conteúdo da Lista Duplamente Encadeada. Para isso, utilizaremos um Array que conterá todos os dados da lista e percorreremos esse array com um laço FOR. Caso não ocorra a existência de dados na lista, retornará null:

MostrarTudo(){
    if (this.head){
        let arr = [];
        let current = this.head;
        for (let i = 0; i < this.count; i++){
            arr[i] = current.data;
            current = current.next;
        }
        return arr;
    } else {
        return null;
    }
}

MostrarFimInicio():

Esse método retorna um array que contém os dados de trás para frente, ou seja, da cauda para a cabeça (tail to head). Caso esteja vazio, retornará null:

MostrarFimInicio(){
    if (this.head){
        let arr = [];
        let current = this.tail;
        for (let i = 0; i < this.count; i++){
            arr[i] = current.data;
            current = current.previous;
        }
        return arr;
    } else {
        return null;
    }
}

VisualizarEm(index):

Esse método retorna o item no índice indicado. Caso esse índice não exista, retornará null:

VisualizarEm(index){
    if (index > -1 && index < this.count){
        let current = this.head;
        let i = 0;

        while (i++ < index){
            current = current.next;
        }
        return current.data;
    } else {
        return null;
    }
}

AdicionarInicio(data):

Adiciona o elemento ao início da lista. Se a lista estiver vazia, o elemento adicionado será o único da lista:

AdicionarInicio(data){
    let no = new Node(data);
    no.next = this.head;

    this.head = no;

    if (this.count === 0){
        this.tail = this.head;
    } else {
        this.head.next.previous = this.head;
    }
    this.count++;
}

AdicionarFinal(data):

Funciona de maneira semelhante ao método anterior, mas adiciona o elemento ao final da lista:

AdicionarFinal(data){
    let no = new Node(data);
    no.previous = this.tail;

    if (this.count === 0){
        this.head = no;
    } else {
        this.tail.next = no;
    }
    this.tail = no;
    this.count++;
}

AdicionarEm(data, index):

Adiciona o elemento no índice indicado:

AdicionarEm(data, index){
    if (index > 0 && index < this.count){
        let no = new Node(data);
        let current = this.head;
        let i = 0;

        while(i++ < index){
            current = current.next;
        }

        current.previous.next = no;
        no.next = current;
        no.previous = current.previous;
        current.previous = no;
            
        this.count++;
    } else if (index < 1){
        this.AdicionarInicio(data);
    } else {
        this.AdicionarFinal(data);
    }
}

RemoverInicio():

Remove o elemento situado no início da lista:

RemoverInicio(){
    if (this.head){
        this.head = this.head.next;
        this.count--;

        if (this.count === 0){
            this.tail = null;
        } else {
            this.head.previous = null;
        }
    }
}

RemoverFinal():

Remove o elemento situado no final da fila. Não esqueça de decrementar o contador:

RemoverFinal(){
    if(this.head){
        if(this.count === 1){
            this.head = null;
            this.tail = null;
        } else {
            this.tail.previous.next = null;
            this.tail = this.tail.previous;
        }

        this.count--;
    }
}

RemoverEm(index):

Remove o elemento no índice indicado:

RemoverEm(index){
    if (index > 0 && index < this.count-1){

        let current = this.head;
        let i = 0;

        while( i++ < index){
            current = current.next;
        }

        current.previous.next = current.next;
        current.next.previous = current.previous;

        this.count--;
    } else if (index < 1){
        this.RemoverInicio();
    } else {
        this.RemoverFinal();
    }
}

Teste no seu navegador:

let lista = new ListaDuplamenteEncadeada();
lista.AdicionarInicio(1);
lista.AdicionarInicio(4);
lista.AdicionarInicio(5);
lista.AdicionarInicio(6);
lista.AdicionarFinal(2);
lista.AdicionarEm(3, 1);
console.log(lista.VisualizarEm(1));
console.log(lista.MostrarFimInicio());
lista.RemoverEm(2);
lista.RemoverInicio();
lista.RemoverFinal();
console.log(lista.MostrarTudo());

E a saída será:

 

Gostou deste artigo? Comente abaixo!

Estrutura de Dados e Classes JavaScript: Deque

O Deque (Fila duplamente Encadeada) funciona basicamente com uma fila, com a diferença de que você pode adicionar e remover dados de qualquer extremidade da fila. Isso torna o nosso código um pouco mais difícil, mas chegaremos lá. Continuaremos usando class para realizar nossa estrutura de dados. Precisamos, inicialmente, criar a nossa classe Deque. Ela precisará de um início (head), um final (tail) e um contador:

class Deque {
    constructor(head = null, tail = null, count = 0){
        this.head = head;
        this.tail = tail;
        this.count = count;
    }
}

Também precisaremos criar os métodos GetHead, GetTail e GetCount:

GetHead(){
    if (this.head){
        return this.head.data;
    }
    return null;
}

GetTail(){
    if (this.tail){
        return this.tail.data;
    }
    return null;
}

GetCount(){
    return this.count;
}

A nossa fila duplamente encadeada terá os seguintes métodos:

  • MostrarInicioFim();
  • MostrarFimInicio();
  • AdicionarInicio(data);
  • AdicionarFim(data);
  • RemoverInicio();
  • RemoverFim().

Para criarmos nossos métodos, criaremos nosso código de forma diferente aos anteriores. Utilizaremos uma Classe de auxílio, para evitar reescrever código:

class Node{
    constructor(data, next = null){
        this.data = data;
        this.next = next;
    }
}

MostrarInicioFim():

Esse método retorna um array com os dados, percorrendo do início ao fim:

MostrarInicioFim(){
    if (this.head != null){
        let arr = [];
        let current = this.head;
        
        while (current){
            arr.push(current.data);
            current = current.next;
        }
        return arr;
    } else {
        return null;
    }
}

MostrarFimInicio():

Semelhante ao nosso método anterior, ele retorna um array com os dados da fila, porém, percorrendo do fim ao início. Para isso, utilizaremos o reverse():

MostrarFimInicio(){
    if (this.head != null){
        let arr = this.MostrarInicioFim();
        return arr.reverse();
    } else {
        return null;
    }
}

AdicionarInicio(data):

Adiciona o dado no início de nossa fila e, para isso, usaremos nossa classe Node criada anteriormente para auxílio. Precisamos também incrementar o nosso contador:

AdicionarInicio(data){
    let no = new Node(data);
    no.next = this.head;
    this.head = no;

    if (!this.tail) {
        this.tail = this.head;
    }
    this.count++;
}

AdicionarFim(data):

Esse método adicionar o dado no fim da fila. Semelhante ao nosso método anterior, usaremos a nossa classe Node de apoio. Precisamos também, nesse método, incrementar nosso contador.

AdicionarFim(data){
    let no = new Node(data);
    if (!this.head){
        this.head = no;
    } else {
        this.tail.next = no;
    }
    this.tail = no;
    this.count++;
}

RemoverInicio():

Remove o dado que está no início (head) de nossa fila duplamente encadeada.

RemoverInicio(){
    if (this.head){
        if (this.count === 1){
            this.head = null;
            this.tail = null;
        } else {
            this.head = this.head.next;
        }
        this.count--;
    }
}

RemoverFim():

Remove o dado que está na posição final da nossa fila:

RemoverFim(){
    if (this.head){
        if (this.count === 1){
            this.head = null;
            this.tail === null;
        } else {
            let current = this.head;

            while(current.next.next){
                current = current.next;
            }

            this.tail = current;
            this.tail.next = null;
        }
        this.count--;
    }
}

Gostou deste artigo? Comente abaixo!