Page 1 of 1

Περιστροφές δένδρων BST (Δομές Δεδομένων)

Posted: Wed Jan 24, 2007 3:02 am
by Zifnab
Παιδιά έχω ένα πρόβλημα! Στις σημειώσεις για τις Δομές δεδομένων(βασισμένες στου Princeton) περιγράφονται οι συναρτήσεις για περιστροφή Binary-Search-Trees... Όμως απ'ότι φαίνεται αυτές οι δύο μέθοδοι ούτε καν περιστρέφουν το δέντρο με το γνωστό αλγόριθμο. Συγκεκριμένα όταν γίνεται π.χ RotR για κάποια ρίζα υπόδενδρου μπλέκει και τον πατέρα του και τον παππού του, κάτι που αυτές οι μέθοδοι δεν κάνουν... Απ' ότι κατάλαβα οι μέθοδοι χρησιμοποιούνται από τον Sedgewick αναδρομικά για να κάνουμε εισαγωγή στοιχείου στη ρίζα και ΜΟΝΟ....

Code: Select all

class bst<Item extends Comparable> {
	private class Node{
		Node left;
		Node right;
		Item item;
		private Node(Item item) {
			this.item=item;
		}
	}
	Node root;
	public void insert(Item item) {
		root=insert(root,item);
	}
	public void insert(Item[] items) {
		for (int i=0; i<items.length; i++) 
			insert(items[i]);
		
	}
	private Node insert(Node x,Item item) {
		if (x==null)
			return new Node(item);
		else if(item.compareTo(x.item)<0) 
			x.left = insert(x.left,item);
		else
			x.right = insert(x.right,item);
		return x;
	}
	public Node protL(Node h) { //aristeri peristrofi
		Node x=h.right;
		h.right=x.left;
		x.left=h;
		return x;
	}
	public Node protR(Node h) { //dexia peristrofi
		Node x=h.left;
		h.left=x.right;
		x.right=h;
		return x;
	}
	public static void main(String args[]) {
		bst<Character> searchtree=new bst<Character>(); 
		Character[] chars={'A','S','E','R','C','H','I','N','G','X','M','P','L'};
		searchtree.insert(chars);
		//dokimes
		System.out.println(searchtree.root.item);
		System.out.println(searchtree.root.right.item);
		System.out.println(searchtree.root.right.left.item);
		System.out.println(searchtree.root.right.left.right.item);
		searchtree.rotR(searchtree.root.right);
		System.out.println("After Right Rotation");
		System.out.println(searchtree.root.item);
		System.out.println(searchtree.root.right.item);
		System.out.println(searchtree.root.right.left.item);
		System.out.println(searchtree.root.right.left.left.item);	
	}			
}


Ο σωστός κώδικας που βρήκα είναι κάτι σαν αυτό:

Code: Select all

void rotate( node c ) {

    node p = c.parent;		// parent of c
    node gp = p.parent;		// grandparent of c (might be null)

    // Update the lower edge which switches sides

    if (c == p.left) {
      p.left = c.right;
      if (p.left != null)
	p.left.parent = p;
      c.right = p;
      p.parent = c;
    } else {
      p.right = c.left;
      if (p.right != null)
	p.right.parent = p;
      c.left = p;
      p.parent = c;
    }

    // Update the upper edge which switches sides

    if (gp == null)
      root = c;
    else if (p == gp.left)
      gp.left = c;
    else
      gp.right = c;
    
    c.parent = gp;
  }
}

Επίσης ο τελευταίος κώδικας μας προστατεύει να μην περιστρέψουμε κάποιο κόμβο δένδρου που δεν επιτρέπεται....

Να και ένα ωραίο link που βρίκα για τις περιστροφές με applet
http://www.cs.queensu.ca/~jstewart/appl ... ation.html

Εσείς τι γνώμη έχετε ? thx ;)

Posted: Wed Jan 24, 2007 5:12 pm
by cactus
Δεν καταλαβαίνω πιο είναι το πρόβλημα...
"Έτρεξα"(=με το χέρι) τις protL(Node), protR(Node) και δεν βρήκα πρόβλημα.
Μήπως επειδή η 1η υλοποίηση δεν χρησιμοποιεί σε κάθε κόμβο πεδίο που να αναφέρεται στον κόμβο-πατέρα του κόμβου όπως κάνει η 2η;

