it编程 > 前端脚本 > Golang

Go实现List、Set、Stack、Deque等数据结构的操作方法

31人参与 2025-02-14 Golang

go实现list、set、stack、deque等数据结构

完整代码地址(欢迎大家⭐️):https://github.com/ziyifast/ziyifast-code_instruction/tree/main/go-demo/go-data-structure
大家有接触过除go其他语言(如:java)可能就会想为什么go没有像deque、stack、set、list这些常见的数据容器。尤其是对于那些习惯了用这些容器解决leetcode问题的同学来说,就更为不便。

1 为什么go原生不提供这些容器:为了简洁

go语言自诞生以来就有着非常明确的目标,那就是简洁、高效、并发。为了实现这些目标,go在设计上做了很多取舍。

相反,通过社区贡献,go可以保持核心的简洁,同时又不失灵活性。

2 实现

完整代码地址:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/go-demo/go-data-structure

虽然go语言没有内置这些高级数据结构,但通过组合使用切片和映射,我们依然可以实现几乎所有需要的数据结构。

所以,下次再遇到类似的问题,大家也可以自己试试看实现这些数据结构,既能提升编码能力,又能更深入地理解go语言的设计理念。

list

思路:对于列表来说,通常需要有add、remove等操作,其实golang原生的切片就很接近切片,因此我们简单做封装即可

package main
import (
	"errors"
	"fmt"
)
/*
	list:
		- newlist(): 创建一个新的列表
		- add(element): 在列表末尾添加元素
		- remove(index): 根据索引移除元素
		- size(): 返回列表的大小
		- get(index): 根据索引获取元素
		- isempty(): 判断列表是否为空
		- clear(): 清空列表
		- getfirst(): 获取第一个元素
		- getlast(): 获取最后一个元素
		- removelast(): 移除最后一个元素
		- addfirst(element): 在列表开头添加元素
		- removefirst(): 移除第一个元素
		...
*/
type list struct {
	data []interface{}
}
// newlist 创建一个新的列表
func newlist() *list {
	return &list{
		data: []interface{}{},
	}
}
// add 在列表末尾添加元素
func (l *list) add(v interface{}) {
	l.data = append(l.data, v)
}
// remove 根据索引移除元素
func (l *list) remove(index int) error {
	if index < 0 || index >= len(l.data) {
		return errors.new("index out of bounds")
	}
	l.data = append(l.data[:index], l.data[index+1:]...)
	return nil
}
// size 返回列表的大小
func (l *list) size() int {
	return len(l.data)
}
// get 根据索引获取元素
func (l *list) get(index int) (interface{}, error) {
	if index < 0 || index >= len(l.data) {
		return nil, errors.new("index out of bounds")
	}
	return l.data[index], nil
}
// isempty 判断列表是否为空
func (l *list) isempty() bool {
	return len(l.data) == 0
}
// clear 清空列表
func (l *list) clear() {
	l.data = []interface{}{}
}
// getfirst 获取第一个元素
func (l *list) getfirst() (interface{}, error) {
	if l.isempty() {
		return nil, errors.new("list is empty")
	}
	return l.data[0], nil
}
// getlast 获取最后一个元素
func (l *list) getlast() (interface{}, error) {
	if l.isempty() {
		return nil, errors.new("list is empty")
	}
	return l.data[len(l.data)-1], nil
}
// addfirst 在列表开头添加元素
func (l *list) addfirst(v interface{}) {
	l.data = append([]interface{}{v}, l.data...)
}
// removefirst 移除第一个元素
func (l *list) removefirst() error {
	if l.isempty() {
		return errors.new("list is empty")
	}
	l.data = l.data[1:]
	return nil
}
// removelast 移除最后一个元素
func (l *list) removelast() error {
	if l.isempty() {
		return errors.new("list is empty")
	}
	l.data = l.data[:len(l.data)-1]
	return nil
}
func main() {
	list := newlist()
	// 测试 add 和 get
	list.add(1)
	list.add(2)
	list.add(3)
	value, err := list.get(1)
	if err != nil {
		fmt.println("error:", err)
	} else {
		fmt.println("value at index 1:", value) // 输出: value at index 1: 2
	}
	// 测试 remove
	err = list.remove(1)
	if err != nil {
		fmt.println("error:", err)
	} else {
		fmt.println("size after remove:", list.size()) // 输出: size after remove: 2
	}
	// 测试 getfirst 和 getlast
	first, err := list.getfirst()
	if err != nil {
		fmt.println("error:", err)
	} else {
		fmt.println("first element:", first) // 输出: first element: 1
	}
	last, err := list.getlast()
	if err != nil {
		fmt.println("error:", err)
	} else {
		fmt.println("last element:", last) // 输出: last element: 3
	}
	// 测试 addfirst 和 removefirst
	list.addfirst(0)
	first, err = list.getfirst()
	if err != nil {
		fmt.println("error:", err)
	} else {
		fmt.println("first element after addfirst:", first) // 输出: first element after addfirst: 0
	}
	err = list.removefirst()
	if err != nil {
		fmt.println("error:", err)
	} else {
		fmt.println("size after removefirst:", list.size()) // 输出: size after removefirst: 2
	}
	// 测试 removelast
	err = list.removelast()
	if err != nil {
		fmt.println("error:", err)
	} else {
		fmt.println("size after removelast:", list.size()) // 输出: size after removelast: 1
	}
	// 测试 clear
	list.clear()
	fmt.println("is list empty after clear?", list.isempty()) // 输出: is list empty after clear? true
}

