Skip to content

Commit e93b4f4

Browse files
committed
Add examples/singleapp/linkedlist/circular
1 parent bb05033 commit e93b4f4

File tree

3 files changed

+259
-0
lines changed

3 files changed

+259
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# https://taskfile.dev
2+
3+
version: '3'
4+
5+
tasks:
6+
default:
7+
cmds:
8+
- go run .
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
8+
type (
9+
// Node は、連結リストのノートを表します.
10+
Node[T any] struct {
11+
Value T // 値
12+
Next *Node[T] // 次要素
13+
}
14+
15+
// Circular は、循環連結リストを表します.
16+
// Capacityを超えた場合、最も古い要素から上書きされます.
17+
Circular[T any] struct {
18+
Head *Node[T] // 先頭
19+
Tail *Node[T] // 末尾
20+
Size int // 要素数
21+
Capacity int // キャパシティ
22+
}
23+
)
24+
25+
// String は、Nodeの文字列表現を返します.
26+
func (me *Node[T]) String() string {
27+
if me == nil {
28+
return ""
29+
}
30+
31+
if me.Next == nil {
32+
return fmt.Sprintf("(v:%v,n:nil)", me.Value)
33+
}
34+
35+
return fmt.Sprintf("(v:%v,n:%v)", me.Value, me.Next.Value)
36+
}
37+
38+
// NewCircular は、指定されたキャパシティを持つ[*Circular]を生成します.
39+
func NewCircular[T any](capacity int) *Circular[T] {
40+
if capacity <= 0 {
41+
panic("capacity must be positive")
42+
}
43+
44+
return &Circular[T]{
45+
Head: nil,
46+
Tail: nil,
47+
Size: 0,
48+
Capacity: capacity,
49+
}
50+
}
51+
52+
// Add は、末尾に新しい要素を追加します.
53+
func (me *Circular[T]) Add(value T) {
54+
var (
55+
n = &Node[T]{Value: value}
56+
)
57+
58+
if me.Head == nil {
59+
me.Head = n
60+
me.Tail = n
61+
me.Size = 1
62+
63+
return
64+
}
65+
66+
if me.Size < me.Capacity {
67+
me.Tail.Next = n
68+
me.Tail = n
69+
me.Size++
70+
} else {
71+
me.Head = me.Head.Next
72+
me.Tail.Next = n
73+
me.Tail = n
74+
}
75+
}
76+
77+
// Delete は、指定した値に合致する最初のノードを削除します.
78+
//
79+
// 型パラメータでは、comparableかどうかが判別できませんので、比較判定関数を指定する必要があります。
80+
func (me *Circular[T]) Delete(value T, equal func(v1, v2 T) bool) bool {
81+
if me.Head == nil {
82+
return false
83+
}
84+
85+
if equal(me.Head.Value, value) {
86+
me.Head = me.Head.Next
87+
me.Size--
88+
89+
if me.Size == 0 {
90+
me.Tail = nil
91+
}
92+
93+
return true
94+
}
95+
96+
var (
97+
current = me.Head
98+
)
99+
for current.Next != nil {
100+
if equal(current.Next.Value, value) {
101+
current.Next = current.Next.Next // 削除対象を抜いて要素を詰める
102+
103+
if current.Next == nil {
104+
me.Tail = current
105+
}
106+
107+
me.Size--
108+
109+
return true
110+
}
111+
112+
current = current.Next
113+
}
114+
115+
return false
116+
}
117+
118+
// ToSlice は、要素の値をスライスにして返します.
119+
func (me *Circular[T]) ToSlice() []T {
120+
var (
121+
result = make([]T, 0, me.Size)
122+
current = me.Head
123+
)
124+
125+
for range me.Size {
126+
result = append(result, current.Value)
127+
current = current.Next
128+
}
129+
130+
return result
131+
}
132+
133+
// String は、[*Circular]の文字列表現を返します.
134+
func (me *Circular[T]) String() string {
135+
if me.Head == nil {
136+
return "[]"
137+
}
138+
139+
var (
140+
sb strings.Builder
141+
current = me.Head
142+
)
143+
144+
sb.WriteString("[")
145+
{
146+
for i := 0; i < me.Size; i++ {
147+
if i > 0 {
148+
sb.WriteString(" -> ")
149+
}
150+
151+
sb.WriteString(fmt.Sprintf("%v", current.Value))
152+
current = current.Next
153+
}
154+
}
155+
sb.WriteString(" ->]")
156+
157+
return sb.String()
158+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
)
8+
9+
func init() {
10+
log.SetFlags(0)
11+
}
12+
13+
func main() {
14+
var (
15+
rootCtx = context.Background()
16+
mainCtx, mainCxl = context.WithCancel(rootCtx)
17+
err error
18+
)
19+
defer mainCxl()
20+
21+
if err = run(mainCtx); err != nil {
22+
log.Fatal(err)
23+
}
24+
}
25+
26+
func run(_ context.Context) error {
27+
var (
28+
circular = NewCircular[string](5)
29+
)
30+
31+
//
32+
// Add
33+
//
34+
title("Add")
35+
{
36+
for _, r := range "helloworld" {
37+
circular.Add(string(r))
38+
log.Println(circular)
39+
}
40+
}
41+
42+
//
43+
// Iterate (slice)
44+
//
45+
title("Iterate (slice)")
46+
{
47+
for i, v := range circular.ToSlice() {
48+
log.Printf("%02d: %v", i, v)
49+
}
50+
}
51+
52+
//
53+
// Iterate (node)
54+
//
55+
title("Iterate (node)")
56+
{
57+
if circular.Head != nil {
58+
for n := circular.Head; ; n = n.Next {
59+
log.Println(n)
60+
61+
if n == circular.Tail {
62+
break
63+
}
64+
}
65+
}
66+
}
67+
68+
//
69+
// Delete
70+
//
71+
title("Delete")
72+
{
73+
var (
74+
fn = func(v1, v2 string) bool {
75+
return v1 == v2
76+
}
77+
deletes = []string{"d", "w", "r"}
78+
)
79+
for _, d := range deletes {
80+
if ok := circular.Delete(d, fn); !ok {
81+
return fmt.Errorf("Delete() returns false (%v)", d)
82+
}
83+
84+
log.Println(circular)
85+
}
86+
}
87+
88+
return nil
89+
}
90+
91+
func title(m string) {
92+
log.Printf("----------[%s]----------", m)
93+
}

0 commit comments

Comments
 (0)