C/C++ 常用的四种查找算法

在计算机科学中,搜索算法是一种用于在数据集合中查找特定元素的算法。C语言作为一种强大的编程语言,提供了多种搜索算法的实现方式。本文将介绍C语言中的四种常见搜索算法其中包括(线性查找,二分法查找,树结构查找,分块查找),并提供每种算法的简单实现示例。

常见的查找算法主要有以下几种:

  1. 线性查找(Linear Search):
    • 简单直观,适用于无序列表。
    • 从列表的一端开始逐个元素比较,直到找到目标元素或遍历完整个列表。
  2. 二分查找(Binary Search):
    • 适用于有序列表。
    • 每次将目标值与中间元素比较,可以迅速缩小搜索范围。
  3. 树结构查找(树的各种形式,如二叉搜索树、AVL树、红黑树等):
    • 通过树结构,可以更加高效地进行查找、插入和删除操作。
    • 二叉搜索树要求左子树上所有结点的值小于根结点的值,右子树上所有结点的值大于根结点的值。
  4. 分块查找(Block Search):
    • 将数据分成若干块,每一块中的元素无序,但块与块之间有序。
    • 先确定目标元素所在的块,再在块内进行线性查找。

这些查找算法各自有适用的场景和优势,选择合适的查找算法取决于数据的特性以及实际应用的需求。

线性查找(Linear Search)

线性搜索,又称为顺序搜索(Sequential Search),是一种简单直观的查找算法。该算法通过顺序遍历数据集,逐一比较每个元素与目标值是否相等,直到找到目标值或遍历完整个数据集。

算法步骤

  1. 从头到尾遍历数据集: 从数据集的第一个元素开始,依次比较每个元素与目标值是否相等。
  2. 比较目标值: 对于每个元素,与目标值进行比较。
  3. 找到目标值: 如果找到了与目标值相等的元素,返回该元素的位置或索引。
  4. 遍历完整个数据集: 如果遍历完整个数据集仍未找到目标值,返回未找到的标记(通常是一个特殊值,如-1)。

特点

  1. 适用于小型数据集: 线性搜索适用于小型数据集,对于大型数据集可能效率较低。
  2. 无序数据: 不依赖数据的排列顺序,适用于无序数据。
  3. 简单直观: 实现简单,易于理解。

线性搜索是最简单的搜索算法之一,它按顺序遍历数据集合,查找目标元素。以下是一个线性搜索的C语言示例:

#include <stdio.h>int linearSearch(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 argc, char *argv[])
{int arr[] = {1, 2, 3, 4, 5};int n = sizeof(arr) / sizeof(arr[0]);int target = 3;int result = linearSearch(arr, n, target);if (result != -1){printf("元素在索引 %d 处找到\n", result);} else{printf("未找到元素\n");}return 0;
}

二分查找(Binary Search)

二分搜索(Binary Search)是一种在有序数组中查找目标值的算法。它通过反复将查找范围划分为两半并比较目标值与中间元素的大小,从而缩小搜索范围,直到找到目标值或确定目标值不存在。

算法步骤

  1. 初始化: 确定搜索范围的起始点 left 和终止点 right
  2. 循环条件:left 小于等于 right 时执行循环。
  3. 计算中间位置: 计算中间位置 midmid = (left + right) / 2
  4. 比较目标值: 将目标值与中间元素进行比较。
    • 如果目标值等于中间元素,找到目标,返回索引。
    • 如果目标值小于中间元素,说明目标值在左半部分,更新 right = mid - 1
    • 如果目标值大于中间元素,说明目标值在右半部分,更新 left = mid + 1
  5. 循环结束:left 大于 right,表示搜索范围为空,未找到目标值。

特点

  1. 有序数组: 二分搜索要求数组是有序的,以便通过比较中间元素确定目标值在哪一半。
  2. 高效性: 由于每一步都将搜索范围缩小一半,因此二分搜索的平均时间复杂度为 O(log n)。
  3. 适用性: 适用于静态数据集或很少变化的数据集,不适用于频繁插入、删除操作的动态数据集。

二分搜索要求数据集合是有序的,以下是一个二分搜索的C语言示例:

#include <stdio.h>int binary_search(int key, int a[], int n)
{int low, high, mid, count = 0, count1 = 0;low = 0;high = n - 1;while (low<high){count++;                    // 记录查找次数mid = (low + high) / 2;     // 求出中间位置if (key<a[mid])             // 当key小于中间值high = mid - 1;         // 确定左子表范围else if (key>a[mid])        // 当key大于中间值low = mid + 1;          // 确定右子表范围else if (key == a[mid])     // 当key等于中间值证明查找成功{printf("查找元素: %d Array[%d]=%d\n", count, mid, key);count1++;            //count1记录查找成功次数break;}}if (count1 == 0)return 0;
}int main(int argc, char *argv[])
{int number = 10, key = 6;int Array[10] = { 1, 5, 6, 7, 9, 3, 4, 6, 0, 2 };binary_search(key, Array, number);return 0;
}

二叉搜索树 (BST)

二叉搜索树(Binary Search Tree,BST)是一种二叉树数据结构,其中每个节点都有一个键值,且满足以下性质:

  1. 对于树中的每个节点,其左子树中的所有节点的键值都小于该节点的键值。
  2. 对于树中的每个节点,其右子树中的所有节点的键值都大于该节点的键值。
  3. 左、右子树也分别为二叉搜索树。

这个性质使得在二叉搜索树中可以高效地进行搜索、插入和删除操作。

特点

  1. 有序性: 由于BST的定义,其中的元素是有序排列的。对于任意节点,其左子树的值小于该节点,右子树的值大于该节点,因此通过中序遍历BST可以得到有序的元素序列。
  2. 高效的搜索操作: 由于有序性,可以通过比较键值快速定位目标节点,使搜索操作的平均时间复杂度为 O(log n)。在最坏情况下(树退化为链表),搜索的时间复杂度为 O(n)。
  3. 高效的插入和删除操作: 插入和删除操作也涉及到比较键值和调整树的结构,平均情况下的时间复杂度为 O(log n)。在最坏情况下,树可能变得不平衡,导致时间复杂度为 O(n),但通过平衡二叉搜索树(如 AVL 树、红黑树等)可以保持树的平衡。

操作

  1. 搜索(Search): 从根节点开始比较目标值,根据比较结果选择左子树或右子树,直到找到目标节点或达到叶子节点。
  2. 插入(Insert): 从根节点开始,按照比较结果选择左子树或右子树,直到找到合适的插入位置,插入新节点。
  3. 删除(Delete): 找到要删除的节点,可能有以下几种情况:
    • 若该节点为叶子节点,直接删除。
    • 若该节点有一个子节点,用子节点替代该节点。
    • 若该节点有两个子节点,找到右子树中的最小节点或左子树中的最大节点,替代该节点,并递归删除被替代的节点。

以下是一个简化的BST的C语言示例:

#include <stdio.h>
#include <stdlib.h>struct Node
{int key;struct Node *left, *right;
};struct Node* newNode(int key)
{struct Node* node = (struct Node*)malloc(sizeof(struct Node));node->key = key;node->left = node->right = NULL;return node;
}struct Node* insert(struct Node* root, int key)
{if (root == NULL)return newNode(key);if (key < root->key)root->left = insert(root->left, key);else if (key > root->key)root->right = insert(root->right, key);return root;
}int main(int argc, char *argv[])
{struct Node* root = NULL;int keys[] = {3, 1, 5, 2, 4};for (int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++){root = insert(root, keys[i]);}// 可以在 'root' 上执行BST操作return 0;
}

分块查找(Block Search)

分块搜索(Block Search)是一种在查找大量数据中的目标值时,将数据分成若干块,然后在块内进行查找的策略。这种方法适用于一些动态更新频繁,但每次更新数据量较小的场景。

算法步骤

  1. 数据分块: 将大量数据按照一定的规则分成若干块。
  2. 建立索引表: 对每个块建立索引,记录每块的起始位置、结束位置和关键字(通常是块内最大的关键字)。
  3. 查找块: 根据目标值的大小确定它可能在哪个块中,找到相应的块。
  4. 在块内查找: 在确定的块内使用线性查找或其他查找算法寻找目标值。

特点

  1. 适用于动态数据: 分块搜索适用于数据集动态更新的情况,因为每次更新数据只需更新相应块的索引。
  2. 索引表: 建立索引表有助于快速定位目标值可能存在的块,提高查找效率。
  3. 非均匀分块: 可以根据数据的特点进行非均匀分块,以适应不同数据分布情况。

该查找与二分查找类似,都是对半分,分块则可以分为多块,效率更高一些。如下这段C语言代码实现了分块查找算法。分块查找是一种基于块的数据结构的搜索算法,通过将数据集划分为若干块(或称为块),并为每个块建立一个索引。每个索引记录了该块的起始位置、结束位置以及该块内元素的最大值。

#include <stdio.h>struct index           //定义块的结构
{int key;int start;int end;
}index_table[4];       //定义结构体数组int block_search(int key, int a[])          //自定义实现分块查找
{int i, j;i = 1;while (i <= 3 && key>index_table[i].key)      //确定在哪个块中i++;if (i>3)                                  //大于分得的块数,则返回0return 0;j = index_table[i].start;                  //j等于块范围的起始值while (j <= index_table[i].end&&a[j] != key)  //在确定的块内进行查找j++;if (j>index_table[i].end)    //如果大于块范围的结束值,则说明没有要查找的数j = 0;return j;
}int main(int argc, char *argv[])
{int x, y = 0,ref = 0;int key = 8;int Array[16] = { 1, 3, 4, 5, 6, 7, 8, 9, 0, 4, 3, 5, 6, 7, 8, 9 };for (x = 1; x <= 3; x++){index_table[x].start = y + 1;       // 确定每个范围的起始行y = y + 1;index_table[x].end = y + 4;         // 确定每个块范围的结束值y = y + 4;index_table[x].key = Array[y];      // 确定每个块范围中元素的最大值}ref = block_search(key, Array);if (ref != 0){printf("position is: %d \n", ref);}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/181424.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【电路笔记】-电阻串联

电阻串联 文章目录 电阻串联1、概述2、电阻串联3、串联电阻电压4、电阻串联示例15、分压电路6、电阻串联示例27、电阻串联的应用8、总结 当电阻器以菊花链方式连接在一条线上时&#xff0c;电阻器被称为串联连接&#xff0c;从而导致共同电流流过它们。 1、概述 各个电阻器可以…

刷题感悟w

题目很长的一定要慢慢把题目的意思搞清楚 有重复操作不知道怎么办 可以用数组去标记 你好&#xff01;在C中&#xff0c;replace 函数通常是用于替换容器&#xff08;例如 std::vector 或 std::string&#xff09;中的特定元素的函数。以下是 std::replace 函数的一般用法&…

vue3中的Fragment、Teleport、Suspense新组件

Fragment组件 在Vue2中: 组件必须有一个根标签 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中 好处: 减少标签层级, 减小内存占用 <template><div style"font-size: 14px;"><p> 组件可以没有根标签</p&g…

ubuntu22.04新机使用(换源,下载软件,安装显卡驱动,锁屏长亮)

换源 国内有很多Ubuntu的镜像源&#xff0c;包括阿里的、网易的&#xff0c;还有很多教育网的源&#xff0c;比如&#xff1a;清华源、中科大源。推荐使用中科大源&#xff0c;快得很。 /etc/apt/sources.list编辑/etc/apt/sources.list文件, 在文件最前面添加以下条目(操作前…

【Vue】绝了!还有不懂生命周期的?

生命周期 Vue.js 组件生命周期&#xff1a; 生命周期函数&#xff08;钩子&#xff09;就是给我们提供了一些特定的时刻&#xff0c;让我们可以在这个周期段内加入自己的代码&#xff0c;做一些需要的事情; 生命周期钩子中的this指向是VM 或 组件实例对象 在JS 中&#xff0c;…

Update this scope and remove the “systemPath“

问题 解析&#xff1a; 在特定的指定路径上查找系统相关性。这大大降低了可移植性&#xff0c;因为如果您将工件部署在一个与您的环境不同的环境中&#xff0c;代码将无法工作。 解决&#xff1a; 1 使用官方maven仓库的第三方jar包 2 如果官方仓库不存在jar包&#xff0c;…

模拟退火算法应用——求解TSP问题

仅作自己学习使用 一、问题 旅行商问题(TSP) 是要求从一个城市出发&#xff0c;依次访问研究区所有的城市&#xff0c;并且只访问一次不能走回头路&#xff0c;最后回到起点&#xff0c;求一个使得总的周游路径最短的城市访问顺序。 采用模拟退火算法求解TSP问题&#x…

接口测试【加密解密攻防完整版】实战教程详解

一、对称加密 对称加密算法是共享密钥加密算法&#xff0c;在加密解密过程中&#xff0c;使用的密钥只有一个。发送和接收双方事先都知道加密的密钥&#xff0c;均使用这个密钥对数据进行加密和解密。 数据加密&#xff1a;在对称加密算法中&#xff0c;数据发送方将明文 (原…

【JavaScript】3.3 JavaScript工具和库

文章目录 1. 包管理器2. 构建工具3. 测试框架4. JavaScript 库总结 在你的 JavaScript 开发之旅中&#xff0c;会遇到许多工具和库。这些工具和库可以帮助你更有效地编写和管理代码&#xff0c;提高工作效率。在本章节中&#xff0c;我们将探讨一些常见的 JavaScript 工具和库&…

linux安装minIo(亲测可用)

一、创建文件夹 进入opt文件夹 cd /opt/创建minio文件夹&#xff1b; mkdir minio赋予权限 chmod 777 minio/执行完后查看目录 进到minio文件夹 创建bin目录 mkdir bin创建data目录 mkdir data创建log touch minio.log创建start.sh文件&#xff0c;并写入数据(不会vi或…

微信公众号扫码授权登录源码 / PHP微信扫码关注公众号并授权登录源码

源码简介&#xff1a; 在当今的互联网时代&#xff0c;微信公众号已成为众多企业与用户之间进行交流和沟通的重要工具&#xff0c;其中包括用户的登录认证。通过关注公众号登录&#xff0c;不仅可以为公众号带来流量&#xff0c;还能够实现用户与公众号粉丝之间的一一对应关系…

数据治理模型的三个模块

数据接入模块 大数据工程的数据来源包含企业内部数据和企业外部数据&#xff0c;其中企业内部数据由资源服务平台、综合资源库、各业务系统生产库中的结构化数据和文件服务器上的文本、图片等非结构化数据组成&#xff0c;其中包括人财物记录、财物报表、原材料、顾客信息、气…

ts中的类型定义的详细使用教程

文章目录 前言原始数据类型&#xff08;Primitive data types&#xff09;特殊数据类型断言尖括号断言&#xff08;Angle Bracket Syntax&#xff09;as 语法断言类型断言函数 泛型数据容器数据类型转换工具函数接口定义 & 和 | 的用法&| 后言 前言 hello world欢迎来到…

Java之函数式接口

1、函数式接口概述 函数式接口: 有且仅有一个抽象方法的接口。Java中的函数式编程体现就是Lambda表达式。所以函数式接口即可以适用于Lambda使用的接口。如何检测一个接口是不是函数式接口? @FunctionalInterface放在接口定义的上方:如果接口是函数式接口,编译通过;如果不…

【SpringBoot篇】登录校验 — JWT令牌

文章目录 &#x1f339;简述JWT令牌⭐JWT特点 &#x1f33a;JWT使用流程&#x1f6f8;JWT令牌代码实现&#x1f354;JWT应用 &#x1f339;简述JWT令牌 JWT全称为JSON Web Token&#xff0c;是一种用于身份验证的开放标准。它是一个基于JSON格式的安全令牌&#xff0c;主要用于…

跨越威胁的传说:揭秘Web安全的七大恶魔

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

CVE-2022-4886 ingress命令注入复现与分析

安装 安装ingress-nginx wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.4/deploy/static/provider/cloud/deploy.yamlk apply -f deploy.yaml 原理 nginx.ingress.kubernetes.io/rewrite-target标签会在nginx配置进行插入字符串&#…

Linux - 动静态库(下篇)

前言 在上篇博客当中&#xff0c;对静态库是什么&#xff0c;怎么使用&#xff0c;简单实现自己的静态库&#xff0c;这些做了描述&#xff0c;具体请看上篇博客&#xff1a; 本篇博客将会对 动态库是什么&#xff0c;怎么使用&#xff0c;简单实现自己的动态库&#xff0c…

ESP32-Web-Server 实战编程-使用文件系统建立强大的 web 系统

ESP32-Web-Server 实战编程-使用文件系统建立强大的 web 系统 概述 在前述章节我们讲述了在网页端控制多个 GPIO 的案例。当程序开始变得复杂&#xff0c;让一些功能“自动起来”是一个好的选择。 在前面的示例中&#xff0c;我们需要在后端为每个前端代码的 URL 指定一个对…

Android RecyclerView分析 第一篇【ChildHelper】

一、在RecyclerView中的位置与角色 在RecyclerView对象创建时&#xff0c;会创建一个 ChildHelper 对象。 在设置layoutManager时&#xff0c;将 RecyclerView中的成员变量 mChildHelper 传进 layoutManager中。 ChildHelper 封装了对 RecyclerView所有子View的所有操作。包括…