______ __ __ _______ __ __ _______
/ __ \ | | | | | ____|| | | | | ____|
| | | | | | | | | |__ | | | | | |__
| | | | | | | | | __| | | | | | __|
| `--' '--.| `--' | | |____ | `--' | | |____
\_____\_____\\______/ |_______| \______/ |_______|
在上一章中我們學習了棧以及棧的基本操作,并使用數組切片和鏈表來實現了兩種不同的棧操作方式,接下來我們將學習并實現隊列。
隊列與棧非常相似,但是元素的出入原則與棧不同,在棧中元素是以后進先出(LIFO)的原則進行的,而在隊列中元素以先進先出(FIFO)的原則進行。
隊列與棧類似,是一種特殊的線性表,它只允許在表的前端進行插入操作,也只允許在表的后端進行彈出操作。進行插入操作的一端稱為隊尾,而進行刪除操作的一端則稱為隊頭。
本章將基于Go數組切片、鏈表來實現隊列的基本操作,同時實現雙端隊列,最終探討循環隊列的特性以及應用。
隊列定義
首先對隊列定義如下基本操作接口:
- Enqueue(e ...Element):添加若干元素入隊
- Dequeue() Element:隊首元素出隊
- Peek() Element:獲取隊首元素,不出隊
- Empty() bool:隊列是否為空
- Size() int:返回隊隊列大小
- Clear():清空隊列
代碼如下
type Element interface{}
type Queue interface {
// 入隊
Enqueue(e ...Element)
// 出隊
Dequeue() Element
// 獲取隊首元素,不出隊
Peek() Element
// 隊列是否為空你
Empty() bool
// 返回隊列大小
Size() int
// 清空隊列
Clear()
}
向隊列添加元素
- 數組切片實現
// 入隊操作
func (s *ArrayQueue) Enqueue(e ...Element) {
*s = append(*s, e...)
}
- 鏈表實現
func (s *LinkedQueue) Enqueue(e ...Element) {
for _, v := range e {
s.Tail.Next = &node{
Value: v,
Next: nil,
}
s.Tail = s.Tail.Next
s.size++
}
}
從隊列移除元素
- 數組切片實現
// 出隊
func (s *ArrayQueue) Dequeue() Element {
if s.Empty() {
return nil
}
first := (*s)[0]
// 出隊操作
*s = (*s)[1:]
return first
}
- 鏈表實現
func (s *LinkedQueue) Dequeue() Element {
if s.Empty() {
return nil
}
first := s.Head.Next.Value
// 出隊
s.Head = s.Head.Next
s.size--
return first
}
查看隊列頭元素
- 數組切片實現
// 獲取隊首元素,不出隊
func (s *ArrayQueue) Peek() Element {
if s.Empty() {
return nil
}
return (*s)[0]
}
- 鏈表實現
func (s *LinkedQueue) Peek() Element {
if s.Empty() {
return nil
}
return s.Head.Next.Value
}
獲取隊列長度
- 數組切片實現
// 返回隊列大小
func (s *ArrayQueue) Size() int {
return len(*s)
}
- 鏈表實現
func (s *LinkedQueue) Size() int {
return s.size
}
檢查隊列是否為空
- 數組切片實現
// 隊列是否為空
func (s *ArrayQueue) Empty() bool {
return s.Size() == 0
}
- 鏈表實現
func (s *LinkedQueue) Empty() bool {
return s.Head == s.Tail
}
清空隊列
- 數組切片實現
// 清空隊列
func (s *ArrayQueue) Clear() {
*s = ArrayQueue{}
}
- 鏈表實現
func (s *LinkedQueue) Clear() {
s.Head.Next = nil
s.Tail = s.Head
s.size = 0
}
雙端隊列
雙端隊列也是在現實中非常常用的一種數據結構,它允許我們在隊列的兩端進行添加和刪除操作。
在本章中雙端隊列的實現主要有以下接口:
- AddFront(e ...Element):向隊首添加元素
- AddBack(e ...Element):向隊尾添加元素
- RemoveFront() Element:移除隊首元素
- RemoveBack() Element:移除隊尾元素
- PeekFront() Element:查看隊首元素,不出隊
- PeekBack() Element:查看隊尾元素,不出隊
- Size() int:獲取隊列長度
- Empty() bool:判斷隊列是否為空
向隊首添加元素
func (s *ArrayDeque) AddFront(e ...Element) {
ln := len(e)
rev := make([]Element, ln)
for i, v := range e {
rev[ln-i-1] = v
}
*s = append(rev, *s...)
}
向隊尾添加元素
func (s *ArrayDeque) AddBack(e ...Element) {
*s = append(*s, e...)
}
移除隊首元素
func (s *ArrayDeque) RemoveFront() Element {
if s.Empty() {
return nil
}
v := (*s)[0]
// 出隊
*s = (*s)[1:]
return v
}
移除隊尾元素
func (s *ArrayDeque) RemoveBack() Element {
if s.Empty() {
return nil
}
ln := len(*s)
v := (*s)[ln-1]
// 出隊
*s = (*s)[:ln-1]
return v
}
查看隊首元素
func (s *ArrayDeque) PeekFront() Element {
if s.Empty() {
return nil
}
return (*s)[0]
}
查看隊尾元素
func (s *ArrayDeque) PeekBack() Element {
if s.Empty() {
return nil
}
return (*s)[len(*s)-1]
}
獲取隊列長度
func (s *ArrayDeque) Size() int {
return len(*s)
}
隊列是否為空
func (s *ArrayDeque) Empty() bool {
return s.Size() == 0
}
完整實現代碼
隊列
package main
import "fmt"
type Element interface{}
type Queue interface {
// 入隊
Enqueue(e ...Element)
// 出隊
Dequeue() Element
// 獲取隊首元素,不出隊
Peek() Element
// 隊列是否為空你
Empty() bool
// 返回隊列大小
Size() int
// 清空隊列
Clear()
}
// 使用數組切片實現的隊列
type ArrayQueue []Element
// 入隊操作
func (s *ArrayQueue) Enqueue(e ...Element) {
*s = append(*s, e...)
}
// 出隊
func (s *ArrayQueue) Dequeue() Element {
if s.Empty() {
return nil
}
first := (*s)[0]
// 出隊操作
*s = (*s)[1:]
return first
}
// 獲取隊首元素,不出隊
func (s *ArrayQueue) Peek() Element {
if s.Empty() {
return nil
}
return (*s)[0]
}
// 隊列是否為空
func (s *ArrayQueue) Empty() bool {
return s.Size() == 0
}
// 返回隊列大小
func (s *ArrayQueue) Size() int {
return len(*s)
}
// 清空隊列
func (s *ArrayQueue) Clear() {
*s = ArrayQueue{}
}
func NewArrayQueue() Queue {
return &ArrayQueue{}
}
type node struct {
Value Element
Next *node
}
// 使用鏈表實現的隊列
// 這里使用帶有頭尾節點的鏈表
type LinkedQueue struct {
Head *node
Tail *node
size int
}
func (s *LinkedQueue) Enqueue(e ...Element) {
for _, v := range e {
s.Tail.Next = &node{
Value: v,
Next: nil,
}
s.Tail = s.Tail.Next
s.size++
}
}
func (s *LinkedQueue) Dequeue() Element {
if s.Empty() {
return nil
}
first := s.Head.Next.Value
// 出隊
s.Head = s.Head.Next
s.size--
return first
}
func (s *LinkedQueue) Peek() Element {
if s.Empty() {
return nil
}
return s.Head.Next.Value
}
func (s *LinkedQueue) Empty() bool {
return s.Head == s.Tail
}
func (s *LinkedQueue) Size() int {
return s.size
}
func (s *LinkedQueue) Clear() {
s.Head.Next = nil
s.Tail = s.Head
s.size = 0
}
func NewLinkedQueue() Queue {
head := &node{}
return &LinkedQueue{
Head: head,
Tail: head,
size: 0,
}
}
func main() {
q := NewArrayQueue()
//q := NewLinkedQueue()
fmt.Println("Empty:", q.Empty())
fmt.Println("Size:", q.Size())
q.Enqueue(1, 2, 3, 4, 5, 6)
fmt.Println("Enqueue 1,2,3,4,5,6")
fmt.Println("Size:", q.Size())
fmt.Println("Peek:", q.Peek())
fmt.Println("Dequeue:", q.Dequeue(), q.Dequeue(), q.Dequeue())
fmt.Println("Size:", q.Size())
fmt.Println("Empty:", q.Empty())
fmt.Println("Dequeue:", q.Dequeue(), q.Dequeue(), q.Dequeue())
fmt.Println("Size:", q.Size())
fmt.Println("Empty:", q.Empty())
fmt.Println("Enqueue:1,2,3")
q.Enqueue(1, 2, 3)
fmt.Println("Dequeue:", q.Dequeue(), q.Dequeue())
fmt.Println("Clear")
q.Clear()
fmt.Println("Empty:", q.Empty(), "Size:", q.Size())
}
運行結果
Empty: true
Size: 0
Enqueue 1,2,3,4,5,6
Size: 6
Peek: 1
Dequeue: 1 2 3
Size: 3
Empty: false
Dequeue: 4 5 6
Size: 0
Empty: true
Enqueue:1,2,3
Dequeue: 1 2
Clear
Empty: true Size: 0
Process finished with exit code 0
雙端隊列
package main
import "fmt"
type Element interface{}
type Deque interface {
// 向隊首添加元素
AddFront(e ...Element)
// 向隊尾添加元素
AddBack(e ...Element)
// 隊首元素出隊
RemoveFront() Element
// 隊尾元素出隊
RemoveBack() Element
// 查看隊首元素
PeekFront() Element
// 查看隊尾元素
PeekBack() Element
// 隊列長度
Size() int
// 隊列是否為空
Empty() bool
}
type ArrayDeque []Element
func (s *ArrayDeque) AddFront(e ...Element) {
ln := len(e)
rev := make([]Element, ln)
for i, v := range e {
rev[ln-i-1] = v
}
*s = append(rev, *s...)
}
func (s *ArrayDeque) AddBack(e ...Element) {
*s = append(*s, e...)
}
func (s *ArrayDeque) RemoveFront() Element {
if s.Empty() {
return nil
}
v := (*s)[0]
// 出隊
*s = (*s)[1:]
return v
}
func (s *ArrayDeque) RemoveBack() Element {
if s.Empty() {
return nil
}
ln := len(*s)
v := (*s)[ln-1]
// 出隊
*s = (*s)[:ln-1]
return v
}
func (s *ArrayDeque) PeekFront() Element {
if s.Empty() {
return nil
}
return (*s)[0]
}
func (s *ArrayDeque) PeekBack() Element {
if s.Empty() {
return nil
}
return (*s)[len(*s)-1]
}
func (s *ArrayDeque) Size() int {
return len(*s)
}
func (s *ArrayDeque) Empty() bool {
return s.Size() == 0
}
func NewArrayDeque() Deque {
return &ArrayDeque{}
}
func main() {
dq := NewArrayDeque()
dq.AddFront(1, 2, 3, 4, 5, 6, 7, 8, 9)
fmt.Println("AddFront: 1,2,3,4,5,6,7,8,9")
fmt.Println("RemoveFront:", dq.RemoveFront(), dq.RemoveFront())
fmt.Println("RemoveBack:", dq.RemoveBack(), dq.RemoveBack())
}
運行結果
AddFront: 1,2,3,4,5,6,7,8,9
RemoveFront: 9 8
RemoveBack: 1 2
Process finished with exit code 0