5.7 有关数组的常用操作

数组作为数据的存储容器,必然会涉及许多和数据有关的操作,比如排序、反转、去重等,这些都是平常编程中经常会用到的操作。我们通过前面的学习已经了解了有关数组的基本操作,是时候来进行一些实际的操作了。

5.7.1 数组的排序

数组的排序方法有许多,比如冒泡排序、快速排序、交换排序、堆排序等。这是我们在数据结构中专门学习的内容,这里介绍最基础的冒泡排序。

冒泡排序的原理是:对于数组中的元素,依次比较相邻的两个数,将小数放在前面、大数放在后面。具体就是先比较第1个和第2个数,将小数放在前面、大数放在后面;然后比较第2个和第3个数,将小数放在前面、大数放在后面,如此继续,直至比较最后两个数,将小数放在前面、大数放在后面,最终最大的数在最后面。重复以上过程,仍从第一对数开始比较,将小数放在前面、大数放在后面,一直比较到最大数前的一对相邻数,将小数放在前面、大数放在后面,第二趟结束,在倒数第二个数中得到一个新的最大数(比前面的数都大,比后面的数都小)。如此下去,直至最终完成排序。

在排序过程中,总是小数往前放、大数往后放,相当于气泡往上升,所以称作冒泡排序。下面我们对数组scores进行排序,其代码如示例5-11所示。

【示例5-11】冒泡排序算法

程序编译后,运行结果如下:

在示例5-11中展示了如何使用冒泡排序对一组无序数组进行排序,最终展示出从小到大的新数组。

5.7.2 数组的反转

数组的反转首先要通过图5.7来认识一下。

图5.7 数组的反转

通过观察上图,我们可以得出一个结论:当前位置加上反转后的位置之和是数组的长度值减1。所以我们定义两个索引变量,一个从最左边开始,一个从最右边开始,它们同时向中间的那个索引位置接近,并在过程中不断地交换彼此的值,直到最左边的索引值大于最右边的索引值时停止。针对上边的例子来说,就是索引0和索引5交换元素值,然后0加1变成1,5减1变成4。重复上述过程,直到2加1变成3、3减1变成2时停止,数组也就完成了反转。代码如示例5-12所示。

【示例5-12】数组的反转

程序编译后,运行结果如下:

示例5-12中展示了如何对数组进行反转操作。索引0和索引9交换元素值,然后0加1变成1,9减1变成8;重复上述过程,直到4加1成了5,5减1成了4,数组也完成了反转操作。

5.7.3 数组的去重

对数组去除重复的元素也是常用的操作。数组一旦定义了大小之后,就不能再增加或者减小,所以去重后的元素应该存放到一个新的数组中保存。

去重最简单的思路就是:依次把旧数组中的元素存放到新数组中,但是在放入新数组中之前,要先在新数组中查找一次,看该元素是否已经存在了,如果没有存在,就把这个元素添加到新数组中去,存在的话就跳过。前面我们已经说过了,数组的大小一经定义就不能再改变,所以我们可以先按最大长度去新建一个临时数组,再把其中的有效值复制到一个相应大小的数组中去。记得置空临时数组,便于垃圾回收。

在正式进行操作之前,让我们再来一起认识一个方法:System.arraycopy——用于数组的复制。该数组的作用如下:

该方法从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。从src引用的源数组到dest引用的目标数组,数组组件的一个子序列被复制下来。被复制的组件的编号等于length参数。源数组中位置在srcPos到srcPos+length-1之间的组件被分别复制到目标数组中的destPos到destPos+length-1位置。其中的参数如下:


● src:源数组。

● srcPos:源数组中的起始位置。

● dest:目标数组。

● destPos:目标数据中的起始位置。

● length:要复制的数组元素的数量。


该方法的使用方式如示例5-13所示。

【示例5-13】数组的去重

程序编译后,运行结果如下:

在示例5-13中展示了如何对数组中的重复数据进行排重。在进行原数组的遍历过程中,通过使用标识位isRepetition来判断当前元素是否已经出现过,如果当前元素没有出现过,就将其记录下来存放到临时数组中;如果出现过,就直接跳出本次循环,转为判断数组中的下一个元素。在原数组中所有的元素都判断完成之后,使用arraycopy()方法将临时数组复制到原数组中,从而实现数组的排重。