【数据结构】查找与散列

  1. 查找

  1. 针对数组

顺序查找O(N),二分查找O(lgN),前提是二分查找的数组已排序。

二分查找c++实现。

假如从小到大排序,如果目标数比中间位置的数大,往右找;反之,往左找。当区间缩小为[a,a+1]时,直接分别比较然后结束。

#include<iostream>
#include<vector>
using namespace std;
int searchv(int s,int e,const vector<int>&v,int n){
    if(s==(e-1)){
        if(v[s]==n){return s;}
        else if(v[e]==n){return e;}
        else{
            return -1;
        }
    }
    int m=(s+e)/2;
    if(v[m]==n){
        return m;
    }
    else if(v[m]>n){
        return searchv(s,m,v,n);
    }
    else{
        return searchv(m,e,v,n);
    }  
}
int main(){
    vector<int>v;
    for(int i=1;i<=10;i++){
        v.push_back(i);
    }
    int num=0;
    cout<<searchv(0,9,v,num);
}
b. 针对树

BST树之前写过了,在此略过。

2. 自己写个散列

散列是什么?

今天去拿快递,我们怎么快速找到快递在哪里?先看第一组的货架号对吧。

货架号+快递=散列

可以这么理解吧。

  1. 初始化

我们需要自己生成货架号。哈希函数听过吧?哈希函数就是输入一个数,给这个数通过某种规则生成一个代号。这里用最简单的,直接除一个数取余。

很明显,当这个数太小的时候,代号可能会有大量重复,不利于查找(货架上有一堆快递,不好找你的快递吧)

所以需要思考这个数是干什么用的?不仅仅是代号,更是这个快递存储的下标。

这个数定位大于等于散列长度的一个质数是ok的(老师说不是质数会降低除法的效率)

所以用户初始化的时候需要输入散列的长度。

这样我们还需要判断散列是否满了,即散列中已经有了多少个数。

另外,散列如果删除一个元素,它该用什么告诉别人这个位置的元素是删除了不是从来都没填过元素呢?不妨再设置一个数组,存放每个位置的状态(初始为空)

b. 插入

这里采用的策略是如果应该插入的位置有人了,就(循环)顺位往后挪,直至有空位(状态不是Active)再插入。

所以还需要一个函数计算输入数字的代号(插入下标的初始值)

c. 查找

参考插入。插入怎么插,查找就怎么找。

注意是懒惰删除,删除的元素不会消失,但该位置的状态会被置为Del

d. 删除

先查找,注意修改的是状态,不是元素值

#include<iostream>
#include<iomanip>
using namespace std;
enum conditions {Active,Del,Empty};
int isPrime(int n){
    if(n==1 or n==2){return 0;}
    for(int i=2;i<n;i++){
        if(n%i==0){return 0;}
    }
    return 1;
}
class dict{
private:
    int *nums;
    int l;
    conditions *c;
    int nowI;
    int hashnum;
public:
    dict(int n){
        nowI=0;
        int i=n;
        l=n;
        for(i;;i++){
            if(isPrime(i)){
                break;
            }
        }
        nums=new int[i];
        hashnum=i;
        c=new conditions[i];
        for(int j=0;j<l;j++){
            c[j]=Empty;
        }
    }
    int hashInt(int n){
        return n%hashnum;
    }
    bool isFull(){
        if(nowI==l){
            return true;
        }
        return false;
    }
    bool insert(int x){
        if(isFull()){return false;}
        int n=hashInt(x);
        while(c[n]==Active){
            n=(n+1)%l;
        }
        nums[n]=x;
        c[n]=Active;
        nowI++;
        return true;
    }
    void rprint(){
        for(int i=0;i<l;i++){
            cout<<left<<setw(5)<<i;
        }cout<<endl;
        for(int i=0;i<l;i++){
            if(c[i]==Active){
                cout<<left<<setw(5)<<nums[i];
            }
            else if(c[i]==Del){
                cout<<left<<setw(5)<<"X";
            }
            else{
                cout<<left<<setw(5)<<"-";
            }
        }cout<<endl;
    }
    int find(int x){
        int n=hashInt(x);
        int i=n;
        do{
            if(c[i]==Empty){return -1;}
            if(c[i]==Active and nums[i]==x){
                return i;
            }
            i=(i+1)%l;
        }while(i!=n);
    }
    bool remove(int x){
        int n=find(x);
        if(n==-1){return false;}
        c[n]=Del;
        return true;
    }
};
int main(){
    dict d(10);
    d.insert(1);
    d.insert(12);
    d.rprint();
    cout<<d.find(11)<<endl;
    cout<<d.find(12)<<endl;
    d.remove(11);
    d.remove(1);
    d.rprint();
    cout<<d.find(12)<<endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值