设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间06 现在时间06 缓存数据 只有内心祥和,才不会被生活所左右,所以一定要从容淡泊。

只有内心祥和,才不会被生活所左右,所以一定要从容淡泊。

查看: 2808|回复: 4

golang实现循环队列的示例代码

[复制链接]

  离线 

TA的专栏

  • 打卡等级:即来则安
  • 打卡总天数:15
  • 打卡月天数:0
  • 打卡总奖励:267
  • 最近打卡:2023-08-27 04:17:41
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
41
主题
33
精华
0
金钱
389
积分
84
注册时间
2023-8-12
最后登录
2025-5-31

发表于 2024-7-4 09:21:09 | 显示全部楼层 |阅读模式
目录


  • 概要说明
  • 队列常见问题:假溢出
  • 循环队列的实现
  • 循环队列的应用

概要说明

循环队列是一种使用固定大小的数组来实现队列的数据结构,它通过循环的方式使用数组空间,具有以下好处:

  • 空间高效:循环队列避免了使用链表实现队列时可能存在的额外空间开销,因为链表的每个节点都需要额外的存储空间来保存指向下一个节点的指针。
  • 时间效率:在循环队列中,入队和出队操作通常可以在常数时间内完成,即O(1)时间复杂度。这是因为不需要移动队列中的其他元素。
  • 减少内存分配:由于循环队列使用固定大小的数组,它避免了动态分配内存的需要,这在某些情况下可以减少内存分配和回收的开销。
  • 避免内存碎片:固定大小的数组可以减少内存碎片的产生,因为不需要为每个元素单独分配内存。
  • 实现简单:循环队列的实现相对简单,只需要管理两个指针(或索引)来跟踪队列的头部和尾部。
  • 动态使用:循环队列可以动态地使用数组空间,即使队列满了,也可以通过循环的方式继续使用数组的未使用部分。
  • 适用于固定大小数据集:当数据集的大小已知且固定时,循环队列可以非常高效地使用内存和处理数据。
  • 减少错误:由于循环队列的实现相对简单,它减少了因复杂实现带来的潜在错误。
避免假溢出是循环队列设计中的一个重要问题。假溢出通常发生在循环队列的头部和尾部索引在数组中相遇时,即使数组中还有空间可以存放新元素。出现假溢出的原因,从根本上来说,是因为循环队列的容量被错误地判断为已满。

队列常见问题:假溢出

以下是几种避免假溢出的策略:

  • 使用标志位:在循环队列结构中添加一个标志位来区分队列是真正的满还是假溢出。当队列满时,设置这个标志位;当队列空时,清除这个标志位。
  • 使用计数器:维护一个计数器来记录队列中实际的元素数量。入队时增加计数器,出队时减少计数器。即使头部和尾部索引相遇,计数器也能正确反映队列的状态。
  • 双重索引:使用两个索引来分别表示队列的头部和尾部,同时使用一个布尔值来区分队列是满还是空。当队列满时,尾部索引会等于头部索引,但布尔值会标记队列为满。
  • 重新计算索引:在检查队列是否满或空时,不要仅仅依赖于头部和尾部索引的比较,而是重新计算它们在数组中的相对位置。
  • 使用额外的数组空间:在数组中预留一个额外的空间,这样即使头部和尾部索引相遇,也不会立即认为队列满了。这种方式牺牲了一点空间效率,但可以简化逻辑。
  • 使用环形缓冲区:在某些编程语言的库中,环形缓冲区(ring buffer)是一种特殊的循环队列,它通过使用上述一些策略来避免假溢出。
  • 动态扩容:虽然这并不直接解决假溢出问题,但通过动态扩容,可以在队列达到容量上限时创建一个新的更大的数组,并将旧数组中的元素复制到新数组中。
  • 使用哨兵元素:在数组的末尾添加一个哨兵元素,这样即使头部和尾部索引相遇,哨兵元素也不会被误认为是队列中的有效元素。
  • 逻辑分离:在逻辑上将满和空的状态与头部和尾部索引的相遇分离,通过额外的逻辑来确定队列的真实状态。
  • 使用状态位图:使用位图来表示数组中哪些位置是被占用的,这样可以通过位图的状态来判断队列是否满或空。
避免假溢出的关键在于正确地维护队列的状态信息,确保在任何时候都能准确地判断队列是否真正满了或者空了。在设计循环队列时,应该根据具体的应用场景和性能要求来选择最合适的策略。
在Go语言中实现循环队列,我们需要定义一个循环队列的数据结构,并实现其基本操作,包括初始化、入队(Push)、出队(Pop)、获取队列长度等。下面是一个简单的循环队列实现示例:

