Lignum binarium vel quomodo parare arborem quaesiti binarii

In Nomine Patris

Hic articulus est de arboribus quaesitis binariis. Ego nuper feci super articulum data compressione utendi methodo Huffman. Ibi arbores binarias non multum attigimus, quia methodi inquisitionis, insertionis et deletionis non adfuerunt. Nunc articulum de arboribus scribere decrevi. Incipiamus.

Lignum est structura data nodorum constans marginibus connexis. Dici possumus arborem specialem graphi casum esse. Exemplum est hic arbor;

Lignum binarium vel quomodo parare arborem quaesiti binarii

Hoc lignum non binarium quaesitum est! Omnia abscinduntur!

terminology

radix

Arbor radix β€” Haec summa nodi est. In exemplo, haec est nodi A. In arbore, una tantum via ab radice in aliam nodi potest ducere! Revera, quaevis nodi considerari potest ut radix subtidis huic nodi correspondens.

Parentibus / posteris

Omnes nodi praeter radicem unam prorsus habent partem nodi ad alteram ducens. Nodus supra hodiernam sita appellatur parent hac nodo. Nodus infra currenti sito et ei conexus appellatur progenies hac nodo. Utamur exemplo. Sit nodi B, parens node A, et filii eius nodes D, E, F erunt.

sheet

Node quae liberos non habet, folium arboris vocabitur. In exemplo, folia erunt nodes D, E, F, G, I, J, K.

Haec est fundamentalis vox. Aliae notiones ulterius dicentur. Binaria ergo arbor est in qua quilibet nodus non plus quam duos filios habebit. Ut tu suspicabaris, arbor ab exemplo non erit binaria, quia nodi B, H plures quam duo filii habent. Exemplum est arboris binariae;

Lignum binarium vel quomodo parare arborem quaesiti binarii

Nodorum arbor aliqua indicia continere potest. Lignum quaesitum binarium est arbor binaria quae sequentes proprietates habet;

  1. Tam dextra laevaque subtree sunt arbores quaesitae binariae.
  2. Omnes nodi sinistrae subtree nodi X arbitrarii clavem datam habent minus quam valorem clavis nodi X ipsius notitiae.
  3. Omnes nodi in dextra parte nodi arbitrarii X habent valorem clavem datam maiorem quam vel aequalem valore ipsius datae clavis nodi X.

clavem β€” quaelibet nodi proprietas (exempli gratia, numerus). Clavis necessaria est ut elementum ligni invenire possis cui haec clavis correspondet. Exemplum arboris binariae inquisitionis:

Lignum binarium vel quomodo parare arborem quaesiti binarii

Visum lignum

Dum progredimur, nonnulla codicis fragmenta (fortasse incompleta) praebebo ut intelligentiam tuam corrigant. Codex plenus erit in fine articuli.

Lignum nodis constat. Nodi compages;

public class Node<T> {
    private T data;
    private int key;
    private Node<T> leftChild;
    private Node<T> rightChild;

    public Node(T data, int key) {
        this.data = data;
        this.key = key;
    }
    public Node<T> getLeftChild() {
        return leftChild;
    }

    public Node<T> getRightChild() {
        return rightChild;
    }
//...ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΡƒΠ·Π»Π°
}

Uterque nodi duos filios habet (fate enim fieri potest ut filii sinistri et/vel dextrae infantes nullum valorem contineant). Probabiliter intellexistis numerum notitiarum in hoc casu esse notas in nodo conditas esse; clavis β€” nodi clavis.

Nodum digesti sumus, nunc de arboribus instantibus quaestionibus loquimur. Postmodum verbo "arboris" conceptum ligni binarii quaesiti designabo. Structura ligni binarii;

public class BinaryTree<T> {
     private Node<T> root;

    //ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ Π΄Π΅Ρ€Π΅Π²Π°
}

Tantum radicem arboris ut genus agri egent, quia ab radice, utendo getLeftChild() et modos get, ad quamlibet nodi in arbore licebit pervenire.