Α,ακόμα μία διαφορά είναι:

--στις protL(Node) & protR(Node) περιστρέφεις το όρισμα και το παιδί του.
--στη rotare(node) περιστρέφεις το όρισμα κια τον πατέρα του.

Αν δες σε κάλυψα πες μου...ίσως να μην κατάλαβα το πρόβλημα.
Ζifnab wrote:Επίσης ο τελευταίος κώδικας μας προστατεύει να μην περιστρέψουμε κάποιο κόμβο δένδρου που δεν επιτρέπεται....
Μπορείς να μου το εξηγήσεις λίγο;; δηλ ένα παράδειγμα ενός κόμβου που δεν μπορούμε να περιστρέψουμε, ή κάτι άλλο, δεν το κατάλαβα

Posted: Wed Jan 24, 2007 5:23 pm
by Zifnab
Απλά είπα πως οι δύο μέθοδοι επάνω δεν μπορούν να χρησιμοποιηθούν έτσι χύμα για ένα δένδρο...παρά μόνο αναδρομικά όταν κάνουμε εισαγωγή στη ρίζα...Γενικά δεν δουλεύουν μόνες τους,αφού δεν αλλάζουν την σύνδεση της νέας υπορίζας με τον πατέρα και τον παππού...τέλος πάντων.

Αυτές οι δύο μέθοδοι έχουν και το άλλο πρόβλημα:
Αν έχω το δένδρο

Code: Select all

    B
  /   \
 A     C
δεν μπορώ να κάνω περιστροφή ως προς το A ή το C, γιατί αυτά δεν έχουν παιδιά. Σύμφωνα με το βιβλίο του Sedgewick π.χ για την δεξιά περιστροφή ο κόμβος που περιστρέφεται γίνεται δεξιό παιδί του αριστερού του παιδιού...

Posted: Wed Jan 24, 2007 5:30 pm
by cactus
Σωστός σε όλα!

Posted: Wed Jan 24, 2007 5:54 pm
by Zifnab
cactus έχει νόημα να περιστρέφουμε κόμβο που είναι ήδη στην κεντρική ρίζα (επίπεδο 1)?
Δες λίγο το link επάνω - και παίξε με τα applets...Παρατήρησε ότι η rotate που παραθέτω στο δεύτερο κομμάτι κώδικα (προέρχεται από το applet) δεν έχει left και right... Δηλαδή ένας κόμβος είτε θα μπορεί να περιστραφεί αριστερά είτε δεξιά (ποτέ και τα δύο μαζί), είτε καθόλου?

Posted: Wed Jan 24, 2007 6:38 pm
by cactus
EDIT: Zifnab, δεν είδα το τελευταίο post σου όταν postaρα το παρακάτω...το κοιτάζω τώρα αυτό που λές...

