数组介绍
概念:什么是数组?
数组就是若干个有序的相同数据类型的元素的集合。
数组是构造类型,数组元素既可以是基本数据类型也可以是构造类型。例如二维数组或者多维数组,数组元素本身也是个数组,也就是构造类型数据。
数组的分类;
按存储元素的类型:
1. 数值数组
2. 字符数组
3. 指针数组
4. 结构数组(用来存放一个结构体类型的数据)
按照数组的维度:
1. 一维数组
2. 两位数组
3. 多维数组
一维数组的定义:
类型修饰符 数祖名[常量表达式];
注意事项:
1. 数组长度可以是常量或者常量表达式,但不能是变量或者变量表达式(C99标准)。虽然XCODE可以定义数组时使用变量作为数组长度,但不建议这样使用。
2. 数组的命名规则严格按照标识符的命名规则
3. 数祖名不能和其他变量名同名
4. 数祖名的长度可以使用宏定义
一维数组的初始化:
1. 定义时初始化
a. 完全初始化
b. 部分初始化
2. 先定义后初始化
注意点:
*1. 定义时初始化,未初始化的部分自动初始为0
*2. 定义时初始化,如果数组长度是一个变量或者变量表达式,则不允许该数组定义时初始化。例如: int leng = 4; int arr[leng] = {1, 2, 3, 4}; 这样是错误的。
*3. 数组没有初始化,数组元素也是有值的,不过值不确定,是个垃圾值。
*4. 先定义后初始化的数组,随后进行的了部分初始化,未被初始化的那部分元素中的值仍为垃圾值。
数组的引用
数组元素作为变量使用。数组元素标识: 数祖名[元素下标]
数组元素的标号从0开始,所以长度为n的数组,数组下标范围是0到n-1
数组的存储方式:
#1 计算机会给数组分配一块联系的内存空间
#2 数祖名代表数组的首地址(数祖名是一个常量,存放的就是数组的(首)地址),从首地址位置,依次存入数组的第1个、第2个、。。。、第n个元素
#3 每个元素占用相同的空间大小(字节数)
#4 元素之间的地址是连续的
一维数组长度的计算:
数组在内存中占用的字节数:sizeof(数组名)
数组的长度 = 数组的总字节数 / 数组元素类型占用字节数 = sizeof(数组名) / sizeof(元素类型)
数组元素作为函数参数
和普通变量作为参数传递给函数一样。
把数组元素的值作为实参传递给函数,是单向传递的过程。
用数组名作为函数参数
作为实参传递:地址传递,将数组的地址传递函数的形参数组,两个数组共享一段内存空间。
作为形参,可以不写数组长度。如果是多维函数可以不写第一维长度可以不写。
形参和实参的类型必须一致。
注意:形参和实参的长度可以不相同,因为编译的时候不会检查数组长度,可以编译通过,但运行结果可能和实际不相符。
Bubble sort:
从开始第一个元素依次和后面的元素比较,把较大(或者较小)的元素和第一个元素交换。执行到最后一个元素后,第一个元素即最大值(或者最小值)。再从第二个元素和后面的元素比较;重复执行这样的循环直到倒数第二个元素比较完成后(因为最后一个元素一定是最小值(或者最大值),不用排序了),数组排序完成。
循环执行 n - 1次,比较了(n - 1) + (n - 2) + (n - 3) + … +1次。
// bubble sort for (int i = 0; i < length - 1; i++) { for (int j = 0; j < length - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } |
Selection sort:
在序列中找到最小(最大)元素,放到序列的起始位置arr[0];再从剩下的未排序的序列中找出最小元素,放到未排序的序列的起始位置arr[1];依次执行该循环直到排序完成。
外循环负责排序,执行了n -1次;(i = 0 ; i < n -1 ; i++)
内循环负责比较及交换元素,每次循环执行n -1 - i次。i 这里指外部循环中的i。
// seleciton sort arr[] for (int i = 0; i < length - 1 ; i++) { for (int j = i + 1; j < length; j++) { if (arr[i] > arr[j]) { arr[i] = arr[i] ^ arr[j]; arr[j] = arr[i] ^ arr[j]; arr[i] = arr[i] ^ arr[j]; } } } |
Binary Search:
如果数组中的元素是有序的,才可以使用折半查找。
基本思路:
在有序的数列中取中间元素作为比较对象,如果中间元素和要查找的关键字相等,则查找成功。如果不相等,则取可能包含关键字的那一半序列中的中间元素和关键字比较,重复这样的操作知道查找成功或者查找失败。
【步骤】
1 low=1;high=length; // 设置初始区间
2 当low>high 时,返回查找失败信息// 表空,查找失败
3 low≤high,mid=(low+high)/2; // 取中点
a. 若key<arr[mid],high=mid-1;转2 // 查找在左半区进行
b. 若key>arr[mid],low=mid+1;转2 // 查找在右半区进行
c. 若key=arr[mid],返回数据元素在表中位置// 查找成功
数组定义时的其他注意事项:
#1 如果定义数组时没有初始化,则必须指定数组的大小;
#2 多维数组可以省略第一维的长度,但不能省略其他维的长度。
#3 定义时部分初始化后,为初始化的元素,自动初始化为0
#4 先定义再初始化,为初始化的元素,内容不确定。
二维数组的存储方式:
1)计算机会给二维数组分配一块连续的存储空间
2)数组名代表数组的首地址,从首地址位置,依次存入第1行、第2行、.....
3)每一行存储方式,从行首地址还是,依次存储行的第1个元素、第2个元素、第3个元素......
4)每个元素占用相同的字节数(取决于数组类型)
5)并且数组中元素之间的地址是连续。
arr == &arr[0] == &arr[0][0]
int arr[3][4];
总计占用字节数: sizeof(arr);
每行占用字节数: sizeof(arr[0]);
行数: 总字节数/每行字节数 --> sizeof(arr)/sizeof(arr[0]);
列数: 行数/每个类型 --> sizeof(arr[0])/sizeof(int)
1 /*
2 有1000000个数,每个数取值范围是0-999999,找出其中重复的数。
3 */
4 //#define COUNT 1000000
5 #define COUNT 1000000
6
7 int main(void)
8 {
9 int a[COUNT] = {0};
10 for (int i = 0; i < COUNT; i++) {
11 int number = arc4random_uniform(COUNT)%COUNT;
12 //把随机数作为下标,值作为出现次数
13 a[number] ++;
14 }
15 //输出 重复的数字以及重复次数
16 for(int i = 0 ;i < COUNT;i++){
17 if (a[i] > 1) {
18 printf("%d repeats %d times\n",i,a[i]);
19 }
20 }
21
22 for (int i = 0; i < COUNT; i++) {
23 printf("a[%d] = %d\t", i, a[i]);
24 }
25 return 0;
26 }