使用链表和切片实现栈和队列
本篇文章将会使用数据结构中的栈和队列来实现音乐播放器的音乐添加和删除功能,分别使用切片和链表实现它。
1. 栈的链表实现
1.1 音乐添加
type song struct {
value interface{}
next *song
}
type Stack struct {
top *song
size int
}
func (stack *Stack) add_song(value interface{}) {
stack.top = &song{value: value, next: stack.top}
fmt.Printf("the top song is %s\n", stack.top.value)
stack.size++
}
实现介绍:
- 使用空接口 value 实现任意类型的存储。
- 栈是 LIFO(Last In First Out) 结构,因此定义 top 指针始终指向栈顶,实现音乐的添加和删除。
- 这里将栈顶 top 指针和链表的 next 指针关联,并且取代了头指针,栈底是 next 指针指向 nil 的元素。
1.2 音乐删除
func (stack *Stack) delete_song() {
if stack.top.next != nil {
stack.top = stack.top.next
fmt.Printf("the top song is %s\n", stack.top.value)
stack.size--
} else {
stack.size = 0
fmt.Printf("it's an empty playlist\n")
}
}
2. 栈的切片实现
2.1 音乐添加
type ItemType interface{}
type Stack_Slice struct {
song []ItemType
rwLock sync.RWMutex
}
func (stack *Stack_Slice) add_song_slice(value interface{}) {
stack.rwLock.Lock()
stack.song = append(stack.song, value)
stack.rwLock.Unlock()
}
实现介绍:
- 使用空接口实现切片对任何类型的存储。
- 使用读写锁防止切片数据的修改。
- 音乐添加实际做的是切片的 append 操作。
2.2 音乐删除
func (stack *Stack_Slice) delete_song_slice() {
if len(stack.song) != 0 {
stack.rwLock.Lock()
stack.song = stack.song[0 : len(stack.song)-1]
stack.rwLock.Unlock()
} else {
fmt.Printf("It's a empty playlist")
}
}
实现介绍:
- 音乐删除实际上做的是切片的分片操作。
Tips: 栈的链表/切片实现,其复杂度均为 O(1)。
3 队列的链表实现
3.1 音乐添加
type Queue struct {
head *song_
tail *song_
}
type song_ struct {
value interface{}
next *song_
}
func (queue *Queue) add_song(value interface{}) {
current_song := &song_{value: value}
if queue.tail != nil {
queue.tail.next, queue.tail = current_song, current_song
} else {
queue.tail, queue.head = current_song, current_song
}
}
实现介绍:
- 队列是 FIFO(First In First Out) 结构,这里设计了两个指针分别指向队头和队尾。
- 链表中的 next 指向顺序是从队头指向队尾。
3.2 音乐删除
func (queue *Queue) delete_song() {
if queue.head != nil {
queue.head = queue.head.next
} else {
fmt.Printf("It's a empty playlist")
}
}
4 队列的切片实现
队列的切片实现类似于链表,区别在于底层数组元素的截断。
芝兰生于空谷,不以无人而不芳。