Επαναποστάρω...(μ'αρέσουν οι δομές :) )

Λοιπόν το λάθος που επισήμανες,σωστός μεν αλλά μου φένεται πολύ χοντρό για να του ξέφυγε...

Παρατήρησα από τα σχόλια στη main ότι εσύ τα έγραψες σωστά;; Επίσης παρατήρησα ότι η κάθε αντικέιμενο τις τάξης είναι ένα BST. Οι κόμβοι είναι αντικέιμενα εσωτερικής τάξης private, άρα μία τάξη πελάτης δεν έχει πρόσβαση σε αυτά. Οι public μέθοδοι έχουν ορίσματα Nodes που δεν έχουμε πρόσβαση αρα ο κώδικας είχε μια getRoot() ή κάτι τέτοιο, σωστα;
(αν αυτες οι υποθέσεις ήταν σωστές, τότε αυτό που ακολουθεί έχει νόημα, αλλιώς δεν νομιζω να αξίζει τον κόπο...)

Οπότε κάνω μια υπόθεση ότι ίσως δεν είναι σκοπός της τάξης να κάνεις ποτέ rotare ένα κόμβο τυχαία, παρα μόνο τη ρίζα, απλά και μόνο για να ισορροπείς το δέντρο...(Μήπως η rotare δεν ήταν καν public αλλά μια άλλη τη χρησιμοπιούσε, (άλλη μία παρακινδυνεμένη υπόθεση))

Έψαξα στα .pdf στο eclass αλλα δεν την πλήρη βρήκα την υλοποίηση, φαντάστηκα ότι είναι από το βιβλίο και ότι δεν τη μετέφερες όλη για ευνόητους λόγους.

Γενικά, πιστεύω καλύτερα είναι ν αδοκιμ'αζεις μια τάξη-βιβλιοθήκη με μία τάξη πελάτη σε άλλο πακέτο ώστε να βλέπεις και το λόγω επιλογής της συγγεκριμένης υλοποίησης.

no offence taken, just shooting ideas

Posted: Wed Jan 24, 2007 7:20 pm
by cactus
Ζifnab wrote:cactus έχει νόημα να περιστρέφουμε κόμβο που είναι ήδη στην κεντρική ρίζα (επίπεδο 1)?
Δες λίγο το link επάνω - και παίξε με τα applets...Παρατήρησε ότι η rotate που παραθέτω στο δεύτερο κομμάτι κώδικα (προέρχεται από το applet) δεν έχει left και right... Δηλαδή ένας κόμβος είτε θα μπορεί να περιστραφεί αριστερά είτε δεξιά (ποτέ και τα δύο μαζί), είτε καθόλου?
Στο βιβλίο του Συντιχάκη βρήκα το εξης:
Η αριστερή περιστροφή ενός κόμβου p εμπλέκει τον ίδιο κια το δεξί του παιδί, έστω r. To αριστερό υπόδεντρο του κόμβου r γίνεται δεξί παιδί του κόμβου p και ο p γίνεται αριστερό παιδί του κόμβου r.
Η δεξιά περιστροφή ενός κόμβου p εμπλέκει τον p και το αριστερό του παιδί έστω l. Το δεξί υπόδεντρο του l γίνεται αριστερού παιδί του p και ο p γίνεται δεξί παιδί του l.
Πρόσεξε ότι οι protL(Node) και protR(Node) περιστρέφουν το δεξί παιδί του ορίσματος, κια το αριστερό αντίστοιχα, ενώ ο η rotare(node) περιστρέφει το όρισμα ανάλογα με το αν είναι δεξί ή αριστερό πιαδί του πατέρα του.

Δηλ όλες περιστρέφουν το παιδί ανάλογα με τη θέση του ως προς τον πατέρα.

Αυτά ως ενδείξεις...επανέρχομαι σύντομα...

Στο χω ξαναπεί, μου αρέσουν οι ιδέες σου. (ποτέ δεν το χα σκεφτει αυτό...ωραίος!!!)

Posted: Wed Jan 24, 2007 7:34 pm
by cactus
Όντως έχεις δίκιο. Έστω το δέντρο:

Code: Select all

                     20   
                  /       \
               15          26
              /   \       /    \
            4      17    23     30
Oι τιμές είναι τα πεδία των κόμβων που τους καθιστούν διαταξιμους.
Προφανώς είναι BST.
Μπορέις να περιστρέψεις αριστερά τον 20 ως προς τον 26, αλλά έστω πως θες να περιστρέψεις τον 20 δεξιά ώς προς τον 26.
Οκ, μπορέι να γίνει, αλλά δεν βλέπω κανονικότητα ούτε ως προς τις κινήσεις που θα κάνεις ούτε ως προς το αποτέλεσμα που θα έχεις στο δέντρο. Δηλ αν και εφικτό δεν βλέπω κέρδος... εσύ τι λές;;;

Posted: Wed Jan 24, 2007 7:35 pm
by The Punisher
κοινώς o Node στις protL και protR είναι ο πατέρας, ενώ στη rotate το παιδί ... νομίζω

Posted: Wed Jan 24, 2007 7:49 pm
by Zifnab
Ευχαριστώ cactus και Punisher που ασχολείστε... ;)
Βασικά και ο Συντιχάκης λέει τα ίδια με τον Sedgewick....Αυτά όμως ισχύουν για την αναδρομική περιστροφή και όχι για μια τυχαία περιστροφή κάποιου κόμβου που οπωσδήποτε μπλέκουν τουλάχιστον τον πατέρα...Θα το ψάξω και εγώ και θα γράψω στα συμπεράσματα στα οποία κατέληξα...