go语言循环队列的实现
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言循环队列的实现相关的知识,希望对你有一定的参考价值。
参考技术A 队列的概念在 顺序队列 中,而使用循环队列的目的主要是规避假溢出造成的空间浪费,在使用循环队列处理假溢出时,主要有三种解决方案本文提供后两种解决方案。
顺序队和循环队列是一种特殊的线性表,与顺序栈类似,都是使用一组地址连续的存储单元依次存放自队头到队尾的数据元素,同时附设队头(front)和队尾(rear)两个指针,但我们要明白一点,这个指针并不是指针变量,而是用来表示数组当中元素下标的位置。
本文使用切片来完成的循环队列,由于一开始使用三个参数的make关键字创建切片,在输出的结果中不包含nil值(看起来很舒服),而且在验证的过程中发现使用append()函数时切片内置的cap会发生变化,在消除了种种障碍后得到了一个四不像的循环队列,即设置的指针是顺序队列的指针,但实际上进行的操作是顺序队列的操作。最后是对make()函数和append()函数的一些使用体验和小结,队列的应用放在链队好了。
官方描述(片段)
即切片是一个抽象层,底层是对数组的引用。
当我们使用
构建出来的切片的每个位置的值都被赋为interface类型的初始值nil,但是nil值也是有大小的。
而使用
来进行初始化时,虽然生成的切片中不包含nil值,但是无法通过设置的指针变量来完成入队和出队的操作,只能使用append()函数来进行操作
在go语言中,切片是一片连续的内存空间加上长度与容量的标识,比数组更为常用。使用 append 关键字向切片中追加元素也是常见的切片操作
正是基于此,在使用go语言完成循环队列时,首先想到的就是使用make(type, len, cap)关键字方式完成切片初始化,然后使用append()函数来操作该切片,但这一方式出现了很多问题。在使用append()函数时,切片的cap可能会发生变化,用不好就会发生扩容或收缩。最终造成的结果是一个四不像的结果,入队和出队操作变得与指针变量无关,失去了作为循环队列的意义,用在顺序队列还算合适。
参考博客:
Go语言中的Nil
Golang之nil
Go 语言设计与实现
数据结构c语言如何实现循环队列
前言
在看接下来的文章之前大家知道必须知道两个问题。
问题一: ‘为什么静态队列都是循环队列?’
答:因为静态队列是基于数组实现的,若不使用循环队列,会导致已经删除的元素所使用的空间无法继续使用,造成空间浪费。
问题二:‘rear和 front分别表示什么?’
答:规定front指向第一个元素的位置,rear指向最后一个元素的下一个位置。
一、队列的初始化
思路分析
pBase指向队列的首元素,此数组长度为8
void init(QUEUE *pQ) //初始化
{
pQ->pBase=(int*)malloc(sizeof(int)*8 );
pQ->front=0;
pQ->rear=0;
}
二、判满及入队
1.判满
思路分析
一般判满采用两种方法
1.多增加一个标识参数,用于表示元素的个数。
2.少放一个元素(例如此处我的数组长度为8,当我数组中含有7个元素的时候我的数组就满了) 此时的判定条件为(rear+1)%数组长度=front是队列为满。
此处我采用的第二种方法,也推荐大家使用第二种方法,因为第一种方法需要多维护一个参数。
int full_queue(QUEUE *pQ) //判断队列是否满
{
if((pQ->rear+1)%8==pQ->front)
{
return 1;
}
else
{
return 0;
}
}
2.入队
思路分析
先使用判满函数判断队列是否为满,若不是,则把新元素的值赋给rear所指的区域,rear向前移一位
rear=(rear+1)%数组长度
int en_queue(QUEUE *pQ, int val)//入队
{
if(full_queue(pQ))
{
return 0;
}
else
{
pQ->pBase[pQ->rear]=val;
pQ->rear=(pQ->rear+1)%8;
return 1;
}
}
三、判空及出队
1.判空
思路分析
若rear=front则队列为空。
int empty_queue(QUEUE * pQ) //判空
{
if(pQ->front==pQ->rear)
{
return 1;
}
else
{
return 0;
}
}
2.出队
思路分析
先使用判空函数判断队列是否为空,若不是则向前移一位
front=(front+1)%数组长度
int de_queue (QUEUE *pQ,int *pVal)//出队
{
if(empty_queue(pQ))
{
return 0;
}
else
{
*pVal=pQ->pBase[pQ->front];
pQ->front=(pQ->front+1 )%8;
return 1;
}
}
四、队列的遍历输出
思路分析
因为遍历是从头部输出所以先把front的值赋给一个参数,当参数等于rear时停止输出。
void traverse_(QUEUE *pQ) //遍历
{
int i= pQ->front;
while(i!=pQ->rear)
{
printf("%d",pQ->pBase[i] );
i=(i+1)%8;
}
}
五、主函数
int main()
{ int val;
QUEUE Q;
init(&Q);
en_queue(&Q,1); //入队
en_queue(&Q,2);
en_queue(&Q,3);
en_queue(&Q,4);
en_queue(&Q,5);
en_queue(&Q,8);
en_queue(&Q,7);
//de_queue(&Q,&val);
traverse_(&Q); //入队后第一次遍历
printf("\\n");
if( de_queue(&Q,&val)) //出队
{
printf("出队成功!\\n",val);
}
else
{
printf("出队失败!\\n") ;
}
traverse_(&Q); //出队后再次遍历
}
以上是关于go语言循环队列的实现的主要内容,如果未能解决你的问题,请参考以下文章