diff --git a/examples/queue/main.go b/examples/queue/main.go new file mode 100644 index 0000000..346d195 --- /dev/null +++ b/examples/queue/main.go @@ -0,0 +1,29 @@ +// queue 包示例:链式队列(Create 批量建队、Push 入列、Pop 出队、Print、Length) +package main + +import ( + "fmt" + + "git.zeroonesoft.cn/golib/zogo/queue" +) + +func main() { + // 头结点作为哨兵,Create 批量创建队列元素 + q := &queue.QueueNode{} + q.Create(1, 2, 3) + fmt.Print("Create 后队列: ") + q.Print() + fmt.Println("Length:", q.Length()) + + // Push 入列(追加到队尾) + q.Push(4) + fmt.Print("Push 4 后: ") + q.Print() + fmt.Println("Length:", q.Length()) + + // Pop 出队:在头结点上调用,返回头结点自身 Data(哨兵为 nil),并使队列前进一个节点 + _ = q.Pop() + fmt.Print("Pop 后队列: ") + q.Print() + fmt.Println("Length:", q.Length()) +} diff --git a/queue/README.md b/queue/README.md new file mode 100644 index 0000000..f398f83 --- /dev/null +++ b/queue/README.md @@ -0,0 +1,30 @@ +# queue + +基于链表实现的先进先出队列(哨兵头结点风格)。 + +> 迁移自 go-hua/queue,代码保持原样。 + +## 用法 + +```go +import "git.zeroonesoft.cn/golib/zogo/queue" + +// 头结点作为哨兵,Create 批量建队 +q := &queue.QueueNode{} +q.Create(1, 2, 3) +q.Length() // 3 + +// Push 入列(追加队尾)/ Pop 出队 +q.Push(4) +v := q.Pop() // 在头结点上调用:返回头结点自身 Data(哨兵为 nil),队列前进一个节点 +q.Print() // 打印剩余元素 +``` + +完整可运行例程:[examples/queue/main.go](../examples/queue/main.go) + +## 注意 + +- `Pop` 语义特殊:在**哨兵头结点**上调用,返回的是哨兵自身的 `Data`(通常为 nil) + 并让队列前进一格;取真正的队头元素请在 `q.Next` 上调用或先取 `q.Next.Data`。 +- `Pop` 在队列仅剩哨兵(`Next == nil`)时调用会 panic,出队前先判断 `Length()`。 +- 元素为 `interface{}`,非泛型非并发安全,多 goroutine 场景需外加拉锁。 diff --git a/queue/queue.go b/queue/queue.go new file mode 100644 index 0000000..8db42c4 --- /dev/null +++ b/queue/queue.go @@ -0,0 +1,95 @@ +// Package queue 基于链表实现的先进先出队列。 +package queue + +import "fmt" + +// QueueNode 队列节点,Data 存任意数据,Next 指向下一节点 +type QueueNode struct { + Data interface{} + Next *QueueNode +} + +// 创建链列(数据) +func (queue *QueueNode) Create(Data ...interface{}) { + if queue == nil { + return + } + if len(Data) == 0 { + return + } + + //创建链列 + for _, v := range Data { + newNode := new(QueueNode) + newNode.Data = v + + queue.Next = newNode + queue = queue.Next + } + +} + +// 打印链列 +func (queue *QueueNode) Print() { + if queue == nil { + return + } + for queue != nil { + if queue.Data != nil { + fmt.Print(queue.Data, " ") + } + queue = queue.Next + } + fmt.Println() +} + +// 链列个数 +func (queue *QueueNode) Length() int { + if queue == nil { + return -1 + } + + i := 0 + for queue.Next != nil { + i++ + queue = queue.Next + } + return i +} + +// 入列(insert) +func (queue *QueueNode) Push(Data interface{}) { + //放在队列的末尾 + + if queue == nil { + return + } + if Data == nil { + return + } + + //找到队列末尾 + for queue.Next != nil { + queue = queue.Next + } + + //创建新节点 将新节点加入队列末尾 + newNode := new(QueueNode) + newNode.Data = Data + + queue.Next = newNode +} + +// 出队(delete) +func (queue *QueueNode) Pop() interface{} { + //队头出列 + if queue == nil { + return nil + } + //记录列队第一个的节点 + //node:=queue.Next + //queue.Next=node.Next + data := queue.Data + queue.Next = queue.Next.Next + return data +} diff --git a/queue/queue_test.go b/queue/queue_test.go new file mode 100644 index 0000000..a4db1e8 --- /dev/null +++ b/queue/queue_test.go @@ -0,0 +1,44 @@ +package queue + +import "testing" + +func TestCreateAndLength(t *testing.T) { + q := &QueueNode{} + q.Create(1, 2, 3) + if got := q.Length(); got != 3 { + t.Errorf("Length = %d, want 3", got) + } +} + +func TestPush(t *testing.T) { + q := &QueueNode{} + q.Create("a") + q.Push("b") + if got := q.Length(); got != 2 { + t.Errorf("Push 后 Length = %d, want 2", got) + } +} + +func TestPop(t *testing.T) { + q := &QueueNode{} + q.Create(1, 2, 3) + // Pop 在头结点(哨兵)上调用,跳过第一个元素并返回头结点 Data + q.Pop() + if got := q.Length(); got != 2 { + t.Errorf("Pop 后 Length = %d, want 2", got) + } +} + +func TestCreateEmpty(t *testing.T) { + q := &QueueNode{} + q.Create() // 无元素,不应 panic + if got := q.Length(); got != 0 { + t.Errorf("空 Create 后 Length = %d, want 0", got) + } +} + +func TestPrint(t *testing.T) { + q := &QueueNode{} + q.Create(1, 2, 3) + q.Print() // 仅验证不 panic +}