Sobes.tech
Middle

Πώς λειτουργεί η αναζήτηση στο δέντρο;

sobes.tech AI

Απάντηση από AI

Η αναζήτηση σε ένα δέντρο εξαρτάται από τη δομή του και τον σκοπό της αναζήτησης.

Βασικοί τρόποι αναζήτησης:

  1. Αναζήτηση βάθους (DFS - Depth-First Search): Πηγαίνει όσο το δυνατόν πιο βαθιά σε ένα κλάδο προτού μεταβεί σε γειτονικό. Υλοποιείται με χρήση στοίβας (ρητά ή μέσω αναδρομής).

    • Προκαταρκτική επίσκεψη (Pre-order): Επισκέπτεται τη ρίζα, μετά το αριστερό υποδέντρο, μετά το δεξί υποδέντρο.
    • Ενδιάμεση επίσκεψη (In-order): Επισκέπτεται το αριστερό υποδέντρο, μετά τη ρίζα, μετά το δεξί υποδέντρο. Χρησιμοποιείται σε δυαδικά δέντρα αναζήτησης για την απόκτηση ταξινομημένης λίστας στοιχείων.
    • Μετα-διάσχιση (Post-order): Επισκέπτεται το αριστερό υποδέντρο, μετά το δεξί υποδέντρο, μετά τη ρίζα.
  2. Αναζήτηση πλάτους (BFS - Breadth-First Search): Εξετάζει όλους τους γείτονες σε ένα επίπεδο προτού προχωρήσει στο επόμενο επίπεδο. Υλοποιείται με χρήση ουράς.

Παράδειγμα DFS (In-order) για δυαδικό δέντρο:

// TreeNode αντιπροσωπεύει τον κόμβο ενός δυαδικού δέντρου
type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

// InOrderTraversal εκτελεί διάσχιση σε in-order
func InOrderTraversal(root *TreeNode) []int {
	var result []int
	if root == nil {
		return result
	}

	// Αναδρομική κλήση για το αριστερό υποδέντρο
	result = append(result, InOrderTraversal(root.Left)...)
	// Επίσκεψη τρέχοντος κόμβου
	result = append(result, root.Val)
	// Αναδρομική κλήση για το δεξί υποδέντρο
	result = append(result, InOrderTraversal(root.Right)...)

	return result
}

Παράδειγμα BFS:

// TreeNode αντιπροσωπεύει τον κόμβο ενός δυαδικού δέντρου
type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

// BFSTraversal εκτελεί διάσχιση BFS
func BFSTraversal(root *TreeNode) []int {
	var result []int
	if root == nil {
		return result
	}

	// Ουρά για αποθήκευση κόμβων σε τρέχον επίπεδο
	queue := []*TreeNode{root}

	for len(queue) > 0 {
		// Αφαιρούμε το πρώτο στοιχείο
		node := queue[0]
		queue = queue[1:]

		// Προσθέτουμε την τιμή του κόμβου στο αποτέλεσμα
		result = append(result, node.Val)

		// Προσθέτουμε τον αριστερό παιδί στην ουρά, αν υπάρχει
		if node.Left != nil {
			queue = append(queue, node.Left)
		}
		// Προσθέτουμε τον δεξιό παιδί στην ουρά, αν υπάρχει
		if node.Right != nil {
			queue = append(queue, node.Right)
		}
	}
	return result
}

Για δυαδικά δέντρα αναζήτησης (BST), όπου το αριστερό υποδέντρο είναι μικρότερο από τη ρίζα και το δεξί μεγαλύτερο:

  1. Δυαδική αναζήτηση: Κατά την αναζήτηση μιας συγκεκριμένης τιμής, συγκρίνουμε με τη ρίζα. Αν η τιμή είναι μικρότερη, αναζητούμε στο αριστερό υποδέντρο· αν μεγαλύτερη, στο δεξί. Αυτή είναι η πιο αποτελεσματική στρατηγική αναζήτησης σε BST.
// TreeNode αντιπροσωπεύει τον κόμβο ενός δυαδικού δέντρου αναζήτησης
type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

// SearchBST εκτελεί δυαδική αναζήτηση σε BST
func SearchBST(root *TreeNode, target int) *TreeNode {
	if root == nil || root.Val == target {
		return root // Βρέθηκε ο κόμβος ή το δέντρο είναι κενό
	}

	if target < root.Val {
		// Αναζητούμε στο αριστερό υποδέντρο
		return SearchBST(root.Left, target)
	}
	// Αναζητούμε στο δεξί υποδέντρο
	return SearchBST(root.Right, target)
}

Η επιλογή του αλγορίθμου αναζήτησης εξαρτάται από το πρόβλημα και τα χαρακτηριστικά του δέντρου. Το DFS είναι κατάλληλο για περιπτώσεις όπου πρέπει να προχωρήσετε βαθιά σε ένα κλάδο ή να βρείτε διαδρομή προς έναν στόχο. Το BFS είναι κατάλληλο για εύρεση της συντομότερης διαδρομής ή διάσχιση κατά επίπεδα. Η δυαδική αναζήτηση είναι αποτελεσματική για την εύρεση συγκεκριμένης τιμής σε ταξινομημένες δομές, όπως το BST.