当前位置: 首页 > news >正文

【数据结构】(C++数据结构)查找算法与排序算法详解

(C++数据结构)查找算法与排序算法详解

目录

  1. 有序向量的查找算法
  2. 排序算法
  3. 算法复杂度分析

1. 有序向量的查找算法

1.1 二分查找(Binary Search)

二分查找是最基本的有序向量查找算法,时间复杂度为O(log n)。

基本实现
int binarySearch(int A[], int lo, int hi, int e) {while (lo < hi) {mi = (lo + hi) >> 1;  // 中间位置,右移1位相当于除以2if (e < A[mi]) hi = mi;           // 目标在左半区间else if (e > A[mi]) lo = mi + 1;  // 目标在右半区间else return mi;                   // 找到目标}return -1;  // 未找到
}
改进版本
int binarySearchImproved(int A[], int lo, int hi, int e) {while (lo < hi) {mi = (lo + hi) >> 1;if (e < A[mi]) hi = mi;else lo = mi + 1;  // 右子区间不包含mi}return --lo;  // 返回不大于e的最大元素位置
}

关键点

  • 循环条件 lo < hi 确保区间有效
  • mi = (lo + hi) >> 1 避免溢出
  • 平均查找长度为 O(1.5 log n)

1.2 插值查找(Interpolation Search)

插值查找适用于均匀分布的有序向量,通过线性插值预测目标位置。

核心公式

mi−lohi−lo=e−A[lo]A[hi]−A[lo]\frac{mi - lo}{hi - lo} = \frac{e - A[lo]}{A[hi] - A[lo]}hilomilo=A[hi]A[lo]eA[lo]
解得:
mi=lo+(hi−lo)⋅e−A[lo]A[hi]−A[lo]mi = lo + (hi - lo) \cdot \frac{e - A[lo]}{A[hi] - A[lo]}mi=lo+(hilo)A[hi]A[lo]eA[lo]

实现代码
int interpolationSearch(int A[], int lo, int hi, int e) {while (lo <= hi && e >= A[lo] && e <= A[hi]) {if (lo == hi) {if (A[lo] == e) return lo;return -1;}// 插值公式计算预测位置mi = lo + ((double)(hi - lo) / (A[hi] - A[lo])) * (e - A[lo]);if (A[mi] == e) return mi;if (A[mi] < e) lo = mi + 1;else hi = mi - 1;}return -1;
}
示例分析

对于数组 V = {2,3,5,7,11,13,17,19,23},查找元素 e=7
mi−08−0=7−223−2=521\frac{mi - 0}{8 - 0} = \frac{7 - 2}{23 - 2} = \frac{5}{21}80mi0=23272=215
mi=8×521≈1.9→mi=1mi = 8 \times \frac{5}{21} \approx 1.9 \rightarrow mi = 1mi=8×2151.9mi=1
复杂度分析

  • 平均时间复杂度:O(log log n)
  • 最坏时间复杂度:O(n)

1.3 斐波那契查找(Fibonacci Search)

斐波那契查找利用斐波那契数列的特性进行分割,接近黄金比例分割。

斐波那契数列
k:  0  1  2  3  4  5  6   7
fib:0  1  1  2  3  5  8  13
核心思想
  • 数组长度满足:n = fib(k) - 1
  • 中间位置:mi = fib(k-1) - 1
  • 左子区间长度:fib(k-2) - 1
  • 右子区间长度:fib(k-1) - 1
实现代码
int fibonacciSearch(int A[], int n, int e) {// 初始化斐波那契数列int fib[20];fib[0] = 0; fib[1] = 1;for (int i = 2; i < 20; i++) {fib[i] = fib[i-1] + fib[i-2];}// 找到最小的k使得fib(k) - 1 >= nint k = 0;while (fib[k] - 1 < n) k++;int lo = 0, hi = n - 1;while (lo <= hi) {mi = lo + fib[k-1] - 1;if (mi > hi) {  // 处理边界情况mi = hi;}if (A[mi] == e) return mi;if (A[mi] < e) {lo = mi + 1;k = k - 2;  // 右子区间} else {hi = mi - 1;k = k - 1;  // 左子区间}}return -1;
}
示例分析

对于数组 V = {1,2,3,4,5,6,7},查找元素 e=1

  1. n=7, fib(6)-1=7, k=6
  2. mi = fib(5)-1 = 4, V[4]=5 > 1, hi=3, k=5
  3. mi = fib(4)-1 = 2, V[2]=3 > 1, hi=1, k=4
  4. mi = fib(3)-1 = 1, V[1]=2 > 1, hi=0, k=3
  5. mi = fib(2)-1 = 0, V[0]=1, 找到目标
    访问序列:[5,3,2,1]

2. 排序算法

2.1 冒泡排序及改进

基本冒泡排序
void bubbleSort(int A[], int n) {for (int i = 0; i < n-1; i++) {for (int j = 0; j < n-i-1; j++) {if (A[j] > A[j+1]) {swap(A[j], A[j+1]);}}}
}
改进版本(记录最后交换位置)
int bubble(int A[], int lo, int hi) {Rank last = lo;while (++lo < hi) {if (A[lo-1] > A[lo]) {swap(A[lo-1], A[lo]);last = lo;  // 记录最后交换位置}}return last;
}
void improvedBubbleSort(int A[], int n) {int lo = 0, hi = n;while (lo < (hi = bubble(A, lo, hi)));
}

改进原理:记录每次循环中最后一次交换的位置,下一轮只需比较到该位置即可。

2.2 归并排序(Merge Sort)

归并排序采用分治策略,时间复杂度O(n log n),是稳定排序。

核心合并算法
void merge(int A[], int lo, int mid, int hi) {int* B = new int[hi-lo+1];  // 临时数组int i = lo, j = mid+1, k = 0;// 合并两个有序子数组while (i <= mid && j <= hi) {if (A[i] <= A[j]) B[k++] = A[i++];else B[k++] = A[j++];}// 复制剩余元素while (i <= mid) B[k++] = A[i++];while (j <= hi) B[k++] = A[j++];// 复制回原数组for (int t = 0; t < k; t++) {A[lo+t] = B[t];}delete[] B;
}
void mergeSort(int A[], int lo, int hi) {if (hi - lo < 2) return;  // 递归基int mid = (lo + hi) >> 1;mergeSort(A, lo, mid);    // 排序左半部分mergeSort(A, mid, hi);    // 排序右半部分merge(A, lo, mid, hi);    // 合并
}

2.3 基数排序(Radix Sort)

基数排序按位数从低到高进行排序,要求每位排序时保持稳定性。

实现代码
// 获取数字的第d位数字
int getDigit(int num, int d) {while (d-- > 1) {num /= 10;}return num % 10;
}
// 对数组的第d位进行计数排序
void countingSortByDigit(int A[], int n, int d) {const int RADIX = 10;int* B = new int[n];int count[RADIX] = {0};// 统计各数字出现次数for (int i = 0; i < n; i++) {count[getDigit(A[i], d)]++;}// 计算累积位置for (int i = 1; i < RADIX; i++) {count[i] += count[i-1];}// 从右向左填充,保证稳定性for (int i = n-1; i >= 0; i--) {int digit = getDigit(A[i], d);B[count[digit]-1] = A[i];count[digit]--;}// 复制回原数组for (int i = 0; i < n; i++) {A[i] = B[i];}delete[] B;
}
void radixSort(int A[], int n) {if (n <= 1) return;// 找到最大值,确定位数int maxVal = A[0];for (int i = 1; i < n; i++) {if (A[i] > maxVal) maxVal = A[i];}// 按位数从低到高排序for (int d = 1; maxVal / d > 0; d *= 10) {countingSortByDigit(A, n, d);}
}
示例演示

对数组 [170, 45, 75, 90, 802, 24, 2, 66] 进行基数排序:

  1. 个位排序[170, 90, 802, 2, 24, 45, 75, 66]
  2. 十位排序[802, 2, 24, 45, 66, 170, 75, 90]
  3. 百位排序[2, 24, 45, 66, 75, 90, 170, 802]

3. 算法复杂度分析

3.1 查找算法复杂度对比

算法平均时间复杂度最坏时间复杂度适用场景
二分查找O(log n)O(log n)通用有序向量
插值查找O(log log n)O(n)均匀分布数据
斐波那契查找O(log n)O(log n)需要减少除法运算

3.2 排序算法复杂度对比

算法时间复杂度空间复杂度稳定性
冒泡排序O(n²)O(1)稳定
归并排序O(n log n)O(n)稳定
基数排序O(d·n)O(n)稳定

3.3 黄金比例与算法优化

斐波那契数列相邻项的比值趋近于黄金比例 φ = (1+√5)/2 ≈ 1.618,这种特性使得斐波那契查找在分割区间时能够达到接近最优的效果。

总结

本文详细介绍了三种重要的查找算法(二分查找、插值查找、斐波那契查找)和三种排序算法(冒泡排序、归并排序、基数排序)的原理、实现和复杂度分析。每种算法都有其适用的场景和优缺点:

  • 查找算法:根据数据分布特性选择合适的算法
  • 排序算法:根据稳定性要求和数据规模选择合适的方法
    理解这些基础算法的原理和实现,对于编写高效的程序和解决实际问题具有重要意义。
http://www.dtcms.com/a/540354.html

相关文章:

  • @pytest.fixture函数怎么传变量参数
  • Excel高性能异步导出完整方案!
  • 网站正在建设 敬请期待免费的cms模板
  • 输电线路绝缘子缺陷检测图像数据集VOC+YOLO格式1578张3类别
  • 跨文化理解的困境与AI大模型作为“超级第三方“的桥梁作用
  • JDK版本管理工具JVMS
  • 【JUnit实战3_18】第十章:用 Maven 3 运行 JUnit 测试(上)
  • SQLite 核心知识点讲解
  • JAiRouter v1.1.0 发布:把“API 调没调通”从 10 分钟压缩到 10 秒
  • 自建网站如何赚钱c2c模式为消费者提供了便利和实惠
  • Lua-编译,执行和错误
  • Lua与LuaJIT的安装与使用
  • 数独生成题目lua脚本
  • 影响网站加载速度wordpress获得当前文章的相关文章
  • Hive 技术深度解析与 P7 数据分析架构师多行业全场景实战课程合集(视频教程)
  • 嘉兴高端网站建设公司网络安全等级保护
  • HOW - localstorage 超时管理方案
  • java如何判断上传文件的类型,不要用后缀名判断
  • 【Linux】系统备份与恢复:rsync 与 tar 的完整使用教程
  • ROS2系列(3):第一个C++节点
  • zookeeper是什么
  • 构建“全链路解决方案”:解决集团化医院信创的三重难题
  • 网站建设区别广安市邻水建设局网站
  • 网站中的文字滑动怎么做化妆品网站建设策略
  • 【Netty4核心原理⑮】【Netty 编解码的艺术】
  • PHP-Casbin 在分布式服务中利用 Watcher 做策略同步
  • OCP考试必须培训吗?费用多少?
  • SpringBoot + 百度内容安全实战:自定义注解 + AOP 实现统一内容审核(支持文本 / 图片 / 视频 + 白名单 + 动态开关)
  • 心智结构与组织学习
  • NAS 私有云零信任部署:cpolar 加密访问 + 本地存储,破解安全与便捷难题