Algorithms in arbore

Поиск

Dicamus te arborem constructam habere. Quomodo elementum clavem invenire? Opus gradatim ex radice de arbore moveri et valorem clavis cum nodo proximae clavibus compara: si clavis minor est quam clavis nodi proximi, tum ad sinistram nodi prolem, si est. major, dextrorsum, si claves sunt aequales, nodi desideratus invenitur! Relevant codicem:

public Node<T> find(int key) {
    Node<T> current = root;
    while (current.getKey() != key) {
        if (key < current.getKey())
            current = current.getLeftChild();
        else
            current = current.getRightChild();
        if (current == null)
            return null;
    }
    return current;
}

Si vena nulla fit, quaesitio ad finem arboris (in gradu rationis, in loco non existente in arbore es - ortus folii).

Consideremus efficaciam investigationis algorithmus in arbore librata (arbor in qua nodi plus minus aequaliter distribuuntur). Tunc efficientiae inquisitionis erit O(log(n)), et logarithmus est basis 2. Vide: si elementa n sunt in arbore librata, hoc significat quod log(n) erit ad bases 2 gradus. Arbor. Et quaerens in uno gradu cycli descendis uno gradu.

inserere

Si essentiam inquisitionis comprehendis, tunc insertionem intelligendi difficile tibi non erit. Vos iustus postulo ut descendat ad folium arboris (secundum regulas descensus in inquisitione descriptos) et fiet eius descendens - laeva sive dextera secundum clavem. Exsecutio:

   public void insert(T insertData, int key) {
        Node<T> current = root;
        Node<T> parent;
        Node<T> newNode = new Node<>(insertData, key);
        if (root == null)
            root = newNode;
        else {
            while (true) {
                parent = current;
                if (key < current.getKey()) {
                    current = current.getLeftChild();
                    if (current == null) {
                         parent.setLeftChild(newNode);
                         return;
                    }
                }
                else {
                    current = current.getRightChild();
                    if (current == null) {
                        parent.setRightChild(newNode);
                        return;
                    }
                }
            }
        }
    }

In hoc casu, praeter nodi hodiernae, informationem de parente nodi hodiernae condere necesse est. Cum vena nulla aequalis fit, parens variabilis schedam quae nobis necessaria est continebit.
Insertionis efficientia eadem plane erit ac inquisitionis - O (log(n)).

removal

Remotio est operatio difficillima quae in ligno confici debet. Perspicuum est primum elementum quod deleturi sumus invenire debebimus. Sed quid tum? Si tantum referat ad nullum, amittemus informationes de subtilitate cuius radix hic nodi est. Arbor remotionis methodi in tres casus dividuntur.

Casus primus. Nodus deletus liberos non habet

Si nodi deletae liberos non habent, id significat quod folium est. Unde simpliciter potes collocare agros sinistrae fili vel dexterae parentis ad nullum.

Secundus casus. Nodus delendus habet unum puerum

Hoc etiam non admodum perplexum est. Redeamus ad exemplum nostrum. Dicamus nos elementum clavis delere necesse est 14. Esto consentiens, cum id sit ius nodi cum clavibus 10 descendens, deinde quaelibet posteris (in hoc casu dextra) clavem maiorem quam 10, sic habebis. facile potest eam ex arbore secare et parentem ad prolem nodi deletam directe coniungere, i.e. nodi connectere cum clavis 10 ad nodi 13. Similis res esset si nodi deleretur, qui est filius sinistrae parentis sui. Te ipsum cogita - an accurata analogia.

Tertius casus. A nodi duos filios habet

Difficillima causa. Inspiciamus novum exemplum.

Lignum binarium vel quomodo parare arborem quaesiti binarii

Quaere successorem

Dicamus nos nodi clavi delere 25. Quis in eius loco ponere debeamus? Unus e suis asseclis (nepotes vel posteritas) fiet successor(ille, qui remoto nodo succedet).

