Como apresentar seus pontos fortes em uma entrevista de emprego

Uma coisa que nunca ensinam o profissional de TI é como se apresentar bem para uma entrevista de emprego. Apesar desta falta de prática acontecer de forma generalizada, para quem tem um trabalho altamente especializado o fato de não conseguir falar quais são suas habilidades chaves pode custar um emprego, uma promoção ou uma ótima oportunidade.

O que falar aos recrutadores?

Durante uma entrevista é importante que você consiga mostrar aos recrutadores o que você tem de melhor. Faça isso utilizando frases breves e contundentes. Utilize palavras chaves e realizações que tem em sua trajetória profissional.
Isso com certeza vai te ajudar a se diferenciar da maioria dos candidatos durante todo processo seletivo. Forme frases utilizando palavras-chave e realizações de acordo com os exemplos abaixo:

Palavras-chave:

  • Dinâmico
  • Busca resultados
  • Criativo
  • Produtivo
  • Motivado
  • Decisivo
  • Receptivo
  • Resiliente
  • Responsável
  • Persistente
  • Adaptável
  • Organizado
  • Solucionador de problemas
  • Etc.

Parece simples? E realmente é, mas você precisa estar com as respostas na ponta da língua para impressionar a pessoa do outro lado.

Agora veja abaixo uma forma bem eficiente de colocar e expressar a importância de suas realizações e como elas contribuíram para o local que você já trabalhou. Se você ainda não possui experiência de trabalho para isso, comece com projetos independentes e fale como você superou desafios neles, isso mostrará sua iniciativa, capacidade e potencial.

Realizações:

  • Um problema que tenha passado;
  • Como fez para superá-lo (método ou ferramentas);
  • Os resultados obtidos.

Aprenda no Ebook Guia do Emprego Novo, como se preparar para os processos seletivos conhecendo o que se passa pela cabeça dos recrutadores. Adquira agora com pelo link: Guia do Emprego Novo e use o cupom MUNDOJS para ter 40% de desconto.

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!

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

TypeScript: Upload de arquivos para o Azure Storage

Veja nesse artigo como fazer upload dos seus arquivos para o Azure Blob Storage

npm i multer-azure-blob-storage --save
import * as multer from 'multer';
import { MulterAzureStorage } from 'multer-azure-blob-storage';


const azureStorage: MulterAzureStorage = new MulterAzureStorage({
    connectionString: 'connectionString',
    accessKey: 'accessKey',
    accountName: 'accountName',
    containerName: 'containerName',
    containerAccessLevel: 'blob',
    urlExpirationTime: 60
});

const uploadAzure = multer({ storage: azureStorage });

export default uploadAzure;

Em seguida, caso esteja acompanhando esse passo a passo utilizando o projeto do meu artigo anterior, atualize o método post dentro do seu arquivo index.ts com o trecho de código abaixo:

app.post('/', uploadAzure.single('file'), (req, res) => {
    if (!req.file) {
        res.send('Erro ao fazer upload do arquivo!');
    } else {
        res.send('Arquivo enviado com sucesso!');
    }
})

Obs.: Não esquece de importar no inicio do arquivo o módulo abaixo:

import uploadAzure from './uploadAzure';

Image for post

2º no campo de pesquisa digite: blob e selecione a primeira opção demonstrada abaixo:

Image for post

3º Clique em create:

Image for post

Image for post

Image for post
Em seguida cole ele dentro da variável connectionString:
Image for post
2º copie o valor de Key (1 ou 2):
Image for post
E cole dentro da variável accessKey
Image for post
3º Copie o valor de Storage account name:
Image for post
E cole em accountName:
Image for post
npm run compile
//esse comando deve fazer o transpile
npm start
//esse comando deve rodar o projeto na porta 3000
Image for post
Acessando agora o nosso serviço Storage accounts, va em -> Storage Explorer -> Blob Containers -> clique no nome do container que você criou e veja a listagem dos arquivos que você fez upload:
Image for post

