BST implementering, huvudstruktur BST-implementering public class BinarySearchTree<E extends Comparable<? super E>> extends AbstractCollection<E> { protected Entry root; protected int size; protected class Entry {... // Metoder som skrivs över, samt hjälpmetoder protected class BST_Iterator implements Iterator<E> {... // class BinarySearchTree Datastrukturer, implementering träd 1
Metoder som skrivs över BST-implementering // Abstrakta, dvs nödvändiga public int size() { public Iterator<E> iterator() { // för modifiering public boolean add( E elem ) { public boolean remove( E elem ) { // av effektivitetsskäl public boolean contains( E elem ) { public void clear() { Datastrukturer, implementering träd 2
Nod-klassen BST-implementering protected class Entry { public E element; public Entry left, right, parent; public Entry( E element, Entry left, Entry right, Entry parent){ this.element = element; this.left = left; this.right = right; this.parent = parent; // constructor Entry public Entry( E element, Entry parent) { this( element, null, null, parent ); // constructor Entry // class Entry Datastrukturer, implementering träd 3
De abstrakta metoderna BST-implementering public int size() { return size; // size public Iterator<E> iterator() { return new BST_Iterator(); // iterator Datastrukturer, implementering träd 4
Lägga till ett element BST-implementering public boolean add( E elem ) { if ( root == null ) root = new Entry( elem, null ); else addin( elem, root ); size++; return true; // add protected void addin(e newelem, Entry t) { if ( newelem.compareto( t.element ) < 0 ) if ( t.left == null ) t.left = new Entry( newelem, t); else addin( newelem, t.left ); else if ( t.right == null ) t.right = new Entry( newelem, t); else addin( newelem, t.right ); // addin Datastrukturer, implementering träd 5
BST-implementering Hitta ett lika stort element public boolean contains( E elem ) { return find( elem, root )!= null; // contains protected Entry find( E elem, Entry t ) { if ( t == null ) return null; else { int jfr = elem.compareto( t.element ); if ( jfr < 0 ) return find( elem, t.left ); else if ( jfr > 0 ) return find( elem, t.right ); else return t; // find Datastrukturer, implementering träd 6
BST-implementering Ta bort ett givet element protected void removethis( Entry t ) { if ( t.left == null ) liftrightsubtree(t); else swapwithrightmostinlefttree(t); size--; // removethis Datastrukturer, implementering träd 7
Ta bort ett givet element hjälpmetoder BST-implementering protected void liftrightsubtree( Entry t ) { // Note that l.left is null if ( t.right!= null ) t.right.parent = t.parent; if ( t.parent == null ) root = t.right; else if ( t.parent.left == t ) t.parent.left = t.right; else t.parent.right = t.right; // liftrightsubtree Datastrukturer, implementering träd 8
Ta bort, hjälpmetoder BST-implementering protected void swapwithrightmostinlefttree( Entry t ) { if ( t.left.right == null ) { t.element = t.left.element; t.left = t.left.left; if ( t.left!= null ) t.left.parent = t; else { Entry p = t.left; while ( p.right.right!= null ) p = p.right; t.element = p.right.element; p.right = p.right.left; if ( p.right!= null ) p.right.parent = p; // swapwithrightmostinlefttree Datastrukturer, implementering träd 9
Ta bort ett lika stort element BST-implementering public boolean remove( E elem ) { Entry remelem = find( elem, root ); if ( remelem == null ) return false; else { removethis( remelem ); return true; // remove public void clear() { root = null; size = 0; Datastrukturer, implementering träd 10
Iteratorn BST-implementering protected class BST_Iterator implements Iterator<E> { private Stacks<Entry> nextontop = new LinkedStack<Entry>(); private Entry lastnext = null; protected BST_Iterator() { for ( Entry p = root; p!= null; p = p.left ) nextontop.push( p ); // constructor BST_Iterator public boolean hasnext() { public E next() { public void remove() { // classbst_iterator Datastrukturer, implementering träd 11
Iteratormetoderna BST-implementering public boolean hasnext() { return! nextontop.isempty(); // hasnext public E next() { lastnext = nextontop.pop(); // throws NoSuchElementException if empty for ( Entry p = lastnext.right; p!= null; p = p.left ) nextontop.push( p ); return lastnext.element; // next public void remove() { if ( lastnext!= null ) { removethis( lastnext ); lastnext = null; else throw new IllegalStateException(); // remove Datastrukturer, implementering träd 12
AVL implementering, huvudstruktur AVL-implementering public class AVL_Tree<E extends Comparable<? super E>> extends BinarySearchTree<E> { private class AVL_Entry extends Entry {... // AVL_Entry // metoder som måste skrivas över public boolean add( E elem) { public boolean remove( E elem ) { protected void removethis( Entry t ) { // samt hjälpmetoder // AVL_Tree Datastrukturer, implementering träd 13
AVL-noder AVL-implementering private class AVL_Entry extends Entry { // The empty tree (i.e. null) is // considered to be of height 0 int height; private AVL_Entry( E element, Entry left, Entry right, Entry parent ) { super( element, left, right, parent ); checkheight(this); // constructor AVL_Entry private AVL_Entry( E element, Entry parent ) { super( element, null, null, parent ); height = 1; // constructor AVL_Entry // class AVL_Entry Datastrukturer, implementering träd 14
Höjd-metoder AVL-implementering private int height( Entry t ) { if ( t == null ) return 0; else return ((AVL_Entry) t).height; // height private void checkheight( Entry t ) { (( AVL_Entry ) t).height = 1 + Math.max( height(t.left ), height(t.right )); // CheckHeight Datastrukturer, implementering träd 15
Lägg till ett element AVL-implementering public boolean add(e elem) { if ( root == null ) root = new AVL_Entry( elem, null ); else addinavl( elem, root ); size++; return true; // add Datastrukturer, implementering träd 16
Lägg till ett element genom rekursiv nedstigning AVL-implementering // returns true if newelem < t.element, false otherwise private boolean addinavl( E newelem, Entry t ) { if ( newelem.compareto( t.element ) < 0 ) { if ( t.left == null ) { t.left = new AVL_Entry( newelem, t ); checkheight(t); else { boolean left = addinavl( newelem, t.left ); if ( height(t.left) - height(t.right) > 1 ) { if ( left ) rotateright( t ); else doublerotateright( t ); else checkheight(t); return true; else { // som ovan, men spegelvänt!! // addinavl Datastrukturer, implementering träd 17
AVL-implementering Rotera 1 steg i högervarv /* Rotera 1 steg i högervarv, dvs x y / \ / \ y C --> A x / \ / \ A B B C */ private void rotateright( Entry x ) { Entry y = x.left; E temp = x.element; x.element = y.element; y.element = temp; x.left = y.left; if ( x.left!= null ) x.left.parent = x; y.left = y.right; y.right = x.right; if ( y.right!= null ) y.right.parent = y; x.right = y; checkheight( y ); checkheight( x ); // rotateright Datastrukturer, implementering träd 18
AVL-implementering Rotera 2 steg i högervarv x z / \ / \ y D --> y x / \ / \ / \ A z A B C D / \ B C private void doublerotateright( Entry x ){ Entry y = x.left, z = x.left.right; E e = x.element; x.element = z.element; z.element = e; y.right = z.left; if ( y.right!= null ) y.right.parent = y; z.left = z.right; z.right = x.right; if ( z.right!= null ) z.right.parent = z; x.right = z; z.parent = x; checkheight( z ); checkheight( y ); checkheight( x ); // doublerotateright Datastrukturer, implementering träd 19
Minimalt AVL-träd Minimalt AVL-träd Skapa ett minimalt AVL-träd av godtycklig höjd. Strategi: låt nodvärdena vara 1..minantal noder räkna ut rotens värde och lägg in det i trädet fortsätt med noderna enligt bredden först. För detta behöver vi en kö för en class IntPair av heltal, som håller reda på vilken höjd som skall byggas och vilka nummer som är upptagna. Kontrollera genom att beräkna höjden i trädet! Datastrukturer, implementering träd 20
Räkna ut antalet noder av godtycklig höjd Minimalt AVL-träd private static int minnodeavl( int height ) { if (height < 3) return height; else return 1 + minnodeavl(height-1) + minnodeavl(height-2); // minnodeavl Datastrukturer, implementering träd 21
Klassen IntPair Minimalt AVL-träd Objekt att stoppas in i kön enligt bredden först. Innehåller information om vilken rotnod som skall skapas. first anger vilka nummer som redan är upptagna. second anger vilken höjd denna rot finns på. class IntPair { int first, second; public IntPair( int first, int second) { this.first = first; this.second = second; // IntPair Datastrukturer, implementering träd 22
Klassen AVL With Depth Minimalt AVL-träd class AVL_With_Depth< E extends Comparable<? super E>> extends AVL_Tree<E> { public int depth() { return depth( root ); private int depth( Entry e ) { if (e == null) return 0; else return 1 + Math.max( depth( e.left ), depth( e.right )); Datastrukturer, implementering träd 23
Minimalt AVL-träd Metoden minavltree( int height ) public static AVL_With_Depth<Integer> minavltree( int height ) { AVL_With_Depth<Integer> tree = new AVL_With_Depth<Integer>(); Queues<IntPair> que = new LinkedQueue<IntPair>(); que.enqueue( new IntPair(height, 0) ); while(! que.isempty() ) { IntPair p = que.dequeue(); if ( p.first == 1 ) tree.add( p.second + 1 ); else if ( p.first > 1 ) { int antleft = minnodeavl( p.first-1 ); int rootvalue = p.second + antleft + 1; tree.add( rootvalue ); que.enqueue( new IntPair( p.first-1, p.second )); que.enqueue( new IntPair( p.first-2, rootvalue)); return tree; // minavltree Datastrukturer, implementering träd 24
Testprogram Minimalt AVL-träd public static void main(string[] args) { for( int i = 3; i < 8; i++ ) { AVL_With_Depth<Integer> t = minavltree( i ); System.out.print( " Min antal noder: " + minnodeavl( i )); System.out.println( " med höjden " + t.depth() + " har trädet för:" ); System.out.println( t ); // main Datastrukturer, implementering träd 25
Testkörning Minimalt AVL-träd sed:bjerner:[~/itds/ovn/program]$ java MinAvlTree Min antal noder: 4 med höjden 3 har trädet för: [1, 2, 3, 4] Min antal noder: 7 med höjden 4 har trädet för: [1, 2, 3, 4, 5, 6, 7] Min antal noder: 12 med höjden 5 har trädet för: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] Min antal noder: 20 med höjden 6 har trädet för: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] Min antal noder: 33 med höjden 7 har trädet för: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33] Datastrukturer, implementering träd 26
Heap allmänt Heap En heap är normalt ett binärt nivåbalanserat träd, konkret implementerat i ett fält. Roten för hela trädet ligger under index 1. Sedan gäller att: Noden under index i har sitt vänstra subträds rot under index 2 i och sitt högra subträds rot under index 2 i + 1 Fadern till en nod under index i fås därför under index i div 2, där div är heltalsdivision. Heap-egenskapen: Roten i varje subträd innhåller det minsta nodvärdet i hela subträdet. Datastrukturer, implementering träd 27
Heap exempel Heap Trädet: Implementeras som: 1 / \ / \ 3 6 / \ / \ 10 5 8 9 / 11-1 3 6 10 5 8 9 11 0 1 2 3 4 5 6 7 8 Datastrukturer, implementering träd 28
Insättning av 2 ger: Heap 1 / \ / \ 2 6 / \ / \ 3 5 8 9 / \ 11 10-1 2 6 3 5 8 9 11 10 0 1 2 3 4 5 6 7 8 9 Datastrukturer, implementering träd 29
Uttag av minsta ger: Heap 2 / \ / \ 3 6 / \ / \ 10 5 8 9 / 11 (1) 2 3 6 10 5 8 9 11 0 1 2 3 4 5 6 7 8 Datastrukturer, implementering träd 30
Metoden add i Java Heap public void add( E elem ) { int hole = ++size; if ( hole == qe.length ) { E [] temp = (E []) new Object[ 3 * qe.length / 2 + 1 ]; System.arraycopy( qe, 0, temp, 0, qe.length ); qe = temp; while ( hole > 1 && elem.compareto( qe[hole >> 1] ) < 0 ) { qe[hole] = qe[hole >> 1]; hole >>= 1; qe[hole] = elem; // add Datastrukturer, implementering träd 31