循环队列的实现
  1. package QUEUE

  2. import (
  3.         "strings"
  4.         "sync"
  5. )

  6. type CycleQueue struct {
  7.         data  []interface{} //存储空间
  8.         front int           //前指针,前指针负责弹出数据移动
  9.         rear  int           //尾指针,后指针负责添加数据移动
  10.         cap   int           //设置切片最大容量
  11.         mu    sync.RWMutex          // 添加互斥锁
  12. }

  13. func NewCycleQueue(cap int) *CycleQueue {
  14.         return &CycleQueue{
  15.                 data:  make([]interface{}, cap),
  16.                 cap:   cap,
  17.                 front: 0,
  18.                 rear:  0,
  19.         }
  20. }

  21. // 入队操作
  22. // 判断队列是否队满,队满则不允许添加数据
  23. func (q *CycleQueue) Push(data interface{}) bool {
  24.         q.mu.Lock()
  25.         defer q.mu.Unlock() // 确保在函数退出时释放锁

  26.         //check queue is full
  27.         if q.QueueLength() == q.cap { //队列已满时,不执行入队操作
  28.                 Log.Error("push err queue is full")
  29.                 return false
  30.         }
  31.         q.data[q.rear] = data         //将元素放入队列尾部
  32.         q.rear = (q.rear + 1) % q.cap //尾部元素指向下一个空间位置,取模运算保证了索引不越界(余数一定小于除数)
  33.         return true
  34. }

  35. // 出队操作
  36. // 需要考虑: 队队为空没有数据返回了
  37. func (q *CycleQueue) Pop() interface{} {
  38.         q.mu.Lock()
  39.         defer q.mu.Unlock()

  40.         if q.rear == q.front {
  41.                 return nil
  42.         }

  43.         data := q.data[q.front]
  44.         q.data[q.front] = nil // 使用nil来避免内存泄露
  45.         q.front = (q.front + 1) % q.cap
  46.         return data
  47. }

  48. // 循环队列长度计算,考虑哨兵空间
  49. func (q *CycleQueue) QueueLength() int {
  50.         if q.rear >= q.front {
  51.                 return q.rear - q.front
  52.         }
  53.         return q.cap - q.front + q.rear
  54. }

  55. func (q *CycleQueue) FindDataByRequestId(requestId string) interface{} {
  56.         q.mu.Lock()
  57.         defer q.mu.Unlock()

  58.         // 计算队列中的有效元素数量
  59.         length := q.QueueLength()

  60.         // 从front指针开始遍历队列
  61.         index := q.front
  62.         for i := 0; i < length; i++ {
  63.                 // 检查当前元素是否包含requestId
  64.                 if data, ok := q.data[index].(string); ok && strings.Contains(data, requestId) {
  65.                         // 找到元素后,从队列中移除
  66.                         q.RemoveAtIndex(index)
  67.                         return data
  68.                 }
  69.                 // 移动到下一个元素
  70.                 index = (index + 1) % q.cap
  71.         }
  72.         // 如果没有找到,返回nil
  73.         return nil
  74. }

  75. // 新增RemoveAtIndex方法,用于在循环队列中移除指定索引的元素
  76. func (q *CycleQueue) RemoveAtIndex(index int) {
  77.         if index < 0 || index >= q.cap {
  78.                 return // 索引越界检查
  79.         }

  80.         // 将index位置的元素复制到最后一个元素的位置
  81.         copy(q.data[index:], q.data[index+1:q.rear])

  82.         // 更新队列的front和rear指针
  83.         if index == q.rear { // 如果移除的是最后一个元素
  84.                 q.rear = index // rear指针向前移动
  85.         } else if index < q.rear { // 如果移除的是中间的元素
  86.                 q.rear-- // rear指针向前移动
  87.         }

  88.         // 如果移除的是front指针前的元素
  89.         if index < q.front {
  90.                 q.front = index // front指针向后移动
  91.         }
  92. }
复制代码
循环队列的应用
  1. package server

  2. import (
  3.     "encoding/json"
  4.     "strconv"
  5.     "time"
  6. )

  7. //队列通道
  8. type Channel struct {
  9.     queue                  *MeetGo.CycleQueue
  10. }

  11. //队列参数项
  12. type QueueItem struct {
  13.     event    string
  14.     msg      map[string]interface{}
  15.     response *chan Response
  16. }

  17. //返回参数
  18. type Response struct {
  19.         err    interface{}
  20.         result map[string]interface{}
  21. }

  22. var globalChannel *Channel


  23. //创建队列通道
  24. func NewChannel() {
  25.     channel.queue = QUEUE.NewCycleQueue(1000)
  26.     go channel.handle()
  27.     return
  28. }

  29. //处理队列数据
  30. func (channel *Channel) handle() {
  31.     for {
  32.         item := channel.queue.Pop()

  33.         if item == nil {
  34.             time.Sleep(40 * time.Millisecond)
  35.             continue
  36.         }
  37.         channel.process(item)
  38.         time.Sleep(1 * time.Millisecond)
  39.     }
  40. }

  41. func (channel *Channel) process(inter interface{}) {
  42.     item := inter.(QueueItem)
  43. }

  44. func (channel *Channel) PushSignal(item QueueItem) {
  45.     Channel.queue.Push(item)
  46. }

  47. func (channel *Channel) onRequest(event string, msg map[string]interface{}) chan Response {
  48.         response := make(chan Response, 1)
  49.         item := QueueItem{
  50.                 event,
  51.                 msg,
  52.                 &response,
  53.         }
  54.         channel.PushSignal(item)
  55.         return response

  56. }

  57. func main(){
  58.     globalChannel = NewChannel()
  59.     globalChannel.onRequset()
  60.     println(response)
  61. }
复制代码
到此这篇关于golang实现循环队列的示例代码的文章就介绍到这了,更多相关golang 循环队列内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
20
积分
20
注册时间
2022-12-27
最后登录
2022-12-27

发表于 2024-12-16 03:32:55 | 显示全部楼层
感谢楼主,顶。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
19
积分
18
注册时间
2022-12-25
最后登录
2022-12-25

发表于 2024-12-20 07:12:07 | 显示全部楼层
顶顶更健康!!!
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
15
积分
10
注册时间
2022-12-29
最后登录
2022-12-29

发表于 2025-2-14 13:38:59 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
19
积分
18
注册时间
2022-12-27
最后登录
2022-12-27

发表于 2025-3-29 04:13:31 | 显示全部楼层
路过,支持一下
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼
4楼
5楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表