在循环队列的扩容/缩容方法中,改变for循环的问题

来源:3-7 循环队列的实现

慕的地9541928

2018-05-29

老师,我是一名计算机语言的初学者,一些问题可能对于其他人而言比较简单,但我不容易理解,希望老师耐心解答;
1、我在resize方法中,改变了原有的for循环,采用toString方法中的循环语句,发现在缩容时会产生一个问
题,就是取出的元素不是front指向的元素,而是tile端的元素;于是我将front=0和tile=size注释掉后,这个
问题就解决了,但在扩容时,又产生了新的问题,就是扩容后,原有的值全变为空值了。这是什么原因呢?
2、在原有的for循环中如果不维护front以及tile的值,为什么也会出错呢?
3、我改写后的代码如下:
private void resize(int newCapacity){
		E[] newData = (E[])new Object[newCapacity +1];
		
//		for(int i= 0;i<size;i++){
//			newData[i] = data[(front+i)%data.length];
//		}
		
		for (int i = front; i != tile; i=(i+1)%data.length){
			newData[i] = data[i];
		}
		
		data = newData;
//		front =0;
//		tile = size;
	}


写回答

1回答

liuyubobobo

2018-05-30

你所写的代码(16-18行),其实无论是扩容,还是缩容,都可能产生问题。只是在缩容中更容易表现出来,被你观察到了:)


在这里,首先要明确一下我们二者的代码逻辑的区别。

我的代码,是将原来data[front...tail)(可循环)范围内的元素,放到新的数组的newData[0...size)的范围中。

你的代码,是将原来data[front...tail)(可循环)范围内的元素,放到新的数组的newData[front...tail)中。


但是这样会出问题,比如,在原数组中,有8个空间,有2个元素,存储在data[4], data[5]的位置。

现在缩容后,newData只有4个空间,即对于newData来说,合法的索引值只有0, 1, 2, 3。此时,你的代码就产生了Bug,因为在你的for循环中,i的索引值是相对data来说的,但是对data合法的i,对newData不一定合法:)


希望你已经了解了你的代码的bug在哪里。如果还不是很清楚,不妨对于你发现问题的测试用例,仔细跟踪看一看:)


----------


正因为如此,我们在缩容后(其实扩容也有可能出现同样的问题),并不能使用原有的data的索引系统。也因此,在我的代码中,我直接将原有的data中的元素,在data[front...tail)(可循环)范围内,放到了新的newData数组的newData[0...size)的范围中。相应的,front和tail也要进行重新的维护。


再回顾我的代码。在我的代码中,for循环中,i的索引值是相对newData来说的,所以有newData[i] = data[(front+i)%data.length],这里的(front+i)%data.length,其实是将每一个newData中的i,转换成了data中相应的索引,使得原来data中的元素,被放置在了newData[0...size)的范围中。


事实上,你也可以在for循环中使用data的索引系统,在赋值的时候,转换成newData中相应的索引。但会稍微麻烦一些。如果有兴趣的话,不妨试试看?:)

0
1
慕的地9541928
谢谢老师,我会尝试做一下
2018-05-30
共1条回复

玩转数据结构

动态数组/栈/队列/链表/BST/堆/线段树/Trie/并查集/AVL/红黑树…

6221 学习 · 1704 问题

查看课程