stack

stack最大的特点就是:先进后出,这里底层存储我们也可以采用切片来进行封装

package main
import (
	"fmt"
)
/*
  stack:
	- push(item): 入栈
	- pop(): 出栈
	- peek(): 返回栈顶元素,但不删除它
	- isempty(): 判断栈是否为空
	- search(item): 搜索 item 元素在栈中的位置,如果没找到,返回 -1
	- clear(): 清空栈
	...
*/
type stack struct {
	data []interface{}
}
func newstack() *stack {
	return &stack{
		data: []interface{}{},
	}
}
// push 入栈
func (s *stack) push(v interface{}) {
	s.data = append(s.data, v)
}
// pop 出栈
func (s *stack) pop() interface{} {
	if len(s.data) == 0 {
		return nil
	}
	val := s.data[len(s.data)-1]
	s.data = s.data[:len(s.data)-1]
	return val
}
// peek 返回栈顶元素,但不删除它
func (s *stack) peek() interface{} {
	if len(s.data) == 0 {
		return nil
	}
	return s.data[len(s.data)-1]
}
// isempty 判断栈是否为空
func (s *stack) isempty() bool {
	return len(s.data) == 0
}
// search 搜索 item 元素在栈中的位置,如果没找到,返回 -1
func (s *stack) search(v interface{}) int {
	for index, value := range s.data {
		if value == v {
			return index
		}
	}
	return -1
}
// clear 清空栈
func (s *stack) clear() {
	s.data = []interface{}{}
}
func main() {
	stack := newstack()
	// 测试 push 和 peek
	stack.push(1)
	stack.push(2)
	stack.push(3)
	fmt.println("top element:", stack.peek()) // 输出: top element: 3
	// 测试 pop
	fmt.println("popped element:", stack.pop())         // 输出: popped element: 3
	fmt.println("top element after pop:", stack.peek()) // 输出: top element after pop: 2
	// 测试 isempty
	fmt.println("is stack empty?", stack.isempty()) // 输出: is stack empty? false
	// 测试 search
	fmt.println("index of 2:", stack.search(2)) // 输出: index of 2: 1
	fmt.println("index of 3:", stack.search(3)) // 输出: index of 3: -1
	// 测试 clear
	stack.clear()
	fmt.println("is stack empty after clear?", stack.isempty()) // 输出: is stack empty after clear? true
}

deque

deque双端队列:前后都可以进出

package main
import (
	"container/list"
	"fmt"
)
/*
	deque:
		- pushfront: 在队列前端插入元素
		- pushback: 在队列后端插入元素
		- popfront: 从队列前端移除并返回元素
		- popback: 从队列后端移除并返回元素
		...
*/
// deque 双端队列结构体
type deque struct {
	data *list.list
}
// newdeque 创建一个新的双端队列
func newdeque() *deque {
	return &deque{data: list.new()}
}
// pushfront 在队列前端插入元素
func (d *deque) pushfront(value interface{}) {
	d.data.pushfront(value)
}
// pushback 在队列后端插入元素
func (d *deque) pushback(value interface{}) {
	d.data.pushback(value)
}
// popfront 移除并返回队列前端的元素
func (d *deque) popfront() interface{} {
	front := d.data.front()
	if front != nil {
		d.data.remove(front)
		return front.value
	}
	return nil
}
// popback 移除并返回队列后端的元素
func (d *deque) popback() interface{} {
	back := d.data.back()
	if back != nil {
		d.data.remove(back)
		return back.value
	}
	return nil
}
func main() {
	deque := newdeque()
	// 测试 pushfront 和 pushback
	deque.pushback(1)
	deque.pushfront(2)
	deque.pushback(3)
	deque.pushfront(4)
	// 测试 popfront
	fmt.println("popped from front:", deque.popfront()) // 输出: popped from front: 4
	fmt.println("popped from front:", deque.popfront()) // 输出: popped from front: 2
	// 测试 popback
	fmt.println("popped from back:", deque.popback()) // 输出: popped from back: 3
	fmt.println("popped from back:", deque.popback()) // 输出: popped from back: 1
	// 测试空队列的情况
	fmt.println("popped from front on empty deque:", deque.popfront()) // 输出: popped from front on empty deque: <nil>
	fmt.println("popped from back on empty deque:", deque.popback())   // 输出: popped from back on empty deque: <nil>
	// 再次测试 pushfront 和 pushback
	deque.pushfront(5)
	deque.pushback(6)
	// 测试 peekfront 和 peekback
	fmt.println("front element:", deque.popfront()) // 输出: front element: 5
	fmt.println("back element:", deque.popback())   // 输出: back element: 6
}

