查找算法

本文详细介绍了数据查找的各种方法,包括线性表查找(顺序查找、折半查找)、树表查找(二叉树查找)、散列表查找等,并通过示例代码进行了解释。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.概念

查找就是在某种数据结构形式存储的数据集合中,找出满足指定条件的结点,若查找成功,给出记录信息或者记录在表中的位置,如果查找不成功,返回空

查找的三种方式

 1.线性表的查找

 (1) 顺序查找
原理: 从表的一端开始,逐个对记录和给定的关键字进行比较,如果找到一个记录与给定的记录一样,那么查找成功,如果没有一样的那么就查找失败
时间复杂性:O(n)
优缺点:顺序查找的优点是算法简单,对表结构没有要求,不需要排序,缺点是平均查找长度较大,查找效率低
示例代码

public class OrderSearch {  
public static int orderSearch(int searchKey,int... array){  
        for(int i=0;i<array.length;i++){  
            if(array[i]==searchKey){  
                return i;  
            }  
        }  
        return -1;  

    }  
    /**测试查找结果 
     * @param args 
     */  
    public static void main(String[] args) {  
          int[] test=new int[]{1,2,29,3,95,3,5,6,7,9,12};//升序序列  
          int index=OrderSearch.orderSearch(95, test);  
          System.out.println("查找到的位置 :"+ index);    
    }  
}  

(2)折半查找
原理:假设查找表的元素存储在数组[1….n],首先将待查的key值与表中间位置上(下标为mid)的纪录的关键字进行比较,若相等,则查找成功,如果key>r[mid].key,那就说明待查记录在后半个子表r[mid+1….n],下一步应该在后半个子表中查找如果key

public class SplitFind {   
    /** 
     * @author hbliu 
     * @param arrayData 数组 
     * @param searchData 要查找的数据 
     * @param start 开始下标 
     * @param end 结束下标 
     * @return 数据在数组中下标的位置,如果数据不在数组中,返回 -1 
     * 功   能:折半查找  
     */  
    public static int splitHalf(int[] arrayData,int searchData,int start,int end){  
        int index = (start + end)/2;  
        int data = arrayData[index];  
        if(start > end ){  
            return -1;  
        }  
        if(data == searchData){  
            return index;  
        }else{  
            if(data < searchData){  
                return splitHalf(arrayData,searchData,index+1,end);  
            }else{  
                return splitHalf(arrayData,searchData,start,index-1);  
            }  
        }  
    }  

    /** 
     * @author hbliu 
     * @param args 
     */  
    public static void main(String[] args) {  
        int[] array = { 3,5,11,17,21,23,28,30,32,50};  
        System.out.println(array.length);  
        int isExist = splitHalf(array,(int)50,0,array.length - 1);  
        System.out.println("isExist : "+isExist);  
    }  

}  

2.树表的查找(动态查找)
(1)二叉树 是一种对排序和查找都很有用的特殊二叉树
二叉树的性质: 左子树一定小于它的根节点 右子树一定大于根节点
二叉树重要性质为中序遍历可以得到一个节点值递增的有序序列
查找原理:
(1)如果排序树为空,则查找失败,返回空
(2) 若二叉排序树非空,将给定的值key 与根节点进行比较
如果 key 等于,那就查找成功 返回根节点的地址
如果key 小于根节点那么就查找左子树
如果key 大于根节点,则进一步查找右节点子树
时间复杂度 O(log2n)

例子
public class BinarySortTree {  

    private Node root = null;  


    /**查找二叉排序树中是否有key值*/  
    public boolean searchBST(int key){  
        Node current = root;  
        while(current != null){  
            if(key == current.getValue())  
                return true;  
            else if(key < current.getValue())  
                current = current.getLeft();  
            else  
                current = current.getRight();  
        }  
        return false;  
    }  


    /**向二叉排序树中插入结点*/  
    public void insertBST(int key){  
        Node p = root;  
        /**记录查找结点的前一个结点*/  
        Node prev = null;  
        /**一直查找下去,直到到达满足条件的结点位置*/  
        while(p != null){  
            prev = p;  
            if(key < p.getValue())  
                p = p.getLeft();  
            else if(key > p.getValue())  
                p = p.getRight();  
            else  
                return;  
        }  
        /**prve是要安放结点的父节点,根据结点值得大小,放在相应的位置*/  
        if(root == null)  
            root = new Node(key);  
        else if(key < prev.getValue())  
            prev.setLeft(new Node(key));  
        else prev.setRight(new Node(key));  
    }  