Quomodo intellegendum est, quis successor factus sit? Intuitive, hic est nodi in arbore cuius clavis est maxima proxima a nodo deleta. Algorithmus talis est. Ad dextram eius descende (semper ad dextram, quia iam dictum est successorem clavem maiorem esse quam clavem nodi deletam), et deinde per catenam posteris sinistri huius dexterae propaginis. . In exemplo, ad nodi cum clavibus iremus 35, et tunc descendamus ad folium per catenam filii sui sinistri β€” in hoc casu, haec catena sola nodi consistit in clavibus 30. Proprie nos querimus. nam nodi minimi in nodis statuto majores quam nos nodi quaerimus.

Lignum binarium vel quomodo parare arborem quaesiti binarii

Successor inquisitionis modum code:

    public Node<T> getSuccessor(Node<T> deleteNode) {
        Node<T> parentSuccessor = deleteNode;//Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ ΠΏΡ€Π΅Π΅ΠΌΠ½ΠΈΠΊΠ°
        Node<T> successor = deleteNode;//ΠΏΡ€Π΅Π΅ΠΌΠ½ΠΈΠΊ
        Node<T> current = successor.getRightChild();//просто "ΠΏΡ€ΠΎΠ±Π΅Π³Π°ΡŽΡ‰ΠΈΠΉ" ΡƒΠ·Π΅Π»
        while (current != null) {
            parentSuccessor = successor;
            successor = current;
            current = current.getLeftChild();
        }
        //Π½Π° Π²Ρ‹Ρ…ΠΎΠ΄Π΅ ΠΈΠ· Ρ†ΠΈΠΊΠ»Π° ΠΈΠΌΠ΅Π΅ΠΌ ΠΏΡ€Π΅Π΅ΠΌΠ½ΠΈΠΊΠ° ΠΈ родитСля ΠΏΡ€Π΅Π΅ΠΌΠ½ΠΈΠΊΠ°
        if (successor != deleteNode.getRightChild()) {//Ссли ΠΏΡ€Π΅Π΅ΠΌΠ½ΠΈΠΊ Π½Π΅ совпадаСт с ΠΏΡ€Π°Π²Ρ‹ΠΌ ΠΏΠΎΡ‚ΠΎΠΌΠΊΠΎΠΌ удаляСмого ΡƒΠ·Π»Π°
            parentSuccessor.setLeftChild(successor.getRightChild());//Ρ‚ΠΎ Π΅Π³ΠΎ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ Π·Π°Π±ΠΈΡ€Π°Π΅Ρ‚ сСбС ΠΏΠΎΡ‚ΠΎΠΌΠΊΠ° ΠΏΡ€Π΅Π΅ΠΌΠ½ΠΈΠΊΠ°, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΠΏΠΎΡ‚Π΅Ρ€ΡΡ‚ΡŒ Π΅Π³ΠΎ
            successor.setRightChild(deleteNode.getRightChild());//связываСм ΠΏΡ€Π΅Π΅ΠΌΠ½ΠΈΠΊΠ° с ΠΏΡ€Π°Π²Ρ‹ΠΌ ΠΏΠΎΡ‚ΠΎΠΌΠΊΠΎΠΌ удаляСмого ΡƒΠ·Π»Π°
        }
        return successor;
    }

Plena code ad modum delete:

