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

数据结构5.(哈希表及数据的排序和查找算法)

1.哈希算法

        将数据通过哈希算法映射成一个键值,存取都在同一位置实现数据的高效存储和查找,将时间复杂度尽可能降低至O(1),同样的参数返回同样的整数,不同的参数返回不同的整数

2. 哈希碰撞

        多个数据通过哈希算法得到的键值相同,称为产生哈希碰撞。优秀的哈希算法会尽可能避免哈希碰撞。

3.哈希表(散列存储)

        3.1哈希表的插入

int insert_hashtable(int tmpdata){int key = 0;linknode **pptmpnode = NULL;linknode *pnewnode = NULL;key = tmpdata % INDEX;for (pptmpnode = &phashtable[key]; *pptmpnode != NULL && 
(*pptmpnode)->data < tmpdata; pptmpnode = &(*pptmpnode)->pnext){} pnewnode = malloc(sizeof(linknode));if (NULL == pnewnode){perror("fail to malloc");return -1;}pnewnode->data = tmpdata;pnewnode->pnext = *pptmpnode;*pptmpnode = pnewnode;return 0;
}

        3.2哈希表的遍历

int show_hashtable(void){int i = 0;linknode *ptmpnode = NULL;for (i = 0; i < INDEX; i++){printf("%d:", i);ptmpnode = phashtable[i];while (ptmpnode != NULL){printf("%2d ", ptmpnode->data);ptmpnode = ptmpnode->pnext;}printf("\n");}return 0;}

4.排序算法

        4.1冒泡排序

                排序方法: 相邻的两个元素比较,大的向后走,小的向前走,循环找len-1个大的值

 int bubble_sort(int *parray, int len){int i = 0;int j = 0;int tmp = 0;for (j = 0; j < len-1; j++){for (i = 0; i < len-1-j; i++){if (parray[i] > parray[i+1]){              tmp = parray[i];parray[i] = parray[i+1];parray[i+1] = tmp;}}}return 0;}

        4.2选择排序

                排序方法: 从前到后找最小值与前面的元素交换 找到len-1个最小值,最后一个最大值即排序完成。

 int select_sort(int *parray, int len){int i = 0;int j = 0;int tmp = 0;int min = 0;for (j = 0; j < len-1; j++){min = j;for (i = j+1; i < len; i++){if (parray[i] < parray[min]){min = i;}}if (min != j){tmp = parray[min];parray[min] = parray[j];parray[j] = tmp;}}return 0;}

        4.3插入排序

                比冒泡排序、选择排序更高效(实际移动次数更少),适用于小规模数据或近乎有序的数组(效率接近线性)。

原理:假设对数组 [5, 2, 4, 6, 1, 3] 进行升序排序:

  1. 初始已排序部分:[5],未排序部分:[2, 4, 6, 1, 3]

  2. 插入 2[2, 5]5 向后移动)。

  3. 插入 4[2, 4, 5]5 向后移动)。

  4. 插入 6:直接放到末尾 → [2, 4, 5, 6]

  5. 插入 1:需移动到最前 → [1, 2, 4, 5, 6](所有元素后移)。

  6. 插入 3:放到 2 和 4 之间 → [1, 2, 3, 4, 5, 6]

int insert_sort(int *parray, int len){int tmp = 0;int i = 0;int j = 0;for (j = 1; j < len; j++){tmp = parray[j];for (i = j; i > 0 && tmp < parray[i-1]; i--){parray[i] = parray[i-1];}parray[i] = tmp;}return 0;}

        4.4希尔排序

        希尔排序是 插入排序的改进版,通过将数组分成多个子序列进行插入排序,逐步缩小子序列的间隔(step),最终使整个数组基本有序,最后进行一次标准的插入排序。

        算法思想:

  1. 分组插入排序:选择一个递减的间隔序列(step),将数组分成若干子序列,对每个子序列进行插入排序。

  2. 逐步缩小间隔:随着step 的减小,子序列越来越接近整个数组,最终 step=1 时,相当于一次标准的插入排序,此时数组已经基本有序,排序效率高。

        步骤:

  1. 选择一个初始间隔序列(如 step = n/2, step /= 2, ... 直到 step = 1)。

  2. 对每个 step,将数组分成 step 个子序列,每个子序列进行插入排序。

  3. 重复缩小 step,直到 step = 1,最后进行一次标准插入排序。

       示例

      假设数组 [8, 3, 1, 2, 7, 5, 6, 4],初始 gap = 4

  1. gap=4:分成 4 个子序列 [8,7], [3,5], [1,6], [2,4],分别排序 → [7,3,1,2,8,5,6,4]

  2. gap=2:分成 2 个子序列 [7,1,8,6], [3,2,5,4],分别排序 → [1,2,6,3,7,4,8,5]

  3. gap=1:标准插入排序 → [1,2,3,4,5,6,7,8]

 //希尔排序int shell_sort(int *parray, int len){int step = 0;int j = 0;int i = 0;int tmp = 0;for (step = len/2; step > 0; step /= 2){for (j = step; j < len; j++){tmp = parray[j];for (i = j; i >= step && tmp < parray[i-step]; i -= step){parray[i] = parray[i-step];}parray[i] = tmp;}}return 0;}

        4.5快速排序

                快速排序是一种 分治算法,通过选择一个键值,将数组分成两部分,左边小于键值,右边大于键值,然后递归排序左右两部分。

 算法思想:

  1. 选择键值:通常选第一个、最后一个或随机元素。

  2. 分区

    • 将小于键值 的元素移到左边,大于键值的移到右边。

    • 最终键值位于正确的位置。

  3. 递归排序:对左右子数组重复上述过程,直到子数组长度为 1。

 步骤:

  1. 选择键值(如 arr[high])。

  2. 初始化指针 i(指向小于 键值 的最后一个元素)。

  3. 遍历数组

    • 如果 arr[j] < 键值,交换 arr[i+1] 和 arr[j],并 i++

  4. 交换 pivot 到正确位置 i+1

  5. 递归排序 左右子数组。

 示例:

       对数组 [5, 3, 8, 4, 2, 7, 1, 10] 进行排序(选择 5 作为 键值):

