活动地址:CSDN21天学习挑战赛
一、创建数组(为数组分配内存)
1.1 c语言
静态分配内存
内存分配在栈上,离开栈内存自动销毁。
可以直接创建数组并指定大小。
C99之前创建数组必须传入固定大小,如下:
1
2int num[10];
C99开始支持传入变量的变长数组
1
2
3int size = 10; int num[size];
动态分配内存
内存分配在堆上,需要使用free手动释放,否则直到程序结束才释放。
使用malloc函数分配内存,如:
1
2
3// 为数组分配一个可以存储10个int数据的内存空间 int* p_int = (int*)malloc(sizeof(int) * 10);
malloc分配的内存,在使用结束时要调用free函数手动释放:
1
2free(p_int);
二、初始化数组
2.1 c语言
可以在创建时初始化,也可以创建后再初始化。
- 创建时初始化可以不写大小,申请空间时通过数据元素个数计算大小。
1
2int num[] = {1, 2, 3};
- 在自定义函数中,如果数组创建后没有初始化,数组会被随机值填充。
- 在全局域或
main
函数中,如果数组创建后没有初始化,数组会被0
填充。 - 当创建时初始化,初始化的元素个数比数组申请的大小少,即没有将数组所有元素初始化,未初始化的数组元素将被
0
填充。
代码验证如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <stdio.h> // 全局域创建数组 int num1[3]; int num5[3] = {1}; void init_array() { // 自定义函数局部域 int num3[3]; int num4[3] = {1}; printf("自定义函数num3[1]: %dn", num3[1]); printf("n打印数组创建时初始化,未被初始化的元素n"); printf("自定义函数num4[1]: %dn", num4[1]); } int main() { printf("打印数组创建时未初始化,数组的元素n"); printf("全局域num1[1]: %dn", num1[1]); int num2[3]; printf("main函数num2[1]: %dn", num2[1]); init_array(); printf("全局域num5[1]: %dn", num5[1]); int num6[3] = {1}; printf("main函数num6[1]: %dn", num6[1]); return 0; }
打印结果如下:
1
2
3
4
5
6
7
8
9打印数组创建时未初始化,数组的元素 全局域num1[1]: 0 main函数num2[1]: 0 自定义函数num3[1]: 21899 打印数组创建时初始化,未被初始化的元素 自定义函数num4[1]: 0 全局域num5[1]: 0 main函数num6[1]: 0
三、获取数组大小
3.1 c语言
数组容量大小(最多能存储的数据个数)
想要获取数组的内存大小,可以使用sizeof函数
1
2
3int arr[10]; int max_size = sizeof(arr)/sizeof(arr[0]);
数组当前存储数据的个数(面向对象思想)
实际上我们需要的,常常是数组存储数据的个数,而不是数组最多能存储多少和数据,如果数组一开始分配内存比实际存储的数据所占内存大(实际上常常就是这样),就需要使用另一种方法了。
常用的是面向对象的思想,不要以为c语言是面向过程的语言,其实它早已偷偷加入了面向对象的东西,而且面向对象的思想,是思想,可以用任何语言实现。
利用c语言的结构体,创建一个数组结构体类型,每次操作数据记录当前长度。
1
2
3
4
5
6
7
8
9
10
11
12
13// 以动态分配内存为例 typedef struct{ int* data; // 数组的首地址 int length; // 数组的当前长度 int maxSize; // 数组最大容量大小 } Array;
四、插入元素
4.1 不需保证数组元素原有排序
当不需要保证数组元素原有排序时,不用指定插入位置,直接使用尾插法,不用移动元素,时间复杂度为O(1)
1
2
3
4
5
6
7
8
9
10
11bool insertBack(Array* array, int num) { if (array->length >= array->maxSize) { return false; } array->pData[array->length] = num; array->length++; return true; }
4.2 需保证数组元素原有排序
当需要保证数组元素原有排序时,要指定插入位置,并且插入位置以后元素都要后移,为新元素腾出位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15bool insert(Array* array, int index, int num) { if (array == NULL || array->pData == NULL || array->length > array->maxSize) { return false; } for (int i = array->length; i > index; i--) { array->pData[i] = array->pData[i-1]; } array->length++; array->pData[index] = num; return true; }
当原数组无数值顺序,需要人为指定插入位置。
当原数组有数值顺序,要先将新元素的数值与原数组元素比较大小,找到对应位置,再调用上面函数。
五、删除元素
和插入元素一样,如果不需保证原有数组的顺序,需把最后一个元素覆盖要删除的元素即可,时间复杂度O(1)。
如果需保证原有数组的顺序,删除位置以后的元素要往前移动,以保证数组内存的连续性,时间复杂度O(n)。
以上复杂度只是删除操作的复杂度,如果需要查找定位,就另说了。这里仅说明需保证原有数组顺序的情况。
根据提供的数据不同,可分为以下两种方法:
5.1 指定索引删除
找到给定位置,将此位置后面的元素前移,把该位置的元素覆盖即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14bool removeWithIndex(Array* array, int index) { if (array == NULL || array->pData == NULL || array->length > array->maxSize) { return false; } for (int i = index+1; i < array->length; i++) { array->pData[i-1] = array->pData[i]; } array->length--; return true; }
5.2 指定数值删除
这里涉及了查找操作,需要先根据数值查找定位元素,再执行删除操作。
这里以穷举遍历查找为例,仅说明一下删除操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21bool removeWithValue(Array* array, int value) { if (array == NULL || array->pData == NULL || array->length > array->maxSize) { return false; } int tmpArray[array->length]; int j = 0; for (int i = 0; i < array->length; i++) { if (array->pData[i] == value) { continue; } tmpArray[j++] = array->pData[i]; } array->pData = tmpArray; array->length = j; return true; }
六、访问元素
访问元素可以通过下标访问,也可以通过指针访问。
1
2
3
4
5
6
7
8
9// 下标 int arr[10]; arr[1] = 2; int a = arr[1]; // 指针 int arr[10]; *arr = 2; // 等价于arr[0] = 2; int a = *(arr+1); // 等价于a = arr[1];
最后
以上就是帅气蚂蚁最近收集整理的关于[数据结构与算法] 线性表之数组基本操作代码实现详解的全部内容,更多相关[数据结构与算法]内容请搜索靠谱客的其他文章。
发表评论 取消回复