C 语言数组的三个特性
1. 固定大小:
- 数组在声明时需要指定大小,一旦分配,大小就不能改变。数组的大小在编译时确定。
- 示例:
int a[10]; // 定义了一个大小为 10 的整数数组
2. 连续内存分配:
- 数组元素在内存中是连续存储的,数组的第一个元素的地址就是整个数组的起始地址。
- 示例:
int a[3] = {1, 2, 3};
printf("%p\n", (void*)&a[0]); // 打印第一个元素的地址
printf("%p\n", (void*)&a[1]); // 打印第二个元素的地址
3. 类型一致:
- 数组中的所有元素必须是相同类型,数组可以存储基本数据类型或自定义的数据类型。
- 示例:
float b[5]; // 定义了一个大小为 5 的浮点数组
什么是越界访问
越界访问是指访问数组时使用了非法的索引,超出了数组的边界范围。这种行为可能导致程序崩溃或产生未定义行为,因为访问的是未分配的内存。
示例:
int a[5] = {1, 2, 3, 4, 5};
printf("%d\n", a[5]); // 非法访问,第五个元素越界,合法索引应该是 0 到 4
选择排序、冒泡排序及插入法的使用及特点
1. 选择排序(Selection Sort):
- 使用方法:
- 每次从未排序部分选择最小(或最大)的元素,放到已排序部分的末尾。
- 重复这个过程,直到所有元素都已排序。
- 特点:
- 时间复杂度:O(n²)
- 空间复杂度:O(1)
- 简单易实现,但性能较低,适用于小规模数据排序。
void selectionSort(int arr[], int n) {
int i, j, minIdx;
for (i = 0; i < n-1; i++) {
minIdx = i;
for (j = i+1; j < n; j++) {
if (arr[j] < arr[minIdx]) {
minIdx = j;
}
}
// 交换
int temp = arr[minIdx];
arr[minIdx] = arr[i];
arr[i] = temp;
}
}
2. 冒泡排序(Bubble Sort):
- 使用方法:
- 每次从数组开头比较相邻元素,如果顺序错误就交换,经过一轮比较后,最大(或最小)的元素会移动到数组末尾。
- 重复这个过程,对前面的元素继续执行,直到所有元素都已排序。
- 特点:
- 时间复杂度:O(n²)
- 空间复杂度:O(1)
- 简单易实现,但性能较低,适用于小规模数据排序。
void bubbleSort(int arr[], int n) {
int i, j;
for (i = 0; i < n-1; i++) {
for (j = 0; j < n-i-1; j++) {
if (arr[j] > arr[j+1]) {
// 交换
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
3. 插入排序(Insertion Sort):
- 使用方法:
- 从第二个元素开始,将每个新元素插入到已排序部分的适当位置。
- 重复这个过程,直到所有元素都已排序。
- 特点:
- 时间复杂度:O(n²)
- 空间复杂度:O(1)
- 对于几乎已排序的数组,性能较好,适用于小规模数据排序。
void insertionSort(int arr[], int n) {
int i, key, j;
for (i = 1; i < n; i++) {
key = arr[i];
j = i - 1;
// 移动大于 key 的元素
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
总结:
- 选择排序:每次选择最小元素,交换到前面,简单但效率低。
- 冒泡排序:相邻元素两两比较并交换,每次把最大元素放到最后,简单但效率低。
- 插入排序:每次插入一个新元素到已排序部分,适用于小规模或部分有序的数据。