English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Implementazione completa dell'algoritmo B-Tree in Java

definizione

In informatica, l'albero B (inglese: B-tree) è un albero auto-bilanciato che può mantenere i dati ordinati. Questa struttura dati permette di completare le operazioni di ricerca dei dati, accesso sequenziale, inserimento e cancellazione in tempo logaritmico.

Perché introdurre l'albero B?

Prima di tutto, inclusi i red-black tree che abbiamo introdotto prima, sono memorizzatimemoriadi un tipoalbero di ricerca interno.

mentre l'albero B è un'estensione dell'algoritmo di albero bilanciato precedente, che supporta la conservazionedisco o retesimboliricerca esternaQuesti file potrebbero essere molto più grandi di quelli che abbiamo considerato prima (difficili da memorizzare in memoria).

Se il contenuto è salvato su disco, naturalmente sarà causato da una profondità di albero eccessiva che causa una lettura e scrittura I/O su disco eccessivamente frequente (la velocità di lettura e scrittura del disco è limitata), portando a una bassa efficienza di query.

Quindi ridurre la profondità dell'albero è naturalmente molto importante. Pertanto, abbiamo introdotto l'albero B, l'albero di ricerca a multipli vie.

Caratteristiche

Ogni nodo dell'albero può avere al massimo m figli (m>=2);

Oltre al nodo radice e ai nodi foglia, ogni altro nodo ha almeno [ceil(m / 2)] figli (dove ceil(x) è una funzione che prende il valore superiore);