public boolean delete(int deleteKey) {
        Node<T> current = root;
        Node<T> parent = current;
        boolean isLeftChild = false;//Π’ зависимости ΠΎΡ‚ Ρ‚ΠΎΠ³ΠΎ, являСтся Π»ΠΈ  удаляСмый ΡƒΠ·Π΅Π» Π»Π΅Π²Ρ‹ΠΌ ΠΈΠ»ΠΈ ΠΏΡ€Π°Π²Ρ‹ΠΌ ΠΏΠΎΡ‚ΠΎΠΌΠΊΠΎΠΌ своСго родитСля, булСвская пСрСмСнная isLeftChild Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ true ΠΈΠ»ΠΈ false соотвСтствСнно.
        while (current.getKey() != deleteKey) {
            parent = current;
            if (deleteKey < current.getKey()) {
                current = current.getLeftChild();
                isLeftChild = true;
            } else {
                isLeftChild = false;
                current = current.getRightChild();
            }
            if (current == null)
                return false;
        }

        if (current.getLeftChild() == null && current.getRightChild() == null) {//ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ случай
            if (current == root)
                current = null;
            else if (isLeftChild)
                parent.setLeftChild(null);
            else
                parent.setRightChild(null);
        }
        else if (current.getRightChild() == null) {//Π²Ρ‚ΠΎΡ€ΠΎΠΉ случай
            if (current == root)
                root = current.getLeftChild();
            else if (isLeftChild)
                parent.setLeftChild(current.getLeftChild());
            else
                current.setRightChild(current.getLeftChild());
        } else if (current.getLeftChild() == null) {
            if (current == root)
                root = current.getRightChild();
            else if (isLeftChild)
                parent.setLeftChild(current.getRightChild());
            else
                parent.setRightChild(current.getRightChild());
        } 
        else {//Ρ‚Ρ€Π΅Ρ‚ΠΈΠΉ случай
            Node<T> successor = getSuccessor(current);
            if (current == root)
                root = successor;
            else if (isLeftChild)
                parent.setLeftChild(successor);
            else
                parent.setRightChild(successor);
        }
        return true;
    }

Complexitas ad O(log(n)) approximari potest.

Inveniens maximum / minimum in arbore

Patet quomodo invenire valorem minimum in arbore - sequentiter moveri debes per catenam elementorum sinistrae dextrae arboris, respective; cum ad schedam perveneris, elementum minimum/maximum erit.

    public Node<T> getMinimum(Node<T> startPoint) {
        Node<T> current = startPoint;
        Node<T> parent = current;
        while (current != null) {
            parent = current;
            current = current.getLeftChild();
        }
        return parent;
    }

    public Node<T> getMaximum(Node<T> startPoint) {
        Node<T> current = startPoint;
        Node<T> parent = current;
        while (current != null) {
            parent = current;
            current = current.getRightChild();
        }
        return parent;
    }

Complexionis - O (log(n))

Symmetrica bypass

Traversal invisit unumquemque nodi arboris ut cum eo aliquid agat.

Symmetria recursiva algorithmus traversalis:

  1. Facere actionem sinistro infante
  2. Facere actionem tecum
  3. Facere actionem pueri ius

Code:

    public void inOrder(Node<T> current) {
        if (current != null) {
            inOrder(current.getLeftChild());
            System.out.println(current.getData() + " ");//Π—Π΄Π΅ΡΡŒ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ всС, Ρ‡Ρ‚ΠΎ ΡƒΠ³ΠΎΠ΄Π½ΠΎ
            inOrder(current.getRightChild());
        }
    }

conclusio,

Denique! Si nihil explicavi aut commentarios habes, eas in commentarios derelinquas. Ut promissum est, codicem integrum praebeo.

Node.java:

public class Node<T> {
    private T data;
    private int key;
    private Node<T> leftChild;
    private Node<T> rightChild;

    public Node(T data, int key) {
        this.data = data;
        this.key = key;
    }

    public void setLeftChild(Node<T> newNode) {
        leftChild = newNode;
    }

    public void setRightChild(Node<T> newNode) {
        rightChild = newNode;
    }

    public Node<T> getLeftChild() {
        return leftChild;
    }

    public Node<T> getRightChild() {
        return rightChild;
    }

    public T getData() {
        return data;
    }

    public int getKey() {
        return key;
    }
}

BinaryTree.java:

public class BinaryTree<T> {
    private Node<T> root;

    public Node<T> find(int key) {
        Node<T> current = root;
        while (current.getKey() != key) {
            if (key < current.getKey())
                current = current.getLeftChild();
            else
                current = current.getRightChild();
            if (current == null)
                return null;
        }
        return current;
    }

