Skip to content

Commit 23dca1c

Browse files
authored
Merge pull request #280 from ecodeclub/dev
准备 Release v0.0.10
2 parents fe23763 + a7e05db commit 23dca1c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1746
-80
lines changed

.devcontainer/devcontainer.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"image": "mcr.microsoft.com/devcontainers/go:1-1.23-bookworm",
3+
"customizations": {
4+
"vscode": {
5+
"extensions": [
6+
"golang.go",
7+
"eamodio.gitlens",
8+
"ms-vscode.makefile-tools"
9+
]
10+
}
11+
}
12+
}

.github/workflows/go.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ jobs:
3535
run: go build -v ./...
3636

3737
- name: Test
38-
run: go test -race -coverprofile=cover.out ./...
38+
run: make ut-coverage
3939

40-
- name: Post Coverage
41-
uses: codecov/codecov-action@v2
40+
- name: Upload results to Codecov
41+
uses: codecov/codecov-action@v5
42+
with:
43+
fail_ci_if_error: true
44+
token: ${{ secrets.CODECOV_TOKEN }}

Makefile

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,32 @@
1-
.PHONY: bench
2-
bench:
3-
@go test -bench=. -benchmem ./...
4-
5-
.PHONY: ut
6-
ut:
7-
@go test -tags=goexperiment.arenas -race ./...
8-
9-
.PHONY: setup
10-
setup:
11-
@sh ./.script/setup.sh
12-
13-
.PHONY: fmt
14-
fmt:
15-
@sh ./.script/goimports.sh
16-
17-
.PHONY: lint
18-
lint:
19-
@golangci-lint run -c .golangci.yml
20-
21-
.PHONY: tidy
22-
tidy:
23-
@go mod tidy -v
24-
25-
.PHONY: check
26-
check:
27-
@$(MAKE) fmt
1+
.PHONY: bench
2+
bench:
3+
@go test -bench=. -benchmem ./...
4+
5+
.PHONY: ut
6+
ut:
7+
@go test -tags=goexperiment.arenas -race ./...
8+
9+
.PHONY: ut-coverage
10+
ut-coverage:
11+
@go test -tags=goexperiment.arenas -race -coverprofile=cover.out ./...
12+
13+
.PHONY: setup
14+
setup:
15+
@sh ./.script/setup.sh
16+
17+
.PHONY: fmt
18+
fmt:
19+
@sh ./.script/goimports.sh
20+
21+
.PHONY: lint
22+
lint:
23+
@golangci-lint run -c .golangci.yml
24+
25+
.PHONY: tidy
26+
tidy:
27+
@go mod tidy -v
28+
29+
.PHONY: check
30+
check:
31+
@$(MAKE) fmt
2832
@$(MAKE) tidy

internal/queue/priority_queue.go

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ type PriorityQueue[T any] struct {
3535
compare ekit.Comparator[T]
3636
// 队列容量
3737
capacity int
38-
// 队列中的元素,为便于计算父子节点的index,0位置留空,根节点从1开始
38+
// 队列中的元素,根节点从0开始
3939
data []T
4040
}
4141

4242
func (p *PriorityQueue[T]) Len() int {
43-
return len(p.data) - 1
43+
return len(p.data)
4444
}
4545

4646
// Cap 无界队列返回0,有界队列返回创建队列时设置的值
@@ -53,19 +53,19 @@ func (p *PriorityQueue[T]) IsBoundless() bool {
5353
}
5454

5555
func (p *PriorityQueue[T]) isFull() bool {
56-
return p.capacity > 0 && len(p.data)-1 == p.capacity
56+
return p.capacity > 0 && len(p.data) == p.capacity
5757
}
5858

5959
func (p *PriorityQueue[T]) isEmpty() bool {
60-
return len(p.data) < 2
60+
return len(p.data) < 1
6161
}
6262

6363
func (p *PriorityQueue[T]) Peek() (T, error) {
6464
if p.isEmpty() {
6565
var t T
6666
return t, ErrEmptyQueue
6767
}
68-
return p.data[1], nil
68+
return p.data[0], nil
6969
}
7070

