golang 基于数组、切片、链表实现队列

数组

package mainimport ("errors""fmt"
)func main() {// 创建一个简单队列// 如果head == tail 队列空// 如果tail == len(array) - 1// 整体做迁移 如果head == 0 队列满stack1 := createQueue[int]()err := stack1.push(1)// 处理错误 后面的就不处理了if err != nil {return}stack1.push(2)stack1.push(3)stack1.push(4)stack1.push(5)popData1 := stack1.pop()fmt.Printf("出队列元素%+v\n", *popData1)popData2 := stack1.pop()fmt.Printf("出队列元素%+v\n", *popData2)stack1.push(6)stack1.push(7)stack1.push(8)stack1.push(9)stack1.pop()err = stack1.push(10)// 处理错误 后面的就不处理了if err != nil {fmt.Printf(err.Error() + "\n")}stack1.forEach()
}// 默认小一点的空间 size 为5 数组空间=size+1
type queue[T int | string | map[string]string] struct {data [6]Thead inttail int
}func createQueue[T int | string | map[string]string]() *queue[T] {return &queue[T]{data: [6]T{},}
}func (s *queue[T]) push(item T) error {// len(s.data) - 1 这里固定为5if len(s.data)-1 == s.tail {if s.head == 0 {return errors.New("队列满!")}// 做迁移currentTail := s.tail - s.head// 队列整体往前移动for i := 0; i < currentTail; i++ {s.data[i] = s.data[i+s.head]}s.head = 0s.tail = currentTail}s.data[s.tail] = items.tail++return nil
}// 数组头部出队列
func (s *queue[T]) pop() *T {// 队列为空if s.head == s.tail {return nil}res := &s.data[s.head]s.head++return res
}func (s *queue[T]) forEach() {fmt.Printf("遍历队列:\n")for i := s.head; i < s.tail; i++ {fmt.Printf("当前队列元素%+v\n", s.data[i])}
}

切片

package mainimport ("fmt"
)func main() {// 创建一个简单队列// 如果head == tail 队列空// 如果tail == len(array) - 1// 整体做迁移 如果head == 0 队列满stack1 := createQueue[int](5)err := stack1.push(1)// 处理错误 后面的就不处理了if err != nil {return}stack1.push(2)fmt.Printf("队列容量%+v\n", cap(stack1.data))stack1.push(3)stack1.push(4)stack1.push(5)popData1 := stack1.pop()fmt.Printf("出队列元素%+v\n", *popData1)popData2 := stack1.pop()fmt.Printf("出队列元素%+v\n", *popData2)stack1.forEach()stack1.push(6)stack1.push(7)stack1.push(8)stack1.push(9)// 看是否自动扩容fmt.Printf("队列容量%+v\n", cap(stack1.data))popData3 := stack1.pop()fmt.Printf("出队列元素%+v\n", *popData3)err = stack1.push(10)// 处理错误 后面的就不处理了if err != nil {fmt.Printf(err.Error() + "\n")}stack1.forEach()
}type queue[T int | string | map[string]string] struct {data []T
}func createQueue[T int | string | map[string]string](len int) *queue[T] {return &queue[T]{data: make([]T, 0, len),}
}func (s *queue[T]) push(item T) error {s.data = append(s.data, item)return nil
}// 数组头部出队列
func (s *queue[T]) pop() *T {// 队列为空if len(s.data) == 0 {return nil}res := &s.data[0]s.data = s.data[1:]return res
}func (s *queue[T]) forEach() {fmt.Printf("遍历队列:\n")for _, datum := range s.data {fmt.Printf("当前队列元素%+v\n", datum)}}

链表