    /** 
     * 删除二叉排序树中的结点 
     * 分为三种情况:(删除结点为*p ,其父结点为*f) 
     * (1)要删除的*p结点是叶子结点,只需要修改它的双亲结点的指针为空 
     * (2)若*p只有左子树或者只有右子树,直接让左子树/右子树代替*p 
     * (3)若*p既有左子树,又有右子树 
     *      用p左子树中最大的那个值(即最右端S)代替P,删除s,重接其左子树 
     * */  
    public void deleteBST(int key){  
        deleteBST(root, key);  
    }  
    private boolean deleteBST(Node node, int key) {  
        if(node == null) return false;  
        else{  
            if(key == node.getValue()){  
                return delete(node);  
            }  
            else if(key < node.getValue()){  
                return deleteBST(node.getLeft(), key);  
            }  
            else{  
                return deleteBST(node.getRight(), key);  
            }  
        }  
    }  

    private boolean delete(Node node) {  
        Node temp = null;  
        /**右子树空,只需要重接它的左子树 
         * 如果是叶子结点,在这里也把叶子结点删除了 
         * */  
        if(node.getRight() == null){  
            temp = node;  
            node = node.getLeft();  
        }  
        /**左子树空, 重接它的右子树*/  
        else if(node.getLeft() == null){  
            temp = node;  
            node = node.getRight();  
        }  
        /**左右子树均不为空*/  
        else{  
            temp = node;  
            Node s = node;  
            /**转向左子树,然后向右走到“尽头”*/  
            s = s.getLeft();  
            while(s.getRight() != null){  
                temp = s;  
                s = s.getRight();  
            }  
            node.setValue(s.getValue());  
            if(temp != node){  
                temp.setRight(s.getLeft());  
            }  
            else{  
                temp.setLeft(s.getLeft());  
            }  
        }  
        return true;  
    }  


    /**中序非递归遍历二叉树 
     * 获得有序序列 
     * */  
    public void nrInOrderTraverse(){  
        Stack<Node> stack = new Stack<Node>();  
        Node node = root;  
        while(node != null || !stack.isEmpty()){  
            while(node != null){  
                stack.push(node);  
                node = node.getLeft();  
            }  
            node = stack.pop();  
            System.out.println(node.getValue());  
            node = node.getRight();  
        }  
    }  

    public static void main(String[] args){  
        BinarySortTree bst = new BinarySortTree();  
        /**构建的二叉树没有相同元素*/  
        int[] num = {4,7,2,1,10,6,9,3,8,11,2, 0, -2};  
        for(int i = 0; i < num.length; i++){  
            bst.insertBST(num[i]);  
        }  
        bst.nrInOrderTraverse();  
        System.out.println(bst.searchBST(10));  
        bst.deleteBST(2);  
        bst.nrInOrderTraverse();  
    }  


    /**二叉树的结点定义*/  
    public class Node{  
        private int value;  
        private Node left;  
        private Node right;  

        public Node(){  
        }  
        public Node(Node left, Node right, int value){  
            this.left = left;  
            this.right = right;  
            this.value = value;  
        }  
        public Node(int value){  
            this(null, null, value);  
        }  

        public Node getLeft(){  
            return this.left;  
        }  
        public void setLeft(Node left){  
            this.left = left;  
        }  
        public Node getRight(){  
            return this.right;  
        }  
        public void setRight(Node right){  
            this.right = right;  
        }  
        public int getValue(){  
            return this.value;  
        }  
        public void setValue(int value){  
            this.value = value;  
        }  
    }  

}  

树的查找还分B+树的查找和B-树的查找 此处略过

散列表的查找方法
散列表的基本思想:通过对元素的关键字值进行某种运算,直接求出元素的地址,即用关键字到地址的直接转换的方法
概念:
散列函数和散列地址:在记录的存储地址p和其关键字key之间建立一个确定的对应关系H 使得p=H(key),称这个对应关系H为散列函数,P为散列地址
散列表:一个有限连续的地址空间,通常散列表的存储空间就是一个一维数组,散列地址就是数组的下标
冲突和同义词: 对不同的关键字可能得到同一个散列地址 就是 key1!=key2 但是H(key1)==H(key2)

构造散列函数的几种方法
数字分析法: 如果每个关键字的位数比散列表的地址码多,每个关键字由n位数组成,如 k1k2k3k4,那么可以从关键字中提取数字分别均匀的几位或者若干位作为散列地址
平方取中法: 一个数平方后的中间几位和数的每一位都是相关的,如果取关键字平方后的中间几位作为散列地址,那么散列地址就是随机的
折叠法:将关键字分割成位数相同的几部分,取这几部分进行舍位相加。
除留余数法: 假关键m设散列表表长,选择一个不大于m的数p 用P去除关键字 除后余数为散列地址 一般取p为表长的最大的质数。
H(key)=key%p

示例代码
package 散列表;  

import java.util.Random;  



public class HashProcess {  