7171
func (p *PriorityQueue[T]) Enqueue(t T) error {
@@ -74,11 +74,12 @@ func (p *PriorityQueue[T]) Enqueue(t T) error {
7474
}
7575

7676
p.data = append(p.data, t)
77-
node, parent := len(p.data)-1, (len(p.data)-1)/2
78-
for parent > 0 && p.compare(p.data[node], p.data[parent]) < 0 {
77+
node := len(p.data) - 1
78+
parent := (node - 1) / 2
79+
for parent >= 0 && p.compare(p.data[node], p.data[parent]) < 0 {
7980
p.data[parent], p.data[node] = p.data[node], p.data[parent]
8081
node = parent
81-
parent = parent / 2
82+
parent = (parent - 1) >> 1
8283
}
8384

8485
return nil
@@ -90,11 +91,11 @@ func (p *PriorityQueue[T]) Dequeue() (T, error) {
9091
return t, ErrEmptyQueue
9192
}
9293

93-
pop := p.data[1]
94-
p.data[1] = p.data[len(p.data)-1]
94+
pop := p.data[0]
95+
p.data[0] = p.data[len(p.data)-1]
9596
p.data = p.data[:len(p.data)-1]
9697
p.shrinkIfNecessary()
97-
p.heapify(p.data, len(p.data)-1, 1)
98+
p.heapify(p.data, len(p.data), 0)
9899
return pop, nil
99100
}
100101

@@ -107,10 +108,10 @@ func (p *PriorityQueue[T]) shrinkIfNecessary() {
107108
func (p *PriorityQueue[T]) heapify(data []T, n, i int) {
108109
minPos := i
109110
for {
110-
if left := i * 2; left <= n && p.compare(data[left], data[minPos]) < 0 {
111+
if left := i*2 + 1; left < n && p.compare(data[left], data[minPos]) < 0 {
111112
minPos = left
112113
}
113-
if right := i*2 + 1; right <= n && p.compare(data[right], data[minPos]) < 0 {
114+
if right := i*2 + 2; right < n && p.compare(data[right], data[minPos]) < 0 {
114115
minPos = right
115116
}
116117
if minPos == i {
@@ -123,14 +124,14 @@ func (p *PriorityQueue[T]) heapify(data []T, n, i int) {
123124

124125
// NewPriorityQueue 创建优先队列 capacity <= 0 时,为无界队列,否则有有界队列
125126
func NewPriorityQueue[T any](capacity int, compare ekit.Comparator[T]) *PriorityQueue[T] {
126-
sliceCap := capacity + 1
127+
sliceCap := capacity
127128
if capacity < 1 {
128129
capacity = 0
129130
sliceCap = 64
130131
}
131132
return &PriorityQueue[T]{
132133
capacity: capacity,
133-
data: make([]T, 1, sliceCap),
134+
data: make([]T, 0, sliceCap),
134135
compare: compare,
135136
}
136137
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2021 ecodeclub
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package queue
16+
17+
import "testing"
18+
19+
func BenchmarkPriorityQueue_NoCapacity_Enqueue(b *testing.B) {
20+
n := 300000
21+
pq := priorityQueueOf(-1, []int{}, compare())
22+
b.ResetTimer()
23+
for i := n; i > 0; i-- {
24+
if pq.Enqueue(i) != nil {
25+
b.Fail()
26+
}
27+
}
28+
}
29+
30+
func BenchmarkPriorityQueue_NoCapacity_Dequeue(b *testing.B) {
31+
n := 300000
32+
pq := priorityQueueOf(-1, []int{}, compare())
33+
for i := n; i > 0; i-- {
34+
if pq.Enqueue(i) != nil {
35+
b.Fail()
36+
}
37+
}
38+
b.ResetTimer()
39+
for i := 0; i < n; i++ {
40+
_, err := pq.Dequeue()
41+
if err != nil {
42+
b.Fail()
43+
}
44+
}
45+
}
46+
47+
func BenchmarkPriorityQueue_Capacity_Enqueue(b *testing.B) {
48+
n := 300000
49+
pq := priorityQueueOf(n, []int{}, compare())
50+
b.ResetTimer()
51+
for i := n; i > 0; i-- {
52+
if pq.Enqueue(i) != nil {
53+
b.Fail()
54+
}
55+
}
56+
}
57+
58+
func BenchmarkPriorityQueue_Capacity_Dequeue(b *testing.B) {
59+
n := 300000
60+
pq := priorityQueueOf(n, []int{}, compare())
61+
for i := n; i > 0; i-- {
62+
if pq.Enqueue(i) != nil {
63+
b.Fail()
64+
}
65+
}
66+
b.ResetTimer()
67+
for i := 0; i < n; i++ {
68+
_, err := pq.Dequeue()
69+
if err != nil {
70+
b.Fail()
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)