现在的位置: 首页 > 综合 > 正文

重提循环队列

2013年08月07日 ⁄ 综合 ⁄ 共 1931字 ⁄ 字号 评论关闭

之前写过一篇博客介绍队列:http://blog.csdn.net/thefutureisour/article/details/7835273

后来发现这个这个队列是有问题的:

bool enQueue(Queue *q,ElemType e)
{
	//如果队列已满,重新分配内存
	if(q->rear == q->Qsize-1)
	{
		q->data = (ElemType*)realloc(q->data,2*q->Qsize*sizeof(ElemType));
		if(q->data == NULL)
			return false;
		else
			q->Qsize *= 2;
	}
	//先赋值,然后队尾循环加1
	q->data[q->rear] = e;
	q->rear = (q->rear+1)%q->Qsize;
	return true;

}

这个判断队列满的办法明显是错误的,因为有可能在多次出队、入队操作以后,data[1]代表rear,data[0]代表front,此时队列已经满了应该重新分配内存,而这个程序并没有做出正确的判断。然后我对作了修改,改成了

if(Qlength(q) == q->Qsize-1)

这个代码看似正确,但是如果进行下面的测试,就会发现问题了:

	int a = 100;
	Queue myQueue;
	
	initQueue(&myQueue,4);
	//先把队列充满
	for(int i = 0 ; i < 3 ;++i)
		enQueue(&myQueue,i);
	printQueue(&myQueue);
	
	deQueue(&myQueue,&a);	
	enQueue(&myQueue,3);
	printQueue(&myQueue);

	deQueue(&myQueue,&a);	
	enQueue(&myQueue,4);
	printQueue(&myQueue);

	enQueue(&myQueue,5);
	printQueue(&myQueue);

	destroyQueue(&myQueue);

 

最后一次入队5以后,打印为空,通过单步调试,我发现问题因为此时Qlength的返回值为0.我才恍然大悟,问题的严重性:

当data[0]为rear而data[1]为front时,虽然这时候队列实际已经满了,我也重新分配了内存,但是rear和front下标却没有修改,进而导致重新分配的后的数组是类似于下面的结构:

data      0         1         2         3         4         5         6         7

             rear     front    数据   数据    {      新分配的空间      }

首先:enqueue以后rear会++,所以此时会出现Qlength为0,其次这已经完全不是循环队列的结构了,rear的前一个数据是没有初始化的内存。

怎么解决这个问题呢?

我也没有特别高明的办法,只能重新分配的时候新建一个数组,数组中的元素按照队列从头至尾的顺序保存,然后重新分配内存之后,把新内存的前Qsize-1个元素用新建的数组初始化,然后把rear置为Qsize,新来的元素放到rear的位置,然后rear再自增。这样就搞定了:

bool enQueue(Queue *q,ElemType e)
{
	//如果队列已满,重新分配内存
	if(q->Qsize-1 == Qlength(q))
	{
		//先把原来的按顺序记录在tmp中
		ElemType* tmp = (ElemType*)malloc(sizeof(ElemType) * q->Qsize);
		for(int i = 0; i< q->Qsize-1;++i)	
		{
			tmp[i] = q->data[(q->front+i+q->Qsize)%q->Qsize];
		}
		//重新分配内存
		q->data = (ElemType*)realloc(q->data,2*q->Qsize*sizeof(ElemType));
		if(q->data == NULL)
			return false;
		//用tmp初始化q->data
		for(int i = 0; i< q->Qsize-1;++i)
		{
			q->data[i] = tmp[i];
		}

		//重新设定front、rear标记
		q->front= 0;
		q->rear = q->Qsize;
		//新来的元素放入队尾
		q->data[q->Qsize] = e;
		//队尾指针自增
		q->rear++;
		//容量翻倍
		q->Qsize *= 2;
		free(tmp);
	}
	else
	{
		//先赋值,然后队尾循环加1
		q->data[q->rear] = e;
		q->rear = (q->rear+1)%q->Qsize;
	}
	return true;

}

 

由于时间匆忙,可能会有小的纰漏,但是大方向上应该是没有问题的。

 

抱歉!评论已关闭.