数组是各种编译型编程语言(C/C++、Fortran、Java等)中最常见的一种数据结构,是一种把同一类型的数值聚集在一起,用下标快速访问的数据集合。真正的数组定义必须含有以下两条:
①必须声明数组中元素的数据类型(例如整数,浮点数,字符等),也就规定了元素是同一数据类型的;
②必须声明数组长度,也就是说数组的长度是固定的。
数组被声明后会在内存中开辟对应大小的空间。比如声明一个5个整数组成的数组(arr),表示在内存中获取了一个4×5=20字节的空间存放该数组。数组的访问,实际是通过内存地址实现的。例如:arr[3]=3,计算机会用下标编号3乘以整数的字节长度4(3×4=12)作为地址偏移量,然后把指针在内存中从数组开头地址平移12字节,指到arr[3]所在的位置,并给此位置的内存空间赋值为3。
数组本质上是内存中一段大小固定、地址连续的存储单元。因此数组空间一经开辟,不可拓展。这意味着如果企图访问超过此数组长度的空间,比如,arr[8]=8,系统会报下标越界。数组结构示意如图下所示。
常用的数组有两种:一维数组和二维数组。一维数组是一个长度固定、下标有序的线性序列;二维数组则是一个矩阵结构,本质上是以数组作为数组元素的数组,即“数组的数组”。
以上是编译型语言中数组的定义,然而Python是解释型语言,它没有数组。列表最接近数组的的一种数据结构,但列表其实是一种链表。为了后续更好地说明数组的操作,把Python中的列表(list)当数组用。为了使列表更像数组,编写array模块,提供创建数组和数组拷贝功能,代码如下图。
下标访问(例如:arr[3])、创建数组(例如:array.create(3))、数组拷贝(例如:array.copy(arr1,0,arr2,0,3))就构成了数组的全部功能。
例题1:消除数组中重复元素。
将数组[1,23,1,1,1,3,23,5,6,7,9,9,8,5]中重复的数字消除掉,只留下不重复的数字。
上题可以有以下三种解决方法:
(1)字典(哈希)法,后续学完散列表再讲解。
(2)新链表法:创建一个新链表,循环逐一取出数组中的元素并与列表中的元素逐比较,如果没有重复数值就把该元素加入新链表。
(3)暴力法:每个元素和后面的元素循环逐一比较,有重复的则删除。
这里采用方法(3),其逻辑是:用双重循环遍历数组,第1重循环中的每个元素和此元素后面的元素逐一比较,发现后面有重复的数据直接删除后面的重复项。用暴力法消除数组中重复元素的算法图解如下图所示。
由于真实的数组删除数组中的元素需要把后续的元素前移,本处改用前移不重复项策略。不是删除元素而是把不重复的元素拷贝到数组前面。
程序代码:
运行结果:
练习1:编程将数组[7,23,23,5,1,9,7,9,18,8,7]中重复的数字消除掉,只留下不重复的数字。
例题2:求数组中的最大值和次大值。
求一个数组的最大值比较简单,声明一个变量,放入数组的第1个元素;然后遍历数组中的元素,逐一和变量中的元素比较,如果比变量元素大,则把变量元素替换为更大的元素;这样循环到队尾时,变量的元素肯定是数组中的最大值。但加上次大值就要麻烦些,看下述求数组最大值和次大值的算法分析。
算法分析:声明两个变量,一个存人最大值,另一个存入次大值;循环数组,每个元素先和最大值比较,如果比最大值小,再和次大值比较,比次大值大就赋值给次大值,比最大值还大就用个临时变量先存入原先的最大值,把最大值变量更新后再把临时变量中的原最大值赋值给次大值变量,如此循环完毕,两个变量就分别存储着最大值和次大值。求数组中的最大值和次大值的图解分析如下图所示。
循环指针每后移1次,最大值先和指针指向的元素比较大小。如果新元素更大,把原最大值赋值给次大值,最大值换上新值;如果新元素更小,则再和次大值比较,如值更大则替换之。
程序代码:
运行结果:
练习2:编程求数组[23,55,7,9,4,244,88,25,201,179]的最大值、次大值、最小值和次小值。
学思营编程课堂基于蓝桥STEM86平台https://www.stem86.com,开展学编程三部曲:Scratch(三年级以前)>>>Python(四年级以后)>>>C++(七年级以后)教育实验活动,任何人可以免费参加,打开https://xuesiying.stem86.com网页注册进入课堂,也可关注本公众号留言。更多课程请打开“学思营”同步网站:http://www.5xstar.com/doc.html
参考资料:
1、《Python算法图解》何韬编著 清华大学出版社