初始:

pivot = 5
[5, 3, 8, 4, 2, 7, 1, 10]↑i                   ↑j

  i 向右找 >5 的元素(8),j 向左找 <5 的元素(1),交换 8 和 1。

[5, 3, 1, 4, 2, 7, 8, 10]↑i     ↑j

  i 继续右移找到 7j 左移找到 2,交换:

[5, 3, 1, 4, 2, 7, 8, 10]↑j ↑i

      此时 i > j,循环终止,交换 pivot 和 arr[j]

[2, 3, 1, 4, 5, 7, 8, 10]

        继续递归调用:左子数组 [2, 3, 1, 4](选 2 为 pivot),右子数组 [7, 8, 10](选 7 为 pivot)

1

5.查找算法

        5.1折半查找(二分查找)

二分查找(折半查找)是一种高效的 有序数组查找算法,它通过 逐步缩小搜索范围 来快速定位目标值。其核心思想是 “分而治之”,每次比较后排除一半的无效数据。

核心思想

  1. 前提条件:数组必须是有序的(升序或降序)。

  2. 查找过程

    每次取数组的 中间元素 与目标值比较。如果中间元素等于目标值,直接返回位置。如果目标值 小于 中间元素,则在 左半部分 继续查找。如果目标值 大于 中间元素,则在 右半部分 继续查找。找到目标值或搜索范围为空(未找到)则终止。

示例

假设有序数组 [1, 3, 5, 7, 9, 11],查找 target = 7

  1. 初始范围low = 0high = 5

    • mid = 2arr[2] = 5 < 7 → 搜索右半部分,low = 3

  2. 新范围[7, 9, 11]low = 3high = 5)。

    • mid = 4arr[4] = 9 > 7 → 搜索左半部分,high = 3

  3. 最终比较low = 3high = 3

    • mid = 3arr[3] = 7 == target → 返回 3

http://www.dtcms.com/a/323043.html

相关文章:

  • GPT-5的4个缺点
  • 数据结构初阶(7)树 二叉树
  • 使用qemu运行与GDB调试内核
  • 解决python错误:playwright._impl._errors.TimeoutError: Timeout 30000ms exceeded.
  • STM32——时钟系统
  • BMS三大领域:电池、楼宇与业务管理系统解析
  • STranslate(翻译OCR工具) v1.5.4.801绿色版,屏幕文字秒译,OCR识别零门槛
  • C++ unordered_map 和 unordered_set 的使用
  • 神经网络-local minima and saddle point
  • 【linux基础】Linux目录和Windows目录的区别
  • ACF插件编辑器无法插入相册的原因及解决方案
  • 黑马点评07 - 附近商户/用户签到/UV统计
  • 【Python 高频 API 速学 ⑦ · 完结篇】
  • CrystalDiskInfo 9.0.1 安装教程 - 硬盘检测工具下载安装步骤详解
  • 【智能穿戴设备】2025智能穿戴隐私危机:数据安全保障技术深度剖析
  • RecyclerView 中 ViewHolder
  • C# OnnxRuntime yolov8 纸箱检测
  • 动态规划(相同地方不同状态)
  • 如何控制需求交付节奏
  • 【数据分析】03 - pandas
  • 深入解析QUIC协议:下一代音视频传输技术的突破与实践
  • 前端如何安全存储 API 密钥 —— 两种实用方案
  • 动手学深度学习(pytorch版):第二章节——预备知识(1)——数据操作
  • pytorch llm 计算flops和参数量
  • 【C++】继承机制全解析
  • Spring-rabbit使用实战七
  • 48伏电气系统—— 铺就电动出行之路的关键技术
  • 大语言模型中的幻觉
  • 24SpringCloud黑马商城微服务整合Seata重启服务报错的解决办法
  • 使用SymPy lambdify处理齐次矩阵的高效向量化计算