package mainimport ("errors""fmt"
)func main() {// 双向循环链表实现队列linkedObj := getLinked[int](5)err := linkedObj.headPush(6)if err != nil {fmt.Printf(err.Error())}err = linkedObj.headPush(5)if err != nil {fmt.Printf(err.Error())}err = linkedObj.headPush(4)if err != nil {fmt.Printf(err.Error())}err = linkedObj.headPush(3)if err != nil {fmt.Printf(err.Error())}err = linkedObj.headPush(2)if err != nil {fmt.Printf(err.Error())}err = linkedObj.headPush(1)if err != nil {fmt.Printf(err.Error())}err = linkedObj.headPush(0)if err != nil {fmt.Printf(err.Error())}//fmt.Printf("当前节点: %+v\n", linkedObj)//fmt.Printf("当前节点: %+v\n", linkedObj.head.next.data)item := linkedObj.tailPop()fmt.Printf("弹出节点: %+v\n", *item)item = linkedObj.tailPop()fmt.Printf("弹出节点: %+v\n", *item)linkedObj.headForeach()err = linkedObj.headPush(-1)if err != nil {fmt.Printf(err.Error())}linkedObj.tailForeach()
}type linked[T int | string | map[string]string] struct {head   *node[T]length intlimit  int
}type node[T int | string | map[string]string] struct {data *Tnext *node[T]prev *node[T]
}func getLinked[T int | string | map[string]string](limit int) *linked[T] {return &linked[T]{head:   nil,length: 0,limit:  limit,}
}func createNode[T int | string | map[string]string](data T) *node[T] {return &node[T]{data: &data,next: nil,prev: nil,}
}// 从头部插入
func (l *linked[T]) headPush(data T) error {if l.length >= l.limit {return errors.New("当前队满\n")}newNode := createNode(data)if l.head == nil {l.head = newNodel.length++newNode.next = newNodenewNode.prev = newNodereturn nil}currentNode := l.head// 头结点位置headNodePos := l.headl.head = newNodenewNode.next = currentNodecurrentNode.prev = newNode// 找尾结点for {if currentNode.next == headNodePos {break}currentNode = currentNode.next}if l.length >= l.limit {currentNode.prev.next = newNodenewNode.prev = currentNode.prev} else {currentNode.next = newNodenewNode.prev = currentNodel.length++}return nil
}// 尾部弹出
func (l *linked[T]) tailPop() *T {if l.head == nil {return nil}currentNode := l.head// 头结点位置headNodePos := l.head// 找尾结点for {if currentNode.next == headNodePos {break}currentNode = currentNode.next}// 将尾结点的前一个节点作为尾节点currentNode.prev.next = headNodePosheadNodePos.prev = currentNode.prevl.length--return currentNode.data
}// 从头部遍历
func (l *linked[T]) headForeach() {headNode := l.headheadNodPos := headNodefmt.Printf("从头结点遍历:\n")for {fmt.Printf("当前节点: %+v\n", *headNode.data)if headNode.next == headNodPos {break}headNode = headNode.next}
}// 从尾部遍历
func (l *linked[T]) tailForeach() {endNode := l.headendNodePos := endNodefmt.Printf("从尾结点遍历:\n")for {fmt.Printf("当前节点: %+v\n", *endNode.prev.data)if endNode.prev == endNodePos {break}endNode = endNode.prev}
}

链表加锁实现线程安全

package mainimport ("errors""fmt""sync"
)func main() {// 双向循环链表实现队列 加锁实现并发安全linkedObj := getLinked[int](5)syncGroup := sync.WaitGroup{}syncGroup.Add(1050)for i := 0; i < 1000; i++ {i := igo func() {err := linkedObj.headPush(i)if err != nil {fmt.Printf(err.Error())}syncGroup.Done()}()}for i := 0; i < 50; i++ {go func() {data := linkedObj.tailPop()if data != nil {fmt.Println(*data)}syncGroup.Done()}()}//fmt.Printf("当前节点: %+v\n", linkedObj)//fmt.Printf("当前节点: %+v\n", linkedObj.head.next.data)syncGroup.Wait()linkedObj.headForeach()
}type linked[T int | string | map[string]string] struct {head     *node[T]length   intlimit    intheadLock sync.MutextailLock sync.Mutex
}type node[T int | string | map[string]string] struct {data *Tnext *node[T]prev *node[T]
}func getLinked[T int | string | map[string]string](limit int) *linked[T] {return &linked[T]{head:     nil,length:   0,limit:    limit,headLock: sync.Mutex{},tailLock: sync.Mutex{},}
}func createNode[T int | string | map[string]string](data T) *node[T] {return &node[T]{data: &data,next: nil,prev: nil,}
}// 从头部插入
func (l *linked[T]) headPush(data T) error {l.headLock.Lock()defer l.headLock.Unlock()if l.length >= l.limit {return errors.New("当前队满\n")}newNode := createNode(data)if l.head == nil {l.head = newNodel.length++newNode.next = newNodenewNode.prev = newNodereturn nil}currentNode := l.head// 头结点位置headNodePos := l.headl.head = newNodenewNode.next = currentNodecurrentNode.prev = newNode// 找尾结点for {if currentNode.next == headNodePos {break}currentNode = currentNode.next}if l.length >= l.limit {currentNode.prev.next = newNodenewNode.prev = currentNode.prev} else {currentNode.next = newNodenewNode.prev = currentNodel.length++}return nil
}// 尾部弹出
func (l *linked[T]) tailPop() *T {l.tailLock.Lock()defer l.tailLock.Unlock()if l.head == nil {return nil}currentNode := l.head// 头结点位置headNodePos := l.head// 找尾结点for {if currentNode.next == headNodePos {break}currentNode = currentNode.next}//currentNode.prev.next = headNodePos//headNodePos.prev = currentNode.previf currentNode == headNodePos {// The list has only one elementl.head = nil} else {currentNode.prev.next = headNodePosheadNodePos.prev = currentNode.prev}l.length--return currentNode.data
}// 从头部遍历
func (l *linked[T]) headForeach() {if l.head == nil {fmt.Printf("队空:\n")return}headNode := l.headheadNodPos := headNodefmt.Printf("从头结点遍历:\n")for {fmt.Printf("当前节点: %+v\n", *headNode.data)if headNode.next == headNodPos {break}headNode = headNode.next}
}// 从尾部遍历
func (l *linked[T]) tailForeach() {if l.head == nil {fmt.Printf("队空:\n")return}endNode := l.headendNodePos := endNodefmt.Printf("从尾结点遍历:\n")for {fmt.Printf("当前节点: %+v\n", *endNode.prev.data)if endNode.prev == endNodePos {break}endNode = endNode.prev}
}

