diff --git a/algorithm/ds/tree/merkle_tree.go b/algorithm/ds/tree/merkle_tree.go index ce3b8df..261e4c5 100644 --- a/algorithm/ds/tree/merkle_tree.go +++ b/algorithm/ds/tree/merkle_tree.go @@ -1,5 +1,76 @@ package main +import ( + "crypto/md5" + "fmt" +) + // 基于二叉树实现 哈希树 +// Git 用于比对文件系统差异时提升效率 +// P2P下载中BT种子的构成是hash列表(按块拆分文件后做hash得到) // https://en.wikipedia.org/wiki/Merkle_tree // https://yeasy.gitbook.io/blockchain_guide/05_crypto/merkle_trie + +type ( + Merkle struct { + tree *BinTree[string] + } +) + +func CreateMerkleByFile(path string) *Merkle { + // 对文件分块计算Hash构造树并存储 + return nil +} + +func CreateMerkle(hash []string) *Merkle { + if len(hash) == 0 { + return nil + } + + var tmp []*BinTree[string] + for _, s := range hash { + tmp = append(tmp, &BinTree[string]{Data: s}) + } + for { + if len(tmp) == 1 { + break + } + var par []*BinTree[string] + var node *BinTree[string] + for i := range tmp { + if node == nil { + node = &BinTree[string]{Left: tmp[i]} + par = append(par, node) + } else { + node.Right = tmp[i] + node = nil + } + } + for _, b := range par { + fillData(b) + } + tmp = par + } + return &Merkle{tree: tmp[0]} +} +func (m *Merkle) Same(merkle *Merkle) bool { + if merkle == nil { + return false + } + return m.tree.Data == merkle.tree.Data +} +func fillData(node *BinTree[string]) { + if node == nil { + return + } + c := node.Left.Data + if node.Right != nil { + c += " " + node.Right.Data + } + + node.Data = hash(c) +} +func hash(val string) string { + sum := md5.Sum([]byte(val)) + return fmt.Sprintf("%x", sum) +} diff --git a/algorithm/ds/tree/merkle_tree_test.go b/algorithm/ds/tree/merkle_tree_test.go new file mode 100644 index 0000000..9947561 --- /dev/null +++ b/algorithm/ds/tree/merkle_tree_test.go @@ -0,0 +1,27 @@ +package main + +import ( + "github.com/kuangcp/gobase/pkg/ctool/algo" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestInitMerkleByHash(t *testing.T) { + merkle := CreateMerkle([]string{"a", "b", "c", "d", "e", "f"}) + + println(algo.PrintBiMindMap(merkle.tree)) +} + +func TestMerkle_Same(t *testing.T) { + a := CreateMerkle([]string{"a", "b", "c", "d", "e", "f"}) + println(algo.PrintBiMindMap(a.tree)) + + b := CreateMerkle([]string{"a", "b", "c", "d", "e", "f"}) + println(algo.PrintBiMindMap(b.tree)) + + c := CreateMerkle([]string{"a", "b", "c", "d", "e"}) + println(algo.PrintBiMindMap(c.tree)) + + assert.Equal(t, a.Same(b), true) + assert.Equal(t, a.Same(c), false) +} diff --git a/algorithm/go.mod b/algorithm/go.mod index be2ddd3..0a1d794 100644 --- a/algorithm/go.mod +++ b/algorithm/go.mod @@ -4,9 +4,12 @@ go 1.19 require ( github.com/kuangcp/gobase/pkg/ctool v1.1.9 - github.com/tidwall/pretty v1.2.1 github.com/stretchr/testify v1.8.4 - golang.org/x/exp v0.0.0-20231006140011-7918f672742d + github.com/tidwall/pretty v1.2.1 + golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc +) + +require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/algorithm/gowork b/algorithm/gowork new file mode 100644 index 0000000..0e01544 --- /dev/null +++ b/algorithm/gowork @@ -0,0 +1,11 @@ +//go 1.19 +// +//use ( +// . +// huffman +// linkedlist +//) +// +//replace ( +// github.com/kuangcp/gobase/pkg/ctool v1.1.5 => ../pkg/ctool +//) \ No newline at end of file diff --git a/learn/system/go.mod b/learn/system/go.mod index 1d47c81..7cd0fd4 100644 --- a/learn/system/go.mod +++ b/learn/system/go.mod @@ -1,5 +1,7 @@ module system +// 系统级信息 + go 1.20 require ( diff --git a/pkg/ctool/go.mod b/pkg/ctool/go.mod index 610081b..df6235c 100644 --- a/pkg/ctool/go.mod +++ b/pkg/ctool/go.mod @@ -6,8 +6,8 @@ go 1.18 require ( github.com/stretchr/testify v1.8.4 - go.uber.org/goleak v1.2.1 - golang.org/x/exp v0.0.0-20231006140011-7918f672742d + go.uber.org/goleak v1.3.0 + golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 ) require ( diff --git a/pkg/ctool/stream/collector_test.go b/pkg/ctool/stream/collector_test.go index 7a883eb..54fdc5d 100644 --- a/pkg/ctool/stream/collector_test.go +++ b/pkg/ctool/stream/collector_test.go @@ -68,11 +68,11 @@ func TestToSet(t *testing.T) { func TestJoinPerformance(t *testing.T) { start := time.Now().UnixMicro() _ = ToJoin(JustN(10000).MapStr()) - fmt.Println(time.Now().UnixMicro()-start, "us") + fmt.Println("sin", time.Now().UnixMicro()-start, "us") start = time.Now().UnixMicro() _ = ToJoin(JustN(10000).Map(ToString, WithWorkers(100))) - fmt.Println(time.Now().UnixMicro()-start, "us") + fmt.Println("con", time.Now().UnixMicro()-start, "us") } func TestMultiGet(t *testing.T) { diff --git a/toolbox/countzh/go.mod b/toolbox/countzh/go.mod index 3a19f96..a66ee3f 100644 --- a/toolbox/countzh/go.mod +++ b/toolbox/countzh/go.mod @@ -4,5 +4,5 @@ go 1.13 require ( github.com/go-redis/redis/v7 v7.2.0 - github.com/kuangcp/gobase/pkg/cuibase v1.0.5 + github.com/kuangcp/gobase/pkg/cuibase v1.0.7 ) diff --git a/toolbox/ksync/main.go b/toolbox/ksync/main.go index a61ae84..d445daf 100644 --- a/toolbox/ksync/main.go +++ b/toolbox/ksync/main.go @@ -45,7 +45,7 @@ func init() { flag.IntVar(&port, "p", 8000, "port") flag.IntVar(&checkSec, "c", 2, "check duration second") flag.BoolVar(&version, "v", false, "version") - flag.StringVar(&serverAddr, "s", "", "init server host&port. ag: 192.168.0.1:8000") + flag.StringVar(&serverAddr, "s", "", "init server host and port. ag: 192.168.0.1:8000") flag.StringVar(&localHost, "l", "", "local side host. ag: 192.168.0.2") flag.StringVar(&syncDir, "d", "./", "sync dir.") }