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 извършва inorder обход
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.