目录
今天继续学习数组的知识
先来排序吧
排序
排序主要有下面几种
选择排序
冒泡排序
插入排序
快速排序
并归排序
冒泡排序
以下是冒泡排序的示例代码:
#include <stdio.h>
// 冒泡排序函数
void bubbleSort(int arr[], int n) {
int i, j, temp;
for (i = 0; i < n - 1; i++) {
for (j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
// 打印数组函数
void printArray(int arr[], int size) {
int i;
for (i = 0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
// 测试案例
int main() {
int arr[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(arr) / sizeof(arr[0]);
printf("排序前的数组为: ");
printArray(arr, n);
bubbleSort(arr, n);
printf("排序后的数组为: ");
printArray(arr, n);
return 0;
}
冒泡排序的基本思想是通过相邻元素的比较和交换,将最大(或最小)的元素逐步“浮”到数组的末尾(或开头)。其时间复杂度为 o(n^2),空间复杂度为 o(1) 。
插入排序
以下为插入排序的 C 语言实现代码:
#include <stdio.h>
// 插入排序函数
void insertionSort(int arr[], int n) {
int i, key, j;
for (i = 1; i < n; i++) {
key = arr[i];
j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
// 打印数组函数
void printArray(int arr[], int size) {
int i;
for (i = 0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
// 测试案例
int main() {
int arr[] = {12, 11, 13, 5, 6};
int n = sizeof(arr) / sizeof(arr[0]);
printf("排序前的数组为: ");
printArray(arr, n);
insertionSort(arr, n);
printf("排序后的数组为: ");
printArray(arr, n);
return 0;
}
插入排序的基本思想是将待排序的元素插入到已排序的部分合适的位置,时间复杂度为 o(n^2),空间复杂度为o(1) 。
选择排序
再介绍选择排序的 C 语言代码:
#include <stdio.h>
// 选择排序函数
void selectionSort(int arr[], int n) {
int i, j, min_idx;
for (i = 0; i < n - 1; i++) {
min_idx = i;
for (j = i + 1; j < n; j++)
if (arr[j] < arr[min_idx])
min_idx = j;
if (min_idx!= i) {
int temp = arr[i];
arr[i] = arr[min_idx];
arr[min_idx] = temp;
}
}
}
// 打印数组函数
void printArray(int arr[], int size) {
int i;
for (i = 0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
// 测试案例
int main() {
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
printf("排序前的数组为: ");
printArray(arr, n);
selectionSort(arr, n);
printf("排序后的数组为: ");
printArray(arr, n);
return 0;
}
选择排序每次从待排序序列中选择最小(或最大)的元素,与序列的起始位置交换,时间复杂度也为o(n^2) ,空间复杂度为 o(1) 。
快速排序
还有快速排序,示例代码如下:
#include <stdio.h>
// 交换两个元素
void swap(int* a, int* b) {
int t = *a;
*a = *b;
*b = t;
}
// 划分函数
int partition(int arr[], int low, int high) {
int pivot = arr[high];
int i = (low - 1);
for (int j = low; j <= high - 1; j++) {
if (arr[j] <= pivot) {
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
return (i + 1);
}
// 快速排序函数
void quickSort(int arr[], int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
// 打印数组函数
void printArray(int arr[], int size) {
int i;
for (i = 0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
// 测试案例
int main() {
int arr[] = {10, 7, 8, 9, 1, 5};
int n = sizeof(arr) / sizeof(arr[0]);
printf("排序前的数组为: ");
printArray(arr, n);
quickSort(arr, 0, n - 1);
printf("排序后的数组为: ");
printArray(arr, n);
return 0;
}
快速排序的平均时间复杂度为o(nlogn) ,空间复杂度为 o(logn) ,是一种效率较高的排序算法。
并归排序
归并排序的 C 语言代码:
#include <stdio.h>
// 合并两个已排序的子数组为一个已排序的数组
void merge(int arr[], int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
int L[n1], R[n2];
for (int i = 0; i < n1; i++)
L[i] = arr[l + i];
for (int j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k++] = L[i++];
} else {
arr[k++] = R[j++];
}
}
while (i < n1) {
arr[k++] = L[i++];
}
while (j < n2) {
arr[k++] = R[j++];
}
}
// 归并排序函数
void mergeSort(int arr[], int l, int r) {
if (l < r) {
int m = l + (r - l) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
// 打印数组函数
void printArray(int arr[], int size) {
int i;
for (i = 0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
// 测试案例
int main() {
int arr[] = {12, 11, 13, 5, 6};
int n = sizeof(arr) / sizeof(arr[0]);
printf("排序前的数组为: ");
printArray(arr, n);
mergeSort(arr, 0, n - 1);
printf("排序后的数组为: ");
printArray(arr, n);
return 0;
}
归并排序的平均时间复杂度和最坏时间复杂度均为 O(nlongn) ,
空间复杂度为 O(logn) 。
查找
在 C 语言中,查找操作通常可以通过不同的方法和数据结构来实现。
比如,如果是在一个数组中查找特定元素,可以使用顺序查找的方法,依次遍历数组中的每个元素,直到找到目标元素。
以下是一个简单的顺序查找的 C 语言示例代码:
#include <stdio.h>
// 顺序查找函数
int sequentialSearch(int arr[], int n, int target) {
for (int i = 0; i < n; i++) {
if (arr[i] == target) {
return i;
}
}
return -1; // 未找到返回 -1
}
int main() {
int arr[] = {2, 4, 6, 8, 10};
int target = 8;
int n = sizeof(arr) / sizeof(arr[0]);
int result = sequentialSearch(arr, n, target);
if (result!= -1) {
printf("元素 %d 在数组中的索引为 %d\n", target, result);
} else {
printf("数组中未找到元素 %d\n", target);
}
return 0;
}
如果要在更复杂的数据结构如链表、二叉搜索树等中进行查找,方法会有所不同。
以下是二分查找的 C 语言代码实现:
#include <stdio.h>
// 二分查找函数
int binarySearch(int arr[], int left, int right, int target) {
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1; // 未找到返回 -1
}
int main() {
int arr[] = {1, 3, 5, 7, 9, 11, 13};
int target = 7;
int n = sizeof(arr) / sizeof(arr[0]);
int result = binarySearch(arr, 0, n - 1, target);
if (result!= -1) {
printf("元素 %d 在数组中的索引为 %d\n", target, result);
} else {
printf("数组中未找到元素 %d\n", target);
}
return 0;
}
在上述代码中, binarySearch 函数接受一个已排序的数组、左边界、右边界和目标值作为参数。通过不断将搜索范围缩小一半,直到找到目标值或确定目标值不存在。
字符数组
在 C 语言中,字符数组用于存储一系列字符。以下是一些关于字符数组的关键知识点:
定义字符数组的方式有多种,例如:
char str1[10]; // 未初始化,数组元素的值是未定义的
char str2[10] = "Hello"; // 初始化部分元素
char str3[] = "World"; // 编译器自动计算数组大小
访问字符数组中的元素可以通过索引,例如 str1[0] 。
可以使用循环来处理字符数组中的字符,比如:
for (int i = 0; str2[i]!= '\0'; i++) {
printf("%c", str2[i]);
}
字符串以 '\0' 作为结束标志,在处理字符数组时要注意这个结束标志。
字符数组和字符串的区别:
1. 存储形式:
- 字符数组可以存储任意的字符序列,不一定以 '\0' 结尾。
- 字符串本质上是一个以 '\0' 结尾的字符数组,这个 '\0' 用于标识字符串的结束。
2. 初始化方式:
- 字符数组初始化时,可以不完整地初始化,未初始化的部分元素值是未定义的。
- 字符串初始化时,会自动在末尾添加 '\0' 。
3. 操作方式:
- 对于字符数组的操作,需要开发者自己注意数组的边界和结束标志。
- 对于字符串,可以使用标准库中的字符串处理函数,如 strcpy 、 strcat 等,这些函数会根据 '\0' 来正确处理字符串。
4. 输出方式:
- 输出字符数组时,如果没有 '\0' ,可能会导致输出不可预期的内容。
- 输出字符串时, printf 等函数会根据 '\0' 自动停止输出。
总的来说,字符串是一种特殊形式的字符数组,其使用更加方便和安全,因为标准库提供了丰富的函数来处理字符串,并且遵循了一定的规则和约定。
在 C 语言中, gets 函数由于无法限制输入字符串的长度,可能导致缓冲区溢出的安全问题,已被弃用。
puts 函数用于输出一个字符串,并在输出完毕后自动换行。
以下是 puts 函数的示例用法:
#include <stdio.h>
int main() {
char str[] = "Hello, World!";
puts(str);
return 0;
}
而对于输入字符串,建议使用 fgets 函数来替代 gets ,它可以指定输入缓冲区的大小,从而避免缓冲区溢出的风险。