    public static void main(String[] args) {  
        int[] arr = new int[10];  
        int[] hashTable = new int[arr.length*2+1];  
        Random random = new Random();  
        for(int i=0 ; i<arr.length ; i++){  

            arr[i] = random.nextInt(10)%10+10;  
        }  
        for(int a : arr){  
            InsertHash(hashTable,a);  
            System.out.print(a + " ");  
        }  

        System.out.println(SearchHash(arr[6],hashTable.length,hashTable));  

    }  



    private static boolean SearchHash(int a,int len,int[] ht) {  
        int addr = Hash(a,len);  
        while(ht[addr] != a){  
            addr = (addr+1)%len;  
            if(ht[addr] == 0 || addr == Hash(a,len)){  
                return false;  
            }  
        }  
        return true;  
    }  



    private static void InsertHash(int[] hashTable, int a) {  
        int len = hashTable.length;  
        int addr = Hash(a,len);  
        while(hashTable[addr] != 0){  
            addr = (addr+1)%len;  
        }  
        hashTable[addr] = a;  
    }  

    private static int Hash(int a,int len) {  
        return a%len;     
    }  

}  
标题基于SpringBoot+Vue的学生交流互助平台研究AI更换标题第1章引言介绍学生交流互助平台的研究背景、意义、现状、方法与创新点。1.1研究背景与意义分析学生交流互助平台在当前教育环境下的需求及其重要性。1.2国内外研究现状综述国内外在学生交流互助平台方面的研究进展与实践应用。1.3研究方法与创新点概述本研究采用的方法论、技术路线及预期的创新成果。第2章相关理论阐述SpringBoot与Vue框架的理论基础及在学生交流互助平台中的应用。2.1SpringBoot框架概述介绍SpringBoot框架的核心思想、特点及优势。2.2Vue框架概述阐述Vue框架的基本原理、组件化开发思想及与前端的交互机制。2.3SpringBoot与Vue的整合应用探讨SpringBoot与Vue在学生交流互助平台中的整合方式及优势。第3章平台需求分析深入分析学生交流互助平台的功能需求、非功能需求及用户体验要求。3.1功能需求分析详细阐述平台的各项功能需求,如用户管理、信息交流、互助学习等。3.2非功能需求分析对平台的性能、安全性、可扩展性等非功能需求进行分析。3.3用户体验要求从用户角度出发,提出平台在易用性、美观性等方面的要求。第4章平台设计与实现具体描述学生交流互助平台的架构设计、功能实现及前后端交互细节。4.1平台架构设计给出平台的整体架构设计,包括前后端分离、微服务架构等思想的应用。4.2功能模块实现详细阐述各个功能模块的实现过程,如用户登录注册、信息发布与查看、在线交流等。4.3前后端交互细节介绍前后端数据交互的方式、接口设计及数据传输过程中的安全问题。第5章平台测试与优化对平台进行全面的测试,发现并解决潜在问题,同时进行优化以提高性能。5.1测试环境与方案介绍测试环境的搭建及所采用的测试方案,包括单元测试、集成测试等。5.2测试结果分析对测试结果进行详细分析,找出问题的根源并
内容概要:本文详细介绍了一个基于灰狼优化算法(GWO)优化的卷积双向长短期记忆神经网络(CNN-BiLSTM)融合注意力机制的多变量多步时间序列预测项目。该项目旨在解决传统时序预测方法难以捕捉非线性、复杂时序依赖关系的问题,通过融合CNN的空间特征提取、BiLSTM的时序建模能力及注意力机制的动态权重调节能力,实现对多变量多步时间序列的精准预测。项目不仅涵盖了数据预处理、模型构建与训练、性能评估,还包括了GUI界面的设计与实现。此外,文章还讨论了模型的部署、应用领域及其未来改进方向。 适合人群:具备一定编程基础,特别是对深度学习、时间序列预测及优化算法有一定了解的研发人员和数据科学家。 使用场景及目标:①用于智能电网负荷预测、金融市场多资产价格预测、环境气象多参数预报、智能制造设备状态监测与预测维护、交通流量预测与智慧交通管理、医疗健康多指标预测等领域;②提升多变量多步时间序列预测精度,优化资源调度和风险管控;③实现自动化超参数优化,降低人工调参成本,提高模型训练效率;④增强模型对复杂时序数据特征的学习能力,促进智能决策支持应用。 阅读建议:此资源不仅提供了详细的代码实现和模型架构解析,还深入探讨了模型优化和实际应用中的挑战与解决方案。因此,在学习过程中,建议结合理论与实践,逐步理解各个模块的功能和实现细节,并尝试在自己的项目中应用这些技术和方法。同时,注意数据预处理的重要性,合理设置模型参数与网络结构,控制多步预测误差传播,防范过拟合,规划计算资源与训练时间,关注模型的可解释性和透明度,以及持续更新与迭代模型,以适应数据分布的变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值