set

package main
import (
	"fmt"
	"sync"
)
/*
 set: 可以去除重复元素
	- add: 添加元素
	- remove: 删除元素
	- contains: 检查元素是否存在
	- isempty: 判断集合是否为空
	- clear: 清空集合
	- iterator: 返回一个迭代器通道
	...
*/
type set struct {
	mu   sync.rwmutex
	data map[interface{}]bool
}
// newset 创建一个新的集合
func newset() *set {
	return &set{
		data: make(map[interface{}]bool),
	}
}
// add 添加元素到集合
func (s *set) add(value interface{}) {
	s.mu.lock()
	defer s.mu.unlock()
	s.data[value] = true
}
// remove 从集合中删除元素
func (s *set) remove(value interface{}) {
	s.mu.lock()
	defer s.mu.unlock()
	delete(s.data, value)
}
// contains 检查元素是否存在于集合中
func (s *set) contains(value interface{}) bool {
	s.mu.rlock()
	defer s.mu.runlock()
	return s.data[value]
}
// isempty 判断集合是否为空
func (s *set) isempty() bool {
	s.mu.rlock()
	defer s.mu.runlock()
	return len(s.data) == 0
}
// clear 清空集合
func (s *set) clear() {
	s.mu.lock()
	defer s.mu.unlock()
	s.data = make(map[interface{}]bool)
}
// iterator 返回一个迭代器通道
func (s *set) iterator() <-chan interface{} {
	ch := make(chan interface{})
	go func() {
		defer func() {
			if r := recover(); r != nil {
				fmt.println("recovered in iterator:", r)
			}
			close(ch)
		}()
		s.mu.rlock()
		defer s.mu.runlock()
		for k := range s.data {
			ch <- k
		}
	}()
	return ch
}
func main() {
	set := newset()
	// 测试 add 和 contains
	set.add(1)
	set.add(2)
	set.add(3)
	fmt.println("contains 1:", set.contains(1)) // 输出: contains 1: true
	fmt.println("contains 4:", set.contains(4)) // 输出: contains 4: false
	// 测试 remove
	set.remove(2)
	fmt.println("contains 2 after remove:", set.contains(2)) // 输出: contains 2 after remove: false
	// 测试 isempty
	fmt.println("is set empty?", set.isempty()) // 输出: is set empty? false
	// 测试 clear
	set.clear()
	fmt.println("is set empty after clear?", set.isempty()) // 输出: is set empty after clear? true
	// 测试 iterator
	set.add(1)
	set.add(2)
	set.add(3)
	fmt.println("elements in set:")
	for i := range set.iterator() {
		fmt.println(i)
	}
	// 其他测试代码
	data := make([]int, 2, 20)
	data[0] = -1
	fmt.println("length of data:", len(data))   // 输出: length of data: 2
	fmt.println("capacity of data:", cap(data)) // 输出: capacity of data: 20
}

更多的数据结构,比如linkedlist等,大家可以自行下来尝试一下。

3 代码地址

完整代码地址(欢迎大家⭐️):https://github.com/ziyifast/ziyifast-code_instruction/tree/main/go-demo/go-data-structure

到此这篇关于go实现list、set、stack、deque等数据结构的文章就介绍到这了,更多相关go list、set、stack、deque数据结构内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

go语言make初始化的实现

02-14

Go语言中的map扩容机制

02-14

go中的参数传递是值传递还是引用传递的实现

02-14

golang debug调试的实现

02-14

Go语言如何获取goroutine的id

02-14

Gin+Gorm实现增删改查的示例代码

02-14

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论