《数据结构》 第七章 查找技术 笔记

                                                                                             第七章  查找技术

【学习重点】

(1)    折半查找的过程及性能分析;

(2)    二叉排序树的插入、删除和查找操作;

(3)    平衡二叉树的调整方法;

(4)    散列表的构造和查找方法;

(5)    各种查找技术的时间性能及对比。

【学习难点】

  (1)二叉排序树的删除操作;

  (2)平衡二叉树的调整方法;

  (3)闭散列表的删除算法。

                                          7.1    概 述

7.1.1 查找的基本概述

关键码 :可以标识一个记录的某个数据项。关键码的值称为关键值 ,若关键码可以唯一的标识一个记录,则称此关键码为主关键码,反之,称为次关键码。

查找:在具有相同类型的记录构成的集合中找出满足给定条件的记录。

静态查找:不涉及插入和删除操作的查找。

动态查找:涉及插入和删除操作的查找。

查找结构:(1)线性表:适用于静态查找,主要采用顺序查找技术、折半查找技术

                    (2)树表:适用于动态查找,主要采用二叉排序树的查找技术

                    (3)散列表:静态查找和动态查找均适用,主要采用散列技术

   7.1.2  查找算法的性能

     平均查找长度:查找算法进行的关键码比较次数的数学期望值。

      在查找不成功的情况, 平均查找长度即为查找失败对应的关键码的比较次数。

                 7.2    线性表的查找技术

   7.2.1 顺序查找

       顺序查找又称线性查找,其基本思想:从线性表的一端向另一端逐个将关键码与给定值进行比较,若相等,则查找成功,给出该记录在表中的位置;若整个表检测完仍未找到与给定值相等的关键码,则查找失败,给出失败信息。

  1.顺序表顺序查找

int SeqSearch2(intr[ ], intn, intk)

//数组r[1] ~ r[n]存放查找集合

{  

    r[0] = k; i = n;

    while (r[i] != k)

       i--;

    return i;

}

基本思想:设置“哨兵”。哨兵就是待查值,将它放在查找方向的尽头处,免去了在查找过程中每一次比较后都要判断查找位置是否越界,从而提高查找速度

2. 单链表的顺序查找

7.2.2       折半查找

使用条件

Ø线性表中的记录必须按关键码 有序
Ø必须采用 顺序存储。

基本思想:在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键码相等,则查找成功;若给定值小于中间记录的关键码,则在中间记录的左半区继续查找;若给定值大于中间记录的关键码,则在中间记录的右半区继续查找。不断重复上述过程,直到查找成功,或所查找的区域无记录,查找失败。

折半查找——非递归

intBinSearch1(intr[ ], intn, intk)

{                                  //数组r[1] ~ r[n]存放查找集合

   low = 1; high = n;

   while (low <= high)                  

   {

      mid = (low + high) / 2;           

      if (k < r[mid])  high = mid -1;

      else if (k > r[mid])  low = mid+ 1;

              else return mid;

   }

   return 0;

}


折半查找——递归

intBinSearch2(intr[ ], intlow, inthigh, intk)

{                              //数组r[1] ~ r[n]存放查找集合

   if (low > high) return 0; 

   else {

      mid = (low + high) / 2;

      if (k < r[mid])

          return BinSearch2(r, low, mid-1, k);

      else  if (k > r[mid])

                   return BinSearch2(r, mid+1,high, k);

               else return mid;

    }

 }

折半查找判定树

判定树:折半查找的过程可以用二叉树来描述,树中的每个结点对应有序表中的一个记录,结点的值为该记录在表中的位置。通常称这个描述折半查找过程的二叉树为折半查找判定树,简称判定树

判定树的构造方法:

⑴当n=0时,折半查找判定树为空;

⑵当n>0时,折半查找判定树的根结点是有序表中序号为mid=(n+1)/2的记录,根结点的左子树是与有序表r[1] ~ r[mid-1]相对应的折半查找判定树,根结点的右子树是与r[mid+1] ~ r[n]相对应的折半查找判定树。

查找性能分析:

查找成功:在表中查找任一记录的过程,即是折半查找判定树中从根结点到该记录结点的路径,和给定值的比较次数等于该记录结点在树中的层数。

查找不成功:查找失败的过程就是走了一条从根结点到外部结点的路径,和给定值进行的关键码的比较次数等于该路径上内部结点的个数。

   7.3  树表的查找技术

7.3.1 二叉排序树

  二叉排序树又称二叉查找树,它或者是一棵树的二叉树,或者是具有下列性质的二叉树:

⑴ 若它的左子树不空,则左子树上所有结点的值均小于根结点的值;

⑵ 若它的右子树不空,则右子树上所有结点的值均大于根结点的值;

⑶ 它的左右子树也都是二叉排序树。

1.二叉排序树的插入

void BiSortTree::InsertBST(BiNode<int> *root, BiNode<int>*s)

   if (root == NULL) 

      root = s;

   else  if (s->data <root->data)

                InsertBST(root->lchild, s);

            else   InsertBST(root->rchild, s);

}

2. 二叉排序树的构造

BiSortTree::BiSortTree(int r[ ], int n)

{    

   for (i = 0; i < n; i++)

   {

      s = new BiNode<int>;

      s->data = r[i];

      s->lchild= s->rchild= NULL;

      InsertBST(root,s);

   }

}

