Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go: [ '1.23.11' ]
go: [ '1.24.0' ]
steps:
- uses: actions/checkout@v3

Expand Down
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: "2"

run:
go: "1.23"
go: "1.24"
timeout: 5m
tests: false
issues-exit-code: 1
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BSD 3-Clause License

Copyright (c) 2019-2025, Mikhail Knyazhev <markus621@yandex.com>
Copyright (c) 2019-2026, Mikhail Knyazhev <markus621@yandex.com>

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Expand Down
2 changes: 1 addition & 1 deletion control/semaphore.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2025 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Copyright (c) 2019-2026 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Use of this source code is governed by a BSD 3-Clause license that can be found in the LICENSE file.
*/

Expand Down
2 changes: 1 addition & 1 deletion encoding/base62/base62.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2025 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Copyright (c) 2019-2026 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Use of this source code is governed by a BSD 3-Clause license that can be found in the LICENSE file.
*/

Expand Down
2 changes: 1 addition & 1 deletion encoding/base62/base62_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2025 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Copyright (c) 2019-2026 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Use of this source code is governed by a BSD 3-Clause license that can be found in the LICENSE file.
*/

Expand Down
2 changes: 1 addition & 1 deletion encoding/otp/options.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2025 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Copyright (c) 2019-2026 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Use of this source code is governed by a BSD 3-Clause license that can be found in the LICENSE file.
*/

Expand Down
2 changes: 1 addition & 1 deletion encoding/otp/totp.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2025 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Copyright (c) 2019-2026 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Use of this source code is governed by a BSD 3-Clause license that can be found in the LICENSE file.
*/

Expand Down
2 changes: 1 addition & 1 deletion encoding/otp/totp_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2025 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Copyright (c) 2019-2026 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Use of this source code is governed by a BSD 3-Clause license that can be found in the LICENSE file.
*/

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module go.osspkg.com/algorithms

go 1.23.11
go 1.24.0

require (
github.com/cespare/xxhash/v2 v2.3.0
Expand Down
173 changes: 96 additions & 77 deletions graph/kahn/type.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2025 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Copyright (c) 2019-2026 Mikhail Knyazhev <markus621@yandex.com>. All rights reserved.
* Use of this source code is governed by a BSD 3-Clause license that can be found in the LICENSE file.
*/

Expand All @@ -9,118 +9,137 @@ package kahn

import (
"errors"
"fmt"
"sort"
)

var (
ErrBuildKahn = errors.New("can't do topographical sorting")
ErrBreakPointKahn = errors.New("don`t found topographical break point")
ErrBuild = errors.New("can't do topographical sorting")
ErrBreakPoint = errors.New("don`t found topographical break point")
)

const empty = ""

type Graph struct {
graph map[string]map[string]int
all map[string]struct{}
result []string
from map[string][]string
to map[string][]string

nodes map[string]struct{}

breakPoint string
result []string
}

func New() *Graph {
return &Graph{
graph: make(map[string]map[string]int),
all: make(map[string]struct{}),
from: make(map[string][]string),
to: make(map[string][]string),
nodes: make(map[string]struct{}),
result: make([]string, 0),
}
}

// Add - Adding a graph edge
func (k *Graph) Add(from, to string) {
if _, ok := k.graph[from]; !ok {
k.graph[from] = make(map[string]int)
}
k.graph[from][to]++
func (g *Graph) Add(from, to string) {
g.from[from] = append(g.from[from], to)
g.to[to] = append(g.to[to], from)
g.nodes[from] = struct{}{}
g.nodes[to] = struct{}{}
}

func (k *Graph) BreakPoint(point string) {
k.breakPoint = point
func (g *Graph) BreakPoint(point string) {
g.breakPoint = point
}

// To update the temporary map
func (k *Graph) updateTemp() (int, []string) {
for i, sub := range k.graph {
for j := range sub {
k.all[j] = struct{}{}
func (g *Graph) Build() error {
g.result = g.result[:0]

var active map[string]struct{}

if len(g.breakPoint) == 0 {
active = g.copyAllNodes()
} else {
active = g.copyNodesByBreakPoint()
if len(active) == 0 {
return ErrBreakPoint
}
k.all[i] = struct{}{}
}
temp := make([]string, 0, len(k.all))
for s := range k.all {
temp = append(temp, s)
}
sort.Strings(temp)
return len(k.all), temp
}

// Build - Perform sorting
func (k *Graph) Build() error {
k.result = k.result[:0]
length, temp := k.updateTemp()

if len(k.breakPoint) > 0 {
j := -1
for i, name := range temp {
if k.breakPoint == name {
j = i
inDegree := make(map[string]int)
for u := range active {
for _, v := range g.from[u] {
if _, ok := active[v]; ok {
inDegree[v]++
}
}
if j < 0 {
return fmt.Errorf("%w: %s", ErrBreakPointKahn, k.breakPoint)
}

queue := make([]string, 0, len(active))

for _, key := range getKeys(active) {
if inDegree[key] == 0 {
queue = append(queue, key)
}
temp[0], temp[j] = temp[j], temp[0]
}

for len(k.result) < length {
found := ""
i := 0
for j, item := range temp {
if item == empty {
continue
}
if k.find(item) {
found = item
i = j
break
for len(queue) > 0 {
key := queue[0]
queue = queue[1:]

g.result = append(g.result, key)

for _, v := range g.from[key] {
if _, ok := active[v]; ok {
inDegree[v]--
if inDegree[v] == 0 {
queue = append(queue, v)
}
}
}
if len(found) > 0 {
k.result = append(k.result, found)
delete(k.all, found)
temp[i] = empty
} else {
return ErrBuildKahn
}
if len(k.breakPoint) > 0 && found == k.breakPoint {
break
}
}

if len(g.result) != len(active) {
return ErrBuild
}

return nil
}

// Finding the next edge
func (k *Graph) find(item string) bool {
for i, j := range k.graph {
if _, jok := j[item]; jok {
if _, iok := k.all[i]; iok {
return false
}
func (g *Graph) Result() []string {
return append(make([]string, 0, len(g.result)), g.result...)
}

func (g *Graph) copyAllNodes() map[string]struct{} {
tmp := make(map[string]struct{}, len(g.nodes))
for k := range g.nodes {
tmp[k] = struct{}{}
}
return tmp
}

func (g *Graph) copyNodesByBreakPoint() map[string]struct{} {
if _, ok := g.nodes[g.breakPoint]; !ok {
return nil
}

queue := make([]string, 0, len(g.nodes))
tmp := make(map[string]struct{}, len(g.nodes))

queue = append(queue, g.breakPoint)
for len(queue) > 0 {
key := queue[0]
queue = queue[1:]

if _, ok := tmp[key]; ok {
continue
}
tmp[key] = struct{}{}
queue = append(queue, g.to[key]...)
}
return true
return tmp
}

// Result - Getting a sorted slice
func (k *Graph) Result() []string {
return append(make([]string, 0, len(k.result)), k.result...)
func getKeys(in map[string]struct{}) []string {
result := make([]string, 0, len(in))
for k := range in {
result = append(result, k)
}
sort.Strings(result)
return result
}
Loading
Loading