19 经典算法实现
在前一篇中,我们讨论了树与图的基本概念和操作,包括二叉树的遍历和图的搜索算法。这一篇将深入探讨一些经典算法,并通过C语言实现它们。这些算法在算法竞赛、面试以及实际开发中扮演着重要角色。
1. 排序算法
排序是数据结构与算法中非常基础且重要的一部分。这里我们介绍几种经典的排序算法,包括快速排序、归并排序和冒泡排序。
1.1 冒泡排序
冒泡排序是一种简单的排序算法,通过重复遍历要排序的列表,比较每对相邻元素并交换它们的位置,如果它们的顺序错误。
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
// 交换
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
1.2 快速排序
快速排序是一种高效的排序算法,采用分治法策略。它的基本思想是选择一个“基准”元素,将数组分成两个子数组,使得一个子数组的所有元素都小于基准元素,而另一个子数组的所有元素都大于基准元素,再递归对这两个子数组进行排序。
void quickSort(int arr[], int low, int high) {
if (low < high) {
int pivot = partition(arr, low, high);
quickSort(arr, low, pivot - 1);
quickSort(arr, pivot + 1, high);
}
}
int partition(int arr[], int low, int high) {
int pivot = arr[high];
int i = (low - 1);
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return i + 1;
}
1.3 归并排序
归并排序也是一种采用分治法的排序算法。它分为两个阶段:分解(递归拆分)和合并(将已排序的子序列合并成一个有序序列)。
void mergeSort(int arr[], int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
void merge(int arr[], int left, int mid, int right) {
int i = left, j = mid + 1, k = 0;
int temp[right - left + 1];
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
for (i = left, k = 0; i <= right; i++, k++) {
arr[i] = temp[k];
}
}
2. 查找算法
查找算法用于在数据结构中查找某个元素,这里介绍线性查找和二分查找。
2.1 线性查找
线性查找是最简单的查找方法,通过逐个检查每一个元素来寻找目标值。如果找到,则返回该元素的索引,否则返回-1。
int linearSearch(int arr[], int n, int target) {
for (int i = 0; i < n; i++) {
if (arr[i] == target) {
return i; // 找到目标
}
}
return -1; // 未找到
}
2.2 二分查找
二分查找是一种高效的查找算法,前提是数组必须是已排序的。它通过不断地将查找范围减半来查找目标值。
int binarySearch(int arr[], int n, int target) {
int left = 0, right = n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid; // 找到目标
}
if (arr[mid] < target) {
left = mid + 1; // 在右半边
} else {
right = mid - 1; // 在左半边
}
}
return -1; // 未找到
}
3. 动态规划
动态规划是一种将复杂问题分解成更简单子问题的方法,它通常用于寻找最优解。这里以“斐波那契数列”为例。
3.1 斐波那契数列
斐波那契数列的定义为:
使用动态规划来解决斐波那契数列。
int fib(int n) {
if (n <= 1) return n;
int dp[n + 1];
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
4. 示例与总结
通过对这些经典算法的理解和实现,我们不仅掌握了常用的算法思想,还能够在实际应用中灵活运用。下面是一个简单的示例,演示如何使用上述的排序和查找算法。
#include <stdio.h>
int main() {
int arr[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(arr)/sizeof(arr[0]);
// 排序数组
bubbleSort(arr, n);