3.二叉排序树的删除

在二叉排序树上删除某个结点之后,仍然保持二叉排序树的特性。

分三种情况讨论:

§ 被删除的结点是叶子;
§ 被删除的结点只有左子树或者只有右子树;
§ 被删除的结点既有左子树,也有右子树
二叉排序树的删除——伪代码

1.若结点p是叶子,则直接删除结点p;

2. 若结点p只有左子树,则只需重接p的左子树;

    若结点p只有右子树,则只需重接p的右子树;

3.若结点p的左右子树均不空,则

   3.1 查找结点p的右子树上的最左下结点s及其双亲结点par

   3.2 将结点s数据域替换到被删结点p的数据域;

   3.3 若结点p的右孩子无左子树,

         则将s的右子树接到par的右子树上;

         否则,将s的右子树接到结点par的左子树上;

   3.4 删除结点s;

4.二叉排序树的查找

⑴ 若root是空树,则查找失败;

⑵若k=root->data,则查找成功;否则

⑶若k<root->data,则在root的左子树上查找;否则

⑷在root的右子树上查找。

    上述过程一直持续到k被找到或者待查找的子树为空,如果待查找的子树为空,则查找失败。

二叉排序树的查找效率在于只需查找二个子树之一。


BiNode*BiSortTree::SearchBST(BiNode<int>*root, intk)

{

   if (root == NULL)

    return NULL;

   else if (root->data== k)

              return root;

          else if (k < root->data)

                      return SearchBST(root->lchild, k);

                  else return SearchBST(root->rchild, k);

}

7.3.2 平衡二叉树

平衡二叉树:或者是一棵空的二叉排序树,或者是具有下列性质的二叉排序树:

⑴ 根结点的左子树和右子树的深度最多相差1;

⑵ 根结点的左子树和右子树也都是平衡二叉树。

平衡因子:结点的平衡因子是该结点的左子树的深度与右子树的深度之差。

最小不平衡子树:在平衡二叉树的构造过程中,以距离插入结点最近的、且平衡因子的绝对值大于1的结点为的子树。

构造平衡二叉树的基本思想:每插入一个结点,

(1)从插入结点开始向上计算各结点的平衡因子,如果某结点平衡因子的绝对值超过1,则说明插入操作破坏了二叉排序树的平衡性,需要进行平衡调整;否则继续执行插入操作。

(2)如果二叉排序树不平衡,则找出最小不平衡子树的根结点,根据新插入结点与最小不平衡子树根结点之间的关系判断调整类型。

(3)根据调整类型进行相应的调整,使之成为新的平衡子树。

设结点A为最小不平衡子树的根结点,对该子树进行平衡调整归纳起来有以下四种情况:

 1. LL型

 2. RR型

 3. LR型

 4. RL型

   7.4 散列表的查找技术

散列的基本思想:在记录的存储地址和它的关键码之间建立一个确定的对应关系。这样,不经过比较,一次读取就能得到所查元素的查找方法。

散列表:采用散列技术将记录存储在一块连续的存储空间中,这块连续的存储空间称为散列表。

散列函数:将关键码映射为散列表中适当存储位置的函数。

散列地址:由散列函数所得的存储地址 。

散列只是通过记录的关键码定位该记录,没有完整地表达记录之间的逻辑关系,所以,散列主要是面向查找的存储结构。

散列技术的关键问题:

⑴散列函数的设计。如何设计一个简单、均匀、存储利用率高的散列函数。

⑵冲突的处理。如何采取合适的处理冲突方法来解决冲突。

设计散列函数一般应遵循以下原则:

⑴ 计算简单。散列函数不应该有很大的计算量,否则会降低查找效率。

⑵函数值即散列地址分布均匀。函数值要尽量均匀散布在地址空间,这样才能保证存储空间的有效利用并减少冲突。

1. 计算散列地址j;

 2. ht[j]等于k,则查找成功,返回记录在散列表中的下标;   

     否则执行第3步;

 3. ht[j]为空或整个散列表探测一遍,则查找失败,转4

     否则,j指向下一单元,转2

 4. 若整个散列表探测一遍,则表满,抛出溢出异常;

     否则,将待查值插入;

intHashSearch1(int ht[ ], int m, int k)

{

   j = H(k);                        //计算散列地址

   if (ht[j] == k) return j;             //没有发生冲突,比较一次查找成功

   else if (ht[j] == Empty) {ht[j]= k; return 0; }    //查找不成功,插入

   i = (j + 1) % m;                            //设置探测的起始下标

   while (ht[i] != Empty && i != j) 

   {

       if (ht[i] == k) return i;            //发生冲突,比较若干次查找成功

       else i = (i + 1) % m;               //向后探测一个位置

   }

   if (i == j) throw "溢出";

   else {ht[i] = k; return 0; }            //查找不成功,插入

}

拉链法:

Node<int> *HashSearch2(Node<int> *ht[ ], int m, int k)

{    

    j = H(k);

    p = ht[j];

    while (p != NULL && p->data != k)

          p = p->next;

    if (p->data== k) return p;

    else {

        q = new Node<int>;q->data = k;

        q->next = ht[j];

        ht[j]= q; 

    }

}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值