diff --git a/slice/slice.go b/slice/slice.go index c02bb59..ce84584 100644 --- a/slice/slice.go +++ b/slice/slice.go @@ -160,3 +160,35 @@ func Align[T any](k []T, v []T, less func(T, T) bool) []Pair[*T, *T] { return lis } + +func Heapify[T any](arr []T, n, i int, less func(T, T) bool) { + largest := i + l := 2*i + 1 + r := 2*i + 2 + + if l < n && less(arr[largest], arr[l]) { + largest = l + } + if r < n && less(arr[largest], arr[r]) { + largest = r + } + if largest != i { + arr[i], arr[largest] = arr[largest], arr[i] + Heapify(arr, n, largest, less) + } +} + +func BuildMaxHeap[T any](arr []T, less func(T, T) bool) { + n := len(arr) + for i := (n / 2) - 1; i >= 0; i-- { + Heapify(arr, n, i, less) + } +} + +func HeapSort[T any](arr []T, less func(T, T) bool) { + BuildMaxHeap(arr, less) + for i := len(arr) - 1; i > 0; i-- { + arr[0], arr[i] = arr[i], arr[0] + Heapify(arr, i, 0, less) + } +} diff --git a/slice/slice_test.go b/slice/slice_test.go index 8806005..e3ce05e 100644 --- a/slice/slice_test.go +++ b/slice/slice_test.go @@ -51,3 +51,21 @@ func TestAlign(t *testing.T) { } func ptr[T any](v T) *T { return &v } + +func TestHeapSort(t *testing.T) { + is := is.New(t) + + arr := []int{9, 4, 3, 8, 10, 2, 5} + slice.HeapSort(arr, func(l, r int) bool { return l < r }) + + is.Equal(arr, []int{2, 3, 4, 5, 8, 9, 10}) +} + +func TestBuildHeap(t *testing.T) { + is := is.New(t) + + arr := []int{1, 3, 5, 4, 6, 13, 10, 9, 8, 15, 17} + slice.BuildMaxHeap(arr, func(l, r int) bool { return l < r }) + + is.Equal(arr, []int{17, 15, 13, 9, 6, 5, 10, 4, 8, 3, 1}) +} diff --git a/xdg/xdg.go b/xdg/xdg.go index 0c37931..f2638b3 100644 --- a/xdg/xdg.go +++ b/xdg/xdg.go @@ -39,6 +39,17 @@ func setENV(name, value string) string { func Get(base, suffix string) string { return strings.Join(paths(base, suffix), string(os.PathListSeparator)) } +func GetRoot(base, suffix string, perm os.FileMode) (*os.Root, error) { + fs, err := os.OpenRoot(base) + if err != nil { + return nil, err + } + err = fs.Mkdir(Get(base, suffix), perm) + if err != nil { + return nil, err + } + return os.OpenRoot(Get(base, suffix)) +} func paths(base, suffix string) []string { paths := strings.Split(os.ExpandEnv(base), string(os.PathListSeparator)) for i, path := range paths {