数据结构-查找

基础概念

关键字

        是数据元素(或记录)中某个数据项的值,用以标识(识别)一个数据元素(或记录)。
        若此关键字可以识别唯一的一个记录,则称之谓“主关键字”。
        若此关键字能识别若干记录,则称之谓“次关键字”。

平均查找长度

衡量一个搜索算法的时间效率的标准是:
        在搜索过程中关键码的平均比较次数,这个标准也称为平均搜索长度ASL(Average Search Length),通常它是搜索结构中对象总数 n 或文件结构中物理块总数 n 的函数。

1.静态查找表

仅作查询和检索操作的查找表

1.1顺序查找

监视哨

1.1.1定义

所谓顺序查找,又称线性查找,主要用于在线性结构中进行查找。
设若表中有 n 个对象,则顺序查找从表的一端开始,顺序用各对象的关键码与给定值x进行比较,直到找到与其值相等的对象,则查找成功,给出该对象在表中的位置。
若整个表都已检测完仍未找到关键码与x相等的对象,则查找失败。给出失败信息。
在这里插入图片描述

1.1.2具体实现

typedef struct {
    int key;
    char name[10];
    int age;
}DataType;
typedef  struct {
    DataType *elem;
    int length;
}SSTable;
int Search_Sql(SSTable *ssTable,int searchNumber) {

    ssTable->elem[0].key = searchNumber;//设置监视哨
    int j;
    for (j = ssTable->length; ssTable->elem[0].key != ssTable->elem[j].key; j--);

    return j;
}

1.2 有序查找表

1.2.1折半查找

mid= l o w + h i g h 2 \frac{low+high}{2} 2low+high
算法思想
设n个对象存放在一个有序顺序表中,并按其关键字从小到大排好了序。
采用折半查找时,先求位于查找区间正中的对象的下标mid,用其关键码与给定值x比较:
Elem[mid].Key = x,查找成功;
Elem[mid].Key > x,把查找区间缩小到表的前半部分,再继续进行折半查找;
Elem[mid].Key < x,把查找区间缩小到表的后半部分,再继续进行折半查找。

每比较一次,查找区间缩小一半。如果查找区间已缩小到一个对象,仍未找到想要查找的对象,则查找失败。

typedef struct {
    int key;
    char name[10];
    int age;
}DataType;
typedef  struct {
    DataType *elem;
    int length;
}SSTable;
int  SearCh_Bin(SSTable *ssTable,int searchNumber)
{
    int  low=1,high=ssTable->length,mid;
    while (low<=high)
    {
        mid=(low+high)/2;
        printf("ssTable->elem[0].key::%d 与 ssTable->elem[mid].key::%d 相比较\n",ssTable->elem[0].key,ssTable->elem[mid].key);
        if(ssTable->elem[0].key==ssTable->elem[mid].key)return mid;
        if(ssTable->elem[0].key  <  ssTable->elem[mid].key)
        {
            high=mid-1;
        } else{
            low=mid+1;
        }
    }
    return 0;
}
int main() {
    SSTable *ssTable;
    int keys[]={1001,1008,1006,1009};
    //初始化顺序表
    ssTable->elem=(DataType*)malloc(sizeof((DATA_SIZE+1) * sizeof(DataType)));
    ssTable->length=0;
    for (int i = 1; i <= DATA_SIZE; ++i) {
        ssTable->elem[i].key=keys[i-1];
        printf("ssTable->elem[%d].key  :::%d  \n",i,ssTable->elem[i].key);
        ssTable->length++;
    }
    printf("请输入要查找的元素:\n");
    int searchNumber;
    scanf("%d", &searchNumber);
    printf("顺序查找元素:%d  查找结果为:%d",searchNumber,Search_Sql(ssTable,searchNumber));

    int ks[]={1001,1002,1003,1004};
    ssTable->length=0;
    for (int i = 1; i <= DATA_SIZE; ++i) {
        ssTable->elem[i].key=ks[i-1];
        printf("\nssTable->elem[%d].key  :::%d  ",i,ssTable->elem[i].key);
        ssTable->length++;
    }
    int x;
    printf("请输入要查找的元素:\n");
    scanf("%d", &x);
    ssTable->elem[0].key=x;
    printf("折半查找元素%d  查找结果为%d",x,SearCh_Bin(ssTable,x));
    return 0;

}

运行结果:
在这里插入图片描述
在这里插入图片描述

一般情况下,表长为 n 的折半查找的判定树的深度和含有 n 个结点的完全二叉树的深度相同。
在有序表中查找记录的过程就是走了一条从根结点到与该记录相应的结点的路径,和给定值进行的比较次数就是该结点在判定树上的层次数.
折半查找在查找成功时关键字比较次数不超过树的深度,即:
⌊ l o g 2 n ⌋ \lfloor log^n_2\rfloor log2n + 1

2.动态查找表

有时在查询之后,还需要将“查询”结果为“不在查找表中”的数据元素插入到查找表中;或者,从查找表中删除其“查询”结果为“在查找表中”的数据元素。

