20 / 69

Decrease Key and Delete Node on Fibonacci Heap

Fibonachchi to'pida kalitni kamaytirish va tugunni o'chirish amallari

Fibonachchi to'pi (Fibonacci Heap) — minimal to'p (min-heap) xossasiga ega bo'lgan daraxtlar to'plamidan iborat daraxtsimon ma'lumotlar tuzilmasidir.

Ushbu darsda biz uning ikkita muhim amalini batafsil ko'rib chiqamiz:

  • Kalitni kamaytirish (Decrease a key) — tanlangan kalit qiymatini undan kichikroq istalgan qiymatga kamaytiradi.
  • Tugunni o'chirish (Delete a node) — berilgan tugunni to'pdan o'chirib tashlaydi.

Kalitni kamaytirish

Kalitni kamaytirish amalida tugunning joriy qiymati kichikroq yangi qiymat bilan almashtiriladi.

Kalitni kamaytirish uchun quyidagi yordamchi funksiyalar qo'llaniladi:

1. Decrease-Key

  • Qiymati kamaytirilishi kerak bo'lgan x tugunini tanlang va uning qiymatini yangi k qiymatiga o'zgartiring.
  • Agar x ning ota tuguni y mavjud bo'lsa va otasining kaliti yangi qiymatdan (k) katta bo'lsa, Cut(x, y) va Cascading-Cut(y) funksiyalarini chaqiring.
  • Agar x ning yangi kaliti min ko'rsatkichidagi kalitdan kichik bo'lsa, x ni yangi min deb belgilang.