Referências:https://medium.com/typescript/typescript-upload-de-arquivos-para-o-azure-storage-838fccc83a2e

TypeScript: Union

Dando continuidade a minha serie de artigos sobre TypeScript, hoje eu irei apresentar o Union.

O Union é um dos tipos do TS que nos permite combinar um ou mais tipos de types. Sua sintaxe é um pouco diferente do que eu demonstrei nos últimos artigos, ele utiliza um barra vertical para passar os tipos que ele irá aceitar.

Sintaxe:

(tipo1| tipo2 ...)

Para ficar mais claro, vamos criar alguns exemplos práticos:

let exemploVariavel: (string | number);
exemploVariavel = 123;
console.log(exemploVariavel); //123
exemploVariavel = "ABC";
console.log(exemploVariavel); //ABC

Note que a variável exemploVariavel aceitou os dois valores: 123 (number) e “ABC” string.

Mas ai vem aquela dúvida, ele só aceita dois types? Não, nós podemos passar mais de um type para ele.

let exemploVariavel: (string | number | boolean);
exemploVariavel = 123;
console.log(exemploVariavel); //123
exemploVariavel = "ABC";
console.log(exemploVariavel); //ABC
exemploVariavel = true;
console.log(exemploVariavel); //true

Nós podemos utilizar ele também como parâmetro de função.

function deleteTeste(usuario: string | string[]) {
    if (typeof usuario == "string") {
        console.log(usuario, "deletado");
        //função para deletar um registro
    } else {
        var i;
        for (i = 0; i < usuario.length; i++) {
            //função para deletar mais de um registro
            console.log(usuario[i], "deletado");
        }
    }
}

Nesse exemplo nós podemos passar um registro para o nosso método deleteTeste ou passar um array de registros para serem deletados.

E para finalizar esse artigo, nós podemos utilizar ele também com Arrays.

var arr: (number[] | string[]);
var i: number;
arr = [1, 2, 4]

for (i = 0; i < arr.length; i++) {
    console.log(arr[i])
}

arr = ["A", "B", "C", "D"]

for (i = 0; i < arr.length; i++) {
    console.log(arr[i])
}

Resultado:

Image for post
Resultado union TypeScript

Bom, a ideia desse artigo era apresentar mais um dos types do TS 😉 Espero que tenham gostado e até um próximo artigo pessoal.

Referência: https://medium.com/xp-inc/typescript-union-4c6899ccf408

Comparando os termos utilizados no NoSQL com SQL

SQL

SQL é a sigla utilizada para “Structured Query Language” que traduzindo para o português significa: “Linguagem de Consulta Estruturada”.

NoSQL

NoSQL (Not Only SQL) é o termo utilizado para banco de dados não relacionais. Ele foi desenvolvido para ter uma performance melhor e uma escalabilidade mais horizontal para suprir necessidades onde os bancos relacionais não são muito eficazes.

  • Colunas: Os dados são armazenados em linhas dentro de tabela no disco. Um exemplo de banco de dados neste formato é o Cassandra
  • Grafos: Os dados são armazenados em forma de grafos (vértices e arestas). Um exemplo de banco de dados neste formato é o Neo4j
  • Chave-valor: Em algumas pesquisas e testes realizados pela internet, esta família de banco NoSQL é a que mais aguenta carga de dados, pois o seu conceito é que um determinado valor seja acessado através de uma chave identificadora única. Um exemplo de banco de dados neste formato é o Redis.

Image for post

Image for post
Comparando SQL com NoSQL fonte: (codersera)

Os termos utilizados em cada um deles:

Image for post
Conhecendo os termos entre SQL e NoSQL
Image for post
Comparando as instruções de inserção e consulta no SQL com NoSQL

Referência: https://medium.com/xp-inc/comparando-os-termos-utilizados-no-nosql-com-sql-e862788e2374

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”

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!