2.1二叉排序树(二叉查找树)

2.1.1定义

二叉排序树或者是一棵空树;或者是具有如下特性的二叉树:
(1)若它的左子树不空,则左子树上所有结点的值均小于根结点的值;
(2)若它的右子树不空,则右子树上所有结点的值均大于根结点的值;
(3)它的左、右子树也都分别是二叉排序树。

在这里插入图片描述
二叉排序树的例子
在这里插入图片描述
如果对一棵二叉搜索树进行中序遍历,可以按从小到大的顺序,将各结点关键字排列起来

2.1.2算法思想

二叉排序树的查找算法:
在二叉排序树上进行查找,是一个从根结点开始,沿某一个分支逐层向下进行比较判等的过程。它可以是一个递归的过程。
若二叉排序树为空,则查找不成功;否则,
1)若给定值等于根结点的关键字,则查找成功;
2)若给定值小于根结点的关键字,则继续在左子树上进行查找;
3)若给定值大于根结点的关键字,则继续在右子树上进行查找。

2.1.3生成二叉排序树(插入)

输入数据序列 { 53, 78, 65, 17, 87, 09, 81, 45, 23 }
在这里插入图片描述
同样 3 个数据{ 1, 2, 3 },输入顺序不同,建立起来的二叉搜索树的形态也不同。这直接影响到二叉搜索树的搜索性能。
如果输入序列选得不好,会建立起一棵单支树,使得二叉搜索树的高度达到最大,这样必然会降低搜索性能。
在这里插入图片描述

2.1.3二叉查找树的删除

可分三种情况讨论:
(1)被删除的结点是叶子;
(2)被删除的结点只有左子树或者只有右子树;
(3)被删除的结点既有左子树,也有右子树。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2二叉平衡树

2.2.1AVL树定义

一棵AVL树或者是空树,或者是具有下列性质的二叉搜索树:它的左子树和右子树都是AVL树,且左子树和右子树的高度之差的绝对值不超过1

2.2.2二叉平衡树的特点

树中每个结点的左、右子树深度之差的绝对值不大于1  |hL-hR|≤1
在这里插入图片描述

2.2.3平衡因子balance

每个结点附加一个数字,给出该结点左子树的高度减去右子树的高度所得的高度差。这个数字即为结点的平衡因子balance 。

根据AVL树的定义,任一结点的平衡因子只能取 -1,0和 1。

如果一个结点的平衡因子的绝对值大于1,则这棵二叉搜索树就失去了平衡,不再是AVL树。

如果一棵二叉搜索树是高度平衡的,它就成为 AVL树。如果它有 n 个结点,其高度可保持在O(log2n),平均搜索长度也可保持在O(log2n)

2.2.4平衡化旋转

        如果在一棵平衡的二叉搜索树中插入一个新结点,造成了不平衡。此时必须调整树的结构,使之平衡化。
        平衡化旋转有两类:
        单旋转 (左旋和右旋)
        双旋转 (左平衡和右平衡)

        每插入一个新结点时,AVL树中相关结点的平衡状态会发生改变。因此,在插入一个新结点后,需要从插入位置沿通向根的路径回溯,检查各结点的平衡因子(左、右子树的高度差)。
        如果在某一结点发现高度不平衡,停止回溯。
        从发生不平衡的结点起,沿刚才回溯的路径取直接下两层的结点。
         如果这三个结点处于一条直线上,则采用单旋转进行平衡化
        单旋转可按其方向分为左单旋转和右单旋转,其中一个是另一个的镜像,其方向与不平衡的形状相关。
        如果这三个结点处于一条折线上,则采用双旋转进行平衡化
        双旋转分为先左后右和先右后左两类。

2.2.5 AVL树的插入

        在向一棵本来是高度平衡的AVL树中插入一个新结点时,如果树中某个结点的平衡因子的绝对值 |balance| > 1,则出现了不平衡,需要做平衡化处理。

        算法从一棵空树开始,通过输入一系列对象的关键码,逐步建立AVL树。在插入新结点时使用了前面所给的算法进行平衡旋转。

例,输入关键码序列为 { 16, 3, 7, 11, 9, 26, 18, 14, 15 },插入和调整过程如下
在这里插入图片描述

3.哈希表

理想的ASL=0

3.1哈希函数构造方法

3.1.1直接地址法

3.1.2函数分析法

3.1.3数学分析法

3.1.4平方取中法

3.1.5折叠法

3.1.6除数余数法

取关键字被某个不大于哈希表长m的数p除后所得余数为哈希地址。
H(key)=key mod p;   p ≤ m

3.2处理冲突的方法

3.2.1开放地址法

线性探测再散列

例如: 关键字集合
{ 19, 01, 23, 14, 55, 68, 11, 82, 36 }
设定哈希函数 H(key) = key MOD 11 ( 表长=11 )
若采用线性探测再散列处理冲突
在这里插入图片描述

二次探测再散列
伪随机探测再散列

3.2.2再哈希法

3.2.3链地址法

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值