2. Cut

  • x tugunini joriy joylashuvidan (otasi y ning bolalar ro'yxatidan) uzing va uni ildizlar ro'yxatiga qo'shing.
  • Agar x belgilangan bo'lsa, uning belgisini bekor qiling (mark = false).

3. Cascading-Cut

  • Agar y ning ota tuguni mavjud bo'lsa, quyidagi shartlarni bajaring:
    • Agar y belgilanmagan bo'lsa, uni belgilang (mark = true).
    • Aks holda, Cut(y, parent of y) va Cascading-Cut(parent of y) ni chaqiring.

Kalitni kamaytirish bo'yicha amaliy misollar

Yuqoridagi amallar qanday ishlashini quyidagi misollarda ko'rib chiqamiz.

1-misol: 46 qiymatini 15 ga kamaytirish

  • 46 qiymatini 15 ga kamaytiramiz:

Decrease 46 to 15

46 ni 15 ga kamaytirish

  • Cut qismi: Otasi 24 ≠ nil va uning qiymati 15 < 24 bo'lganligi sababli (min-heap xossasi buzildi), 15 ni kesib olamiz va ildizlar ro'yxatiga qo'shamiz.
  • Cascading-Cut qismi: 24 tuguni belgilanmagan bo'lgani uchun uni belgilaymiz (mark 24):

Cut and Cascading part

15 ni ildizlar ro'yxatiga qo'shish va 24 ni belgilash


2-misol: 35 qiymatini 5 ga kamaytirish

  • 35 qiymatini 5 ga kamaytiramiz:

Decrease 35 to 5

35 ni 5 ga kamaytirish

  • Cut qismi: 26 ≠ nil va 5 < 26 bo'lganligi sababli, 5 ni kesib olamiz va ildizlar ro'yxatiga qo'shamiz:

Cut 5 and add it to root list

5 ni kesib olish va ildizlar ro'yxatiga qo'shish

  • Cascading-Cut qismi: 26 allaqachon belgilangan bo'lganligi sababli, boshqaruv Cut va Cascading-Cut amallariga o'tadi:
    • Cut(26): 26 ni kesib olib ildizlar ro'yxatiga qo'shamiz va belgisini bekor qilamiz (mark = false):

Cut 26 and add it to root list

26 ni kesib olish va ildizlar ro'yxatiga qo'shish

  • Cascading-Cut(24): 24 ham avval belgilanganligi sababli, yana Cut(24) va Cascading-Cut(7) chaqiriladi. Bu amallar natijasida 24 ham ildizlar ro'yxatiga qo'shiladi:

Cut 24 and add it to root list

24 ni kesib olish va ildizlar ro'yxatiga qo'shish

  • 5 < 7 bo'lganligi sababli, 5 tuguni yangi min deb belgilanadi:

Mark the min

5 ni yangi min deb belgilash


Tugunni o'chirish

Fibonachchi to'pidan ixtiyoriy tugunni o'chirish jarayoni decrease-key va extract-min amallarining birgalikdagi kombinatsiyasiga tayanadi:

  1. Aytaylik, k — o'chirilishi kerak bo'lgan tugun bo'lsin.
  2. decrease-key amalini qo'llab, ushbu k tugunning qiymatini mumkin bo'lgan eng kichik qiymatga (-∞) kamaytiring.
  3. Shundan so'ng, ushbu tugun to'pning eng kichik elementiga aylanadi. Endi extract-min amalini chaqirib, uni to'pdan butunlay olib tashlang.

Dasturiy namunalar: Go, Python, Java, C va C++

// Go tilida Fibonachchi to'pida Decrease Key va Delete amallari
package main

import (
	"fmt"
	"math"
)

// Fibonachchi daraxti tuguni
type FibonacciTree struct {
	key      int
	children []*FibonacciTree
	parent   *FibonacciTree
	marked   bool
	order    int
}

func newFibonacciTree(key int) *FibonacciTree {
	return &FibonacciTree{
		key:      key,
		children: make([]*FibonacciTree, 0),
		parent:   nil,
		marked:   false,
		order:    0,
	}
}

func (t *FibonacciTree) addAtEnd(other *FibonacciTree) {
	t.children = append(t.children, other)
	other.parent = t
	t.order++
}

// Fibonachchi to'pi
type FibonacciHeap struct {
	trees []*FibonacciTree
	least *FibonacciTree
	count int
}

func newFibonacciHeap() *FibonacciHeap {
	return &FibonacciHeap{
		trees: make([]*FibonacciTree, 0),
		least: nil,
		count: 0,
	}
}

// Tugun qo'shish
func (h *FibonacciHeap) insert(key int) *FibonacciTree {
	newTree := newFibonacciTree(key)
	h.trees = append(h.trees, newTree)
	if h.least == nil || key < h.least.key {
		h.least = newTree
	}
	h.count++
	return newTree
}

// Minimal qiymatni olish
func (h *FibonacciHeap) getMin() (int, bool) {
	if h.least == nil {
		return 0, false
	}
	return h.least.key, true
}

func floorLog2(x int) int {
	if x <= 0 {
		return 0
	}
	return int(math.Log2(float64(x)))
}

// Minimal elementni ajratib olish
func (h *FibonacciHeap) extractMin() (int, bool) {
	smallest := h.least
	if smallest == nil {
		return 0, false
	}

	for _, child := range smallest.children {
		child.parent = nil
		h.trees = append(h.trees, child)
	}

	newTrees := make([]*FibonacciTree, 0, len(h.trees))
	for _, t := range h.trees {
		if t != smallest {
			newTrees = append(newTrees, t)
		}
	}
	h.trees = newTrees

	if len(h.trees) == 0 {
		h.least = nil
	} else {
		h.least = h.trees[0]
		h.consolidate()
	}

	h.count--
	return smallest.key, true
}

// Daraxtlarni konsolidatsiya qilish
func (h *FibonacciHeap) consolidate() {
	auxSize := floorLog2(h.count) + 2
	aux := make([]*FibonacciTree, auxSize)

	for len(h.trees) > 0 {
		x := h.trees[0]
		h.trees = h.trees[1:]
		order := x.order

		for order < len(aux) && aux[order] != nil {
			y := aux[order]
			if x.key > y.key {
				x, y = y, x
			}
			x.addAtEnd(y)
			aux[order] = nil
			order++
			if order >= len(aux) {
				aux = append(aux, nil)
			}
		}
		if order >= len(aux) {
			for len(aux) <= order {
				aux = append(aux, nil)
			}
		}
		aux[order] = x
	}

	h.least = nil
	for _, k := range aux {
		if k != nil {
			h.trees = append(h.trees, k)
			if h.least == nil || k.key < h.least.key {
				h.least = k
			}
		}
	}
}

// Kalit qiymatini kamaytirish (Decrease Key)
func (h *FibonacciHeap) decreaseKey(x *FibonacciTree, newKey int) error {
	if newKey > x.key {
		return fmt.Errorf("yangi kalit mavjud kalitdan katta")
	}
	x.key = newKey
	y := x.parent
	if y != nil && x.key < y.key {
		h.cut(x, y)
		h.cascadingCut(y)
	}
	if x.key < h.least.key {
		h.least = x
	}
	return nil
}

// Tugunni ota tugundan uzib ildizlar ro'yxatiga qo'shish (Cut)
func (h *FibonacciHeap) cut(x *FibonacciTree, y *FibonacciTree) {
	newChildren := make([]*FibonacciTree, 0, len(y.children))
	for _, c := range y.children {
		if c != x {
			newChildren = append(newChildren, c)
		}
	}
	y.children = newChildren
	y.order--
	x.parent = nil
	x.marked = false
	h.trees = append(h.trees, x)
}

// Kaskadli kesish (Cascading Cut)
func (h *FibonacciHeap) cascadingCut(y *FibonacciTree) {
	z := y.parent
	if z != nil {
		if !y.marked {
			y.marked = true
		} else {
			h.cut(y, z)
			h.cascadingCut(z)
		}
	}
}

// Tugunni o'chirish (Delete)
func (h *FibonacciHeap) delete(x *FibonacciTree) {
	h.decreaseKey(x, math.MinInt)
	h.extractMin()
}

func main() {
	fheap := newFibonacciHeap()

	fheap.insert(11)
	fheap.insert(10)
	fheap.insert(39)
	fheap.insert(26)
	fheap.insert(24)

	if minVal, ok := fheap.getMin(); ok {
		fmt.Println("Minimum value:", minVal)
	}

	if removedVal, ok := fheap.extractMin(); ok {
		fmt.Println("Minimum value removed:", removedVal)
	}
}