    public void insert(T insertData, int key) {
        Node<T> current = root;
        Node<T> parent;
        Node<T> newNode = new Node<>(insertData, key);
        if (root == null)
            root = newNode;
        else {
            while (true) {
                parent = current;
                if (key < current.getKey()) {
                    current = current.getLeftChild();
                    if (current == null) {
                         parent.setLeftChild(newNode);
                         return;
                    }
                }
                else {
                    current = current.getRightChild();
                    if (current == null) {
                        parent.setRightChild(newNode);
                        return;
                    }
                }
            }
        }
    }

    public Node<T> getMinimum(Node<T> startPoint) {
        Node<T> current = startPoint;
        Node<T> parent = current;
        while (current != null) {
            parent = current;
            current = current.getLeftChild();
        }
        return parent;
    }

    public Node<T> getMaximum(Node<T> startPoint) {
        Node<T> current = startPoint;
        Node<T> parent = current;
        while (current != null) {
            parent = current;
            current = current.getRightChild();
        }
        return parent;
    }

    public Node<T> getSuccessor(Node<T> deleteNode) {
        Node<T> parentSuccessor = deleteNode;
        Node<T> successor = deleteNode;
        Node<T> current = successor.getRightChild();
        while (current != null) {
            parentSuccessor = successor;
            successor = current;
            current = current.getLeftChild();
        }

        if (successor != deleteNode.getRightChild()) {
            parentSuccessor.setLeftChild(successor.getRightChild());
            successor.setRightChild(deleteNode.getRightChild());
        }
        return successor;
    }

    public boolean delete(int deleteKey) {
        Node<T> current = root;
        Node<T> parent = current;
        boolean isLeftChild = false;
        while (current.getKey() != deleteKey) {
            parent = current;
            if (deleteKey < current.getKey()) {
                current = current.getLeftChild();
                isLeftChild = true;
            } else {
                isLeftChild = false;
                current = current.getRightChild();
            }
            if (current == null)
                return false;
        }

        if (current.getLeftChild() == null && current.getRightChild() == null) {
            if (current == root)
                current = null;
            else if (isLeftChild)
                parent.setLeftChild(null);
            else
                parent.setRightChild(null);
        }
        else if (current.getRightChild() == null) {
            if (current == root)
                root = current.getLeftChild();
            else if (isLeftChild)
                parent.setLeftChild(current.getLeftChild());
            else
                current.setRightChild(current.getLeftChild());
        } else if (current.getLeftChild() == null) {
            if (current == root)
                root = current.getRightChild();
            else if (isLeftChild)
                parent.setLeftChild(current.getRightChild());
            else
                parent.setRightChild(current.getRightChild());
        } 
        else {
            Node<T> successor = getSuccessor(current);
            if (current == root)
                root = successor;
            else if (isLeftChild)
                parent.setLeftChild(successor);
            else
                parent.setRightChild(successor);
        }
        return true;
    }

    public void inOrder(Node<T> current) {
        if (current != null) {
            inOrder(current.getLeftChild());
            System.out.println(current.getData() + " ");
            inOrder(current.getRightChild());
        }
    }
}

PS

O ad degeneratum (n)

Multi vestrum notasse: quid, si non libratam arborem? Exempli gratia: nodos pone cum claves in arbore crescentes: 1,2,3,4,5,6. Et sic, arbor structuram arboris amittet, et ideo accessus notitiae efficacia. Incomplexitas operationum inquisitionis, insertionis et deletionis eadem fiet ac cum indice coniuncto: O (n). Haec est praecipua, opinor, arborum binarum incommoda.

Tantum usores descripserunt in aliquet participare possunt. InscribeTe gratissimum esse.

Diutissime in centrum non fui, et scire velim quos articulos de quibus locis plura videre velis?

  • Data structurae

  • Algorithmus (DP, recursio, data compressio, etc.)

  • Applicatio notitiarum structurarum et algorithmorum in vita reali

  • Programming Android Applications in Java

  • Applicationes programmandi interreti Java

2 utentes censuerunt. 1 Insere abstinuisse.

Source: www.habr.com