Se il nodo radice non è un nodo foglia, allora ha almeno 2 figli (caso speciale: nodo radice senza figli, ovvero il nodo radice è un nodo foglia, l'albero ha solo un nodo radice);

Tutti i nodi foglia appaiono nello stesso livello (il livello più basso),I nodi foglia sono nodi esterni, che salvano il contenuto, ovvero key e value.

Altri nodi sono nodi interni, che salvano l'indice, ovvero key e next.

Chiavi dei nodi interni key: K[1], K[2], …, K[M-1]; e K[i] < K[i+1];

Puntatori ai nodi di contenuto next: P[1], P[2], …, P[M]; dove P[1] punta all'albero figlio con chiavi minori di K[1], P[M] punta all'albero figlio con chiavi maggiori di K[M-1], gli altri P[i] puntano agli alberi figli con chiavi appartenenti a (K[i-1], K[i]);

Ad esempio: (M=3)

Ricerca e inserimento

Per facilità, è stato utilizzato una chiave sentinella speciale, che è minore di tutte le altre chiavi, rappresentata con *.

All'inizio l'albero B contiene solo un nodo radice, e il nodo radice contiene solo la chiave sentinella durante l'inizializzazione.

Ogni chiave all'interno del nodo interno è associata a un nodo, e i sottoalberi radicate in questo nodo, tutte le chiavi sono maggiori o uguali alla chiave associata a questo nodo, ma minori di tutte le altre chiavi.

Queste convenzioni possono semplificare notevolmente il codice.

Codice

Clicca per scaricare.

Questo codice introduce la chiave sentinella, ma l'output del codice la elimina.

Albero B con chiave sentinella nel codice (salva l'immagine localmente per vedere meglio i testi):

Albero B generato dal codice (salva l'immagine localmente per vedere meglio i testi):

public class BTree<Key extends Comparable<Key>, Value> 
{
  // numero massimo di figli per un nodo del B-treno = M-1
  // (deve essere anche e maggiore di 2)
  private static final int M = 4;
  private Node root;    // radice del B-treno
  private int height;   // altezza del B-treno
  private int n;      // numero di coppie chiave-valore nel B-treno
  // helper B-tree node data type
  private static final class Node 
  {
    private int m;               // number of children
    private Entry[] children = new Entry[M];  // the array of children
    // create a node with k children
    private Node(int k) 
    {
      m = k;
    }
  }
  // internal nodes: only use key and next
  // external nodes: only use key and value
  private static class Entry 
  {
    private Comparable key;
    private Object val;
    private Node next;   // helper field to iterate over array entries
    public Entry(Comparable key, Object val, Node next) 
    {
      this.key = key;
      this.val = val;
      this.next = next;
    }
  }
  /**
   * Initializes an empty B-tree.
   */
  public BTree() 
  {
    root = new Node(0);
  }
  /**
   * Returns true if this symbol table is empty.
   * @return {@code true} if this symbol table is empty; {@code false} otherwise
   */
  public boolean isEmpty() 
  {
    return size() == 0;
  }
  /**
   * Returns the number of key-value pairs in this symbol table.
   * @return the number of key-value pairs in this symbol table
   */
  public int size() 
  {
    return n;
  }
  /**
   * Restituisce l'altezza di questo albero B (per debug).
   *
   * @return l'altezza di questo albero B
   */
  public int height() 
  {
    return height;
  }
  /**
   * Restituisce il valore associato alla chiave fornita.
   *
   * @param key la chiave
   * @return il valore associato alla chiave fornita se la chiave è nella tabella dei simboli
   *     e {@code null} se la chiave non è nella tabella dei simboli
   * @throws NullPointerException se {@code key} è {@code null}
   */
  public Value get(Key key) 
  {
    if (key == null) 
    {
      throw new NullPointerException("key must not be null");
    }
    return search(root, key, height);
  }
  @SuppressWarnings("unchecked")
  private Value search(Node x, Key key, int ht) 
  {
    Entry[] children = x.children;
    // nodo esterno al livello più basso dei nodi foglia, esplora
    if (ht == 0) 
    {
      for (int j = 0; j < x.m; j++)       
      {
        if (eq(key, children[j].key)) 
        {
          return (Value) children[j].val;
        }
      }
    }
    // nodo interno ricerca ricorsiva dell'indirizzo next
    else 
    {
      for (int j = 0; j < x.m; j++) 
      {
        if (j+1 == x.m || less(key, children[j+1].key))
        {
          return search(children[j].next, key, ht-1);
        }
      }
    }
    return null;
  }
  /**
   * Inserisce la coppia chiave-valore nella tabella dei simboli, sovrascrivendo il valore vecchio
   * con il nuovo valore se la chiave è già nella tabella dei simboli.
   * Se il valore è {@code null}, questo elimina effettivamente la chiave dalla tabella dei simboli.
   *
   * @param key la chiave
   * @param val il valore
   * @throws NullPointerException se {@code key} è {@code null}
   */
  public void put(Key key, Value val) 
  {
    if (key == null) 
    {
      throw new NullPointerException("key must not be null");
    }
    Node u = insert(root, key, val, height); // nodo destro generato dopo la scissione
    n++;
    if (u == null) 
    {
      return;
    }
    // need to split root重组root
    Node t = new Node(2);
    t.children[0] = new Entry(root.children[0].key, null, root);
    t.children[1] = new Entry(u.children[0].key, null, u);
    root = t;
    height++;
  }
  private Node insert(Node h, Key key, Value val, int ht) 
  {
    int j;
    Entry t = new Entry(key, val, null);
    // external node nodo esterno, anche foglia, situato al livello più basso dell'albero, contiene valori
    if (ht == 0) 
    {
      for (j = 0; j < h.m; j++) 
      {
        if (less(key, h.children[j].key)) 
        {
          break;
        }
      }
    }
    // internal node nodo interno, contiene indirizzi
    else 
    {
      for (j = 0; j < h.m; j++) 
      {
        if ((j+1 == h.m) || less(key, h.children[j+1].key)) 
        {
          Node u = insert(h.children[j++].next, key, val, ht-1);
          if (u == null) 
          {
            return null;
          }
          t.key = u.children[0].key;
          t.next = u;
          break;
        }
      }
    }
    for (int i = h.m; i > j; i--)
    {
      h.children[i] = h.children[i-1];
    }
    h.children[j] = t;
    h.m++;
    if (h.m < M) 
    {
      return null;
    }
    else     
    {  // spezza il nodo
      return split(h);
    }
  }
  // spezza il nodo a metà
  private Node split(Node h) 
  {
    Node t = new Node(M/2);
    h.m = M/2;
    for (int j = 0; j < M/2; j++)
    {
      t.children[j] = h.children[M/2+j];     
    }
    return t;  
  }
  /**
   * Restituisce una rappresentazione stringa di questo B-tree (per debug).
   *
   * @return una rappresentazione stringa di questo B-tree.
   */
  public String toString() 
  {
    return toString(root, height, "") + "\n";
  }
  private String toString(Node h, int ht, String indent) 
  {
    StringBuilder s = new StringBuilder();
    Entry[] children = h.children;
    if (ht == 0) 
    {
      for (int j = 0; j < h.m; j++) 
      {
        s.append(indent + children[j].key + " " + children[j].val + "\n");
      }
    }
    else 
    {
      for (int j = 0; j < h.m; j++) 
      {
        if (j > 0) 
        {
          s.append(indent + "(" + children[j].key + ")\n");
        }
        s.append(toString(children[j].next, ht-1, indent + "   "));
      }
    }
    return s.toString();
  }
  // funzioni di confronto - rendi Comparable invece di Key per evitare cast
  private boolean less(Comparable k1, Comparable k2) 
  {
    return k1.compareTo(k2) < 0;
  }
  private boolean eq(Comparable k1, Comparable k2) 
  {
    return k1.compareTo(k2) == 0;
  }
  /**
   * Unit tests the {@code BTree} data type.
   *
   * @param args the command-line arguments
   */
  public static void main(String[] args) 
  {
    BTree<String, String> st = new BTree<String, String>();
    st.put("www.cs.princeton.edu", "128.112.136.12");
    st.put("www.cs.princeton.edu", "128.112.136.11");
    st.put("www.princeton.edu", "128.112.128.15");
    st.put("www.yale.edu", "130.132.143.21");
    st.put("www.simpsons.com", "209.052.165.60");
    st.put("www.apple.com", "17.112.152.32");
    st.put("www.amazon.com", "207.171.182.16");
    st.put("www.ebay.com", "66.135.192.87");
    st.put("www.cnn.com", "64.236.16.20");
    st.put("www.google.com", "216.239.41.99");
    st.put("www.nytimes.com", "199.239.136.200");
    st.put("www.microsoft.com", "207.126.99.140");
    st.put("www.dell.com", "143.166.224.230");
    st.put("www.slashdot.org", "66.35.250.151");
    st.put("www.espn.com", "199.181.135.201");
    st.put("www.weather.com", "63.111.66.11");
    st.put("www.yahoo.com", "216.109.118.65");
    System.out.println("cs.princeton.edu: " + st.get("www.cs.princeton.edu"));
    System.out.println("hardvardsucks.com: " + st.get("www.harvardsucks.com"));
    System.out.println("simpsons.com:   " + st.get("www.simpsons.com"));
    System.out.println("apple.com:     " + st.get("www.apple.com"));
    System.out.println("ebay.com:     " + st.get("www.ebay.com"));
    System.out.println("dell.com:     " + st.get("www.dell.com"));
    System.out.println();
    System.out.println("dimensione:  " + st.size());
    System.out.println("altezza: " + st.height());
    System.out.println(st);
    System.out.println();
  }
}

Output:
cs.princeton.edu: 128.112.136.12
hardvardsucks.com: null
simpsons.com: 209.052.165.60
apple.com: 17.112.152.32
ebay.com: 66.135.192.87
dell.com: 143.166.224.230

dimensione: 17
altezza: 2
          www.amazon.com 207.171.182.16
          www.apple.com 17.112.152.32
          www.cnn.com 64.236.16.20
     (www.cs.princeton.edu)
          www.cs.princeton.edu 128.112.136.12
          www.cs.princeton.edu 128.112.136.11
          www.dell.com 143.166.224.230
(www.ebay.com)
          www.ebay.com 66.135.192.87
          www.espn.com 199.181.135.201
          www.google.com 216.239.41.99
     (www.microsoft.com)
          www.microsoft.com 207.126.99.140
          www.nytimes.com 199.239.136.200
(www.princeton.edu)
          www.princeton.edu 128.112.128.15
          www.simpsons.com 209.052.165.60
     (www.slashdot.org)
          www.slashdot.org 66.35.250.151
          www.weather.com 63.111.66.11
     (www.yahoo.com)
          www.yahoo.com 216.109.118.65
          www.yale.edu 130.132.143.21

Questo è tutto il contenuto dell'articolo, speriamo che sia utile per la tua apprendimento e che tu sostenga fortemente il tutorial urla.

Dichiarazione: il contenuto di questo articolo è stato raccolto da Internet, di proprietà del rispettivo autore, il contenuto è stato caricato autonomamente dagli utenti di Internet, il sito web non detiene i diritti di proprietà, non è stato editato manualmente e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una e-mail a notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare il problema e fornire prove pertinenti. Una volta verificata, il sito eliminerà immediatamente il contenuto sospetto di violazione del copyright.

Ti potrebbe interessare