在前一篇中,我们讨论了树与图的基本概念和操作,包括二叉树的遍历和图的搜索算法。这一篇将深入探讨一些经典算法,并通过C语言实现它们。这些算法在算法竞赛、面试以及实际开发中扮演着重要角色。
1. 排序算法 排序是数据结构与算法中非常基础且重要的一部分。这里我们介绍几种经典的排序算法,包括快速排序、归并排序和冒泡排序。
1.1 冒泡排序 冒泡排序是一种简单的排序算法,通过重复遍历要排序的列表,比较每对相邻元素并交换它们的位置,如果它们的顺序错误。
1 2 3 4 5 6 7 8 9 10 11 12 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 快速排序 快速排序是一种高效的排序算法,采用分治法策略。它的基本思想是选择一个“基准”元素,将数组分成两个子数组,使得一个子数组的所有元素都小于基准元素,而另一个子数组的所有元素都大于基准元素,再递归对这两个子数组进行排序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 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 归并排序 归并排序也是一种采用分治法的排序算法。它分为两个阶段:分解(递归拆分)和合并(将已排序的子序列合并成一个有序序列)。
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 27 28 29 30 31 32 33 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。
1 2 3 4 5 6 7 8 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 二分查找 二分查找是一种高效的查找算法,前提是数组必须是已排序的 。它通过不断地将查找范围减半来查找目标值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 斐波那契数列 斐波那契数列的定义为:
$$ F(n) = F(n-1) + F(n-2), \quad F(0) = 0, \quad F(1) = 1 $$
使用动态规划来解决斐波那契数列。
1 2 3 4 5 6 7 8 9 10 11 12 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);