cas 实现 无锁队列

// todo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/219507.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ajax原理以及优缺点

Ajax原理 1.Ajax的原理简单来说是在用户和服务器之间加了—个中间层(AJAX引擎)&#xff0c;通过XmlHttpRequest对象来向服务器发异步请求&#xff0c; 2.从服务器获得数据&#xff0c;然后用javascript来操作DOM而更新页面。使用户操作与服务器响应异步化。 3.这其中最关键的一…

Java----冒泡排序、选择排序、插入排序、快速排序、堆排序

int[] arr {4, 2, 7, 1, 5, 9, 3, 6, 8}; 冒泡排序 for(int i 0; i < arr.length-1; i) //外循环是控制排序的次数n-1, 每次循环结束确定一个最大值{for(int j 0; j < arr.length - 1 - i; j) // 内循环是第i次循环中比较的次数n-i{if(arr[j] > arr[j1]){//前面一…

LeetCode-23. 合并 K 个升序链表

问题分析 先建立一个小顶堆将每一路的最小元素都加入小顶堆&#xff0c;此时堆顶元素就是全局的最小值将堆顶元素弹出。若堆顶元素所在的数组不为空&#xff0c;则将下一元素加入堆中重复2、3操作&#xff0c;直到所有数据都读取完毕将堆内元素按顺序读出&#xff0c;并清空堆…

双系统安装显卡驱动

安装步骤 更新系统: 在安装任何新软件之前&#xff0c;最好先更新系统&#xff0c;以确保所有依赖都是最新的。打开终端&#xff08;Terminal&#xff09;并运行以下命令&#xff1a; sudo apt update sudo apt upgrade关闭Nouveau驱动: Nouveau是Nvidia显卡的开源驱动&#xf…

Linux系统使用ESP8266开发板(CP2102)

连接ESP8266开发板到电脑 虚拟机选择开发板硬件连接 查看USB连接情况: lsusb 授权USB接口访问 成功连接 编译项目 上传到开发板 成功提供WIFI热点服务

跳跃游戏 + 45. 跳跃游戏 II

给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输…

动态SQL学习及使用场景(简略)

假设我们有一个商品表&#xff0c;包含id、name、price和category四个字段。现在需要实现修改商品价格的功能&#xff0c;我们可以使用动态SQL实现。 首先&#xff0c;我们需要构造一个SQL语句&#xff0c;根据用户提供的参数来动态生成&#xff0c;具体实现如下&#xff1a; …

三、Shell 环境

一、Linux 系统分类 在 Linux 中&#xff0c;常见的 Shell 有以下几种&#xff1a; Bourne Shell&#xff08;sh&#xff09;&#xff1a;最早的 Shell&#xff0c;由 Stephen Bourne 开发。它是大多数其他 Shell 的基础。Bourne Again Shell&#xff08;bash&#xff09;&am…

Tomcat指定jdk启动

要在Tomcat中指定使用特定的JDK启动&#xff0c;可以按照以下步骤进行操作&#xff1a; 确保你已经安装了所需的JDK&#xff0c;并且知道其安装路径。 打开Tomcat的安装目录&#xff0c;在bin目录下找到catalina.bat&#xff08;Windows&#xff09;或catalina.sh&#xff08;…

thinkphp6入门(13)-- 一对多关联模型

定义一对一关联&#xff0c;例如&#xff0c;一个用户都有多个工作经历。 一、两表 1.用户表:user 2.工作经验表&#xff1a;work_experience user表的id关联work_experience表的user_id。 注意看&#xff0c;user_id1的有2条工作经验 二、数据模型 主表模型&#xff1a;…

2023.12.6 关于flask中的route、render_template、redirect的关系问题

2023.12.6 关于flask中的route、render_template、redirect的关系问题 之前对于route、render_template、redirect三者的关系还有一些模糊&#xff0c;测试了一个案例后就比较清晰了&#xff0c;简单来说就是路径、模板和重定向&#xff0c;三者相对独立&#xff0c;只是一般命…

我的创作纪念日-第四年

机缘 不知不觉&#xff0c;CSDN 写博客已经四年了&#xff0c;也伴随了我读研读博的绝大多数时间。最多的时候&#xff0c;还是想记录下自己所走过的路程吧&#xff0c;然后留给后人一点经验借鉴。 实战项目中的经验分享   应该只分享过一篇博文&#xff1a;基于Jetson nan…

如何在 1 天内将网站打造为手机app

为您的网站提供移动应用程序的重要性怎么强调都不为过。随着用户越来越依赖智能手机和平板电脑进行在线活动&#xff0c;将您的网站转变为移动手机app可以显着增强用户体验、提高参与度并扩大您的在线影响力。在这篇博客中&#xff0c;我们将探讨如何快速有效地将网站制作成移动…

【Let‘s Encrypt SSL】使用 acme.sh 给 Nginx 安装 Let’s Encrypt 提供的免费 SSL 证书

安装acme.sh 安装 acme.sh 并设置邮箱用来接受重要通知&#xff0c;如证书快过期未更新通知 curl https://get.acme.sh | sh -s emailmyexample.com执行命令后几秒就安装好了&#xff0c;如果半天没有反应请 CtrlC 后重新执行命令。acme.sh 安装在 ~/.acme.sh 目录下&#xf…

windows 10多用户同时远程登陆配置【笔记】

系统环境&多用户访问情况&#xff1a; 1、【win】【R】键入【gpedit.msc】 2、依次选择【计算机配置】→ 【管理模板】 → 【Windows组件】 → 【远程桌面服务】 → 【远程桌面会话主机】 →【连接】 2.1、右键 【允许用户通过使用远程桌面服务进行远程连接】 编辑 …

C++初阶-vector类的模拟实现

vector类的模拟实现 一、经典的vector类问题1.1 前期准备 二、vector的默认成员函数2.1 构造函数2.1.1 无参构造2.1.2 构造具有n个对象值为val的容器&#xff08;数据类型为模板类型T&#xff09;2.1.3 拷贝构造 2.2 swap&#xff08;operator需要用&#xff09;2.3 复制重载op…

volatile 系列之指令重排序导致的可见性问题

什么是指令重排序呢?为了更加直观地理解&#xff0c;老司机还是通过一个案例来说明 public class MemoryReorderingExample {private static int x0,y0:private static int a0,b0;public static void main(String[] args) throws InterruptedException {int i0;while(true){…

排序算法之一:直接插入排序

1.基本思想 直接插入排序是一种简单的插入排序法&#xff0c;其基本思想是&#xff1a; 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&#xff0c;得到一个新的有序序列 实际中我们玩扑克牌时&#xff0c;就用…

【UML】组件图中的供接口和需接口与面向对象中的接口

UML&#xff08;统一建模语言&#xff09;组件图中的“供接口”&#xff08;Provided Interface&#xff09;和“需接口”&#xff08;Required Interface&#xff09;与面向对象编程中的接口概念有关联&#xff0c;但它们在应用上有所区别。 下面解释两者的关系&#xff1a; …

NCNN 源码学习【一】:学习顺序

最近一段时间一直在做模型部署的工作&#xff0c;主要是利用NCNN部署到安卓端&#xff0c;跟着网上的博客和开源项目&#xff0c;做了很多工作&#xff0c;也学习到很多东西&#xff0c;但是对于NCNN的源码&#xff0c;并没有仔细的研究过&#xff0c;对我来说&#xff0c;仿佛…