DS博客作业05-查找

0.PTA得分截图

1.本周学习总结(0-4分)

1.1 总结查找内容

1.1.1 查找的基本概念

ASL:是查找算法的查找成功时的平均查找长度的缩写,是为确定记录在查找表中的位置,需和给定值进行比较的关键字个数的期望值。ASL是查找性能好坏指标,一个算法ASL越小其时间性能越好。

(上图一般指的是静态查找,Pi指的是查找表中第i个记录的概率,Ci指的是比较过的关键字个数)
动态和静态查找:若在查找是对表进行修改操作(插入or删除)则称为动态查找反之则为静态查找。

1.1.2 静态查找

顺序查找


int SeqSearch(SeqList R,int n,int K)       //R为顺序表,n为顺序表元素个数,K为待查找元素
{
    int i= 0;
    while(i<n && R[i].key != k)
    {
        i++;
    }
    if(i>=n)
    {
        return -1;
    }
    else
    {
        return i;
    }
}


成功ASL:
不成功ASL=n(从头找到尾还没有找到)

二分查找

  1. 二分查找要求线性表是有序的,由于每次都分成左半区间和右半区间,所以可以用二叉树来描述,有左右子表构成的二叉树分别作为根的左右子树,由此得到的二叉树又称为判定树或比较树。
  2. 查找的过程图示:
  3. 二叉判定树:

    成功的ASL=
    不成功ASL=log(n+1)
    算法的时间复杂度O(log2n),虽然时间复杂度不高,但是要求顺序表一定要有序。
  4. 代码:

int Binsearck(SeqList R,int n,KeyType K)
{
    int low = 0;
    int high = n-1;
    int mid = (low + high)/2;
    if(R[mid].key == K)
    {
        return mid;
    }
    else if(R[mid].key > K)
    {
        right = mid-1;
    }
    else
    {
        left = mid+1;
    }
    return -1;
}

1.1.3 动态查找

二叉搜索树

二叉搜索树(又称二叉排序树)性质:

(1)若左子树非空,则左子树上的所有节点关键字都小于根节点关键字
(2)若右子树非空,则右子树上的所有节点关键字都大于根节点关键字
(3)根结点的左右子树本身又是一颗二叉搜索树
(4)补充:中序遍历二叉搜索树得到的中序序列是一个递增有序序列

代码:

结构体定义:


typedef struct node 
{     KeyType key;            	  //关键字项
     InfoType data;          	  //其他数据域
      struct node *lchild,*rchild; 	  //左右孩子指针
}  BSTNode,*BSTree;

创建及插入:

BSTNode *CreatBST(KeyType A[],int n) //返回树根指针
{      BSTNode *bt=NULL;    //初始时bt为空树
       int i=0;
       while (i<n) 
       {    
         InsertBST(bt,A[i]);  //将A[i]插入二叉排序树T中
       i++;
       }
       return bt;       	    //返回建立的二叉排序树的根指针
} 

BinTree Insert(BinTree BST, ElementType X)
{
    if (BST == NULL)    //空结点
    {
        BST = new BSTNode;    //生成新结点
        BST->Data = X;
        BST->Left = BST->Right = NULL;    
    }
    else if (X < BST->Data) 
    {
        BST->Left = Insert(BST->Left, X);   //插入左子树
    }
    else if (X > BST->Data)
    {
        BST->Right = Insert(BST->Right, X);   //插入右子树
    }  
    return BST;
}

删除:
  情况1:要删除的结点为叶子结点,直接删去
  情况2:要删除的结点只有右子树(或左子树),用右孩子(或左孩子)代替它
  情况3:要删除的结点同时存在左右子树,从左子树中选择最大的结点的值替代要删除结点的值,并删除选择到的最大结点(一定没有右子树,情况2)

int DeleteBST(BSTree &bt,KeyType k)  //bt的值可能发生变化,所以一定要用引用类型	
{  
   if (bt==NULL)     //空树删除失败
   {
      return 0;
   }
   else 
   { 
      if (k<bt->key) //递归在左子树中删除为k的节点
      {
           return DeleteBST(bt->lchild,k);
      }
      else if (k>bt->key) //递归在右子树中删除为k的节点
      {
           return DeleteBST(bt->rchild,k);
      }
      else 
      {    
           Delete(bt);//删除*bt节点
	   return 1;
      }
  }
} 
void Delete(BSTree &p)//从二叉排序树中删除*p节点
{  
   BSTNode *q;
   if (p->rchild==NULL)//*p节点没有右子树的情况
   {   
     q=p; p=p->lchild;delete q; 
   }
   else if (p->lchild==NULL)//*p节点没有左子树
   {    q=p; p=p->rchild;delete q; 

   }
   else Delete1(p,p->lchild);//*p节点既有左子树又有右子树的情况
}
void Delete1(BSTNode *p,BSTNode *&r)//被删节点:p,p的左子树节点:r
{  
   BSTNode *q;
   if (r->rchild!=NULL)
   {
      Delete1(p,r->rchild); //递归找最右下节点
   }
   else //找到了最右下节点*r
   {    
      p->key=r->key;
      q=r; r=r->lchild;delete q; //将*r的关键字值赋给*p,用r的左孩子替代r并释放q的空间
   }
}

AVL树

AVL树的定义:

若一棵二叉树中每个结点的左右子树的高度差不超过1,则称此二叉树为平衡二叉树。一般情况,平衡二叉树总是二叉搜索树。
从平衡因子的角度来说,一棵二叉树的某个结点的平衡因子(结点左右子树的高度差)绝对值不超过1,则该结点是平衡的,若一棵二叉树的所有节点都是平衡的,则称为平衡二叉树。

AVL树的及4种调整做法。

a. LL型调整:
在A结点的左孩子的左子树上插入结点使得A的平衡因子变为2引起失衡,调整方法如下:

b. RR型调整:
在结点A的右孩子的右子树上插入结点使得A的平衡因子变为2引起失衡,调整方法如下:

c. LR型调整:
在结点A的左孩子的右子树上插入结点使得A的平衡因子变为2引起失衡,调整方法如下:

d. RL型调整:
在结点A的右孩子的左子树上插入结点使得A的平衡因子变为2引起失衡,调整方法如下:

B-树(外查找)

定义:B-树是一种平衡的多路查找树。
满足要求要求:

a. 每个节点至多m个孩子节点(至多有m-1个关键字)
b. 除根节点外,其他节点至少有[m/2]个孩子节点(即至少有[m/2]-1个关键字)
c. 若根节点不是叶子节点,根节点至少两个孩子节点

结点特点:

a. 非根结点:孩子个数最小: m/2, 最大:m
b. 非根结点:关键字个数:最小: m/2 -1 , 最大:m-1
c. 根节点至少2个孩子:2--m
d. 结点中的关键字按升序排列

B-树的插入、删除的操作:
  1. 结构体:
#define MAXM 10		  //定义B-树的最大的阶数
typedef int KeyType;    //KeyType为关键字类型
typedef struct node      //B-树节点类型定义
{  int keynum; 	  //节点当前拥有的关键字的个数
   KeyType key[MAXM];  //[1..keynum]存放关键字,[0]不用
   struct node *parent;	    //双亲节点指针
   struct node *ptr[MAXM];//孩子节点指针数组[0..keynum]
} BTNode;

  1. 查找:
    在一棵B-树上顺序查找关键字为k的方法为:将k与根节点中的key[i]进行比较,与二叉搜索树类似,不同的是每个结点确定向下查找的路径是n+1路。
    a. 若k=key[i],则查找成功;
    b. 若k<key[1] 则沿着指针ptr[0]所指的子树继续查找;
    c. 若key[i]<k<key[i+1] 则沿着指针ptr[i]所指的子树继续查找;
    d. 若k>key[n] 则沿着指针ptr[n]所指的子树继续查找。

  2. 插入:
    B树的插入分为两步:
    a. 用查找算法找出插入结点(一定是某个叶子结点)
    b. 判断插入结点是否还有位置,即判断该结点关键字个数是否小于m-1
    若结点关键字个数<max,直接插入到合适位置上;
    若结点关键字个数=max,把结点分裂成两个,做法是创建一个新结点,把原结点中的关键字和插入的关键字排序后从中间位置([m/2]处)分为左右两部分,左部分放在原结点中,右部分放在新结点中,中间的关键字连同新结
    点的存储位置插入到双亲结点中,若双亲结点的关键字个数也超过m-1,则重复此过程,直到根节点,若根节点需要分裂则树高度增加一层。

  3. 删除:
    B树的删除分为两步(与插入类似):
    (1)用查找算法找出删除结点
    (2)删除结点分为两种情况:一种是叶子结点,一种是非叶子层的结点。
    a. 在非叶子结点上删除关键字ki

    • 从pi子树节点借调最大或最小关键字key代替ki。
    • pi子树中删除key
    • 若子树节点关键字个数< m/2-1,重复步骤1
    • 若删除关键字为叶子结点层,按叶子结点删除操作法
      b. 在B树的叶子结点b上删除关键字共有以下3种情况:
    • 若b结点的关键字个数大于Min,说明删去该关键字后该结点仍满足B树的定义,则可直接删去该关键字。
    • 若b结点的关键字个数等于Min,说明删去关键字后该结点将不满足B树的定义。若可以从兄弟结点借。
      兄弟结点最小关键字上移双亲结点
      双亲结点大于删除关键字的关键字下移删除结点  
    • 若b结点的关键字个数等Min,兄弟节点关键字个数也等于Min
      删除关键字
      兄弟节点及删除关键字节点、双亲结点中分割二者关键字合并一个新叶子结点
      若双亲结点关键字个数<=Min,重复2

B+树

  • B+树是B-树的变形树。
    1. 满足条件:
      ⑴有n 棵子树的结点中含有n 个关键字;
      ⑵所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小按增序链接。
      ⑶所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。

1.1.4 散列查找

哈希表

概念:
  1. 哈希表(散列表)存储线性表的存储结构:主要适合关键字与存储地址存在某种函数关系的数据
  2. 哈希函数h(key):把关键字为ki的对象存放在相应的哈希地址中
  3. 哈希冲突(同义词冲突):对于两个关键字分别为ki和kj(i≠j)的记录,有ki≠kj,但h(ki)=h(kj)
    a. 与哈希表长度有关
    b. 与装填因子有关
    c. 与装填因子α=需要存储的数据个数/哈希表的大小有关,α越小,冲突可能性就越小
    d. 与所采用的哈希函数有关
  4. 散列:散列技术就是数据保存的存储位置和关键字之间存在一个映射关系(哈希函数),使关键字和地址直接对应起来
哈希函数构造方式
  1. 直接地址法:
    a. 直接定址法是以关键字k本身或关键字加上某个数值常量c作为哈希地址的方法
    b. 哈希函数表达式为:h(i)=k(i)+c(即关键字本身+常数值作为地址)
    c. 优点:表达式简单,不会产生哈希冲突;缺点:可能会有大量的连续空间浪费
  2. 除留余数法:
    a. 除留余数法是将关键字除以一个不小于哈希表长度m的数p所得的余数作为地址的方法
    b. 哈希函数表达式:h(k)=k % p (p<=m,且p最好是质(素)数,一般选择小于m的最大质数)
哈希冲突的解决方法
  1. 开放地址法:
    开放地址法是在发生哈希冲突时,寻找新地址的方法
    a. 线性探测法:从发生冲突的地址开始,依次往后探测(当到达表尾时,下一探测位置为首地址)
    数学描述公式:

    b. 平方探测法:可以避免出现堆积问题
    数学描述公式:

  2. 拉链法:
    拉链法是将所有同义词用单链表链接起来的方法,哈希表每个单元不在是关键字本身,而是相应同义词单链表的首节点指针

a. 优点:(1)哈希链处理冲突简单,且无堆积现象,平均操查找长度较短 (2)适用与表长无法确定的情况 (3)空间利用率高 (4)删除结点操作简单
b. 缺点:指针需要的额外空间,数据规模较小时一般选择开放地址法

哈希链的操作
  1. 插入及创建:
  • 开放地址法
typedef struct
{
    KeyType key;  //关键字域
    int count;  //探测次数域
}HashTable;  //哈希表单位类型
int InsertHT(HashTable ha,int p,int k,int &n)
{
    int adr,i;
    adr=k % p;
    if(adr==NULLKEY || adr==DELKEY)    //地址为空,可插入数据
    { 
       ha[adr].key=k;ha[adr].count=1;
    } 
    else
    {
        i=1;
        while(ha[adr].key!=NULLKEY && ha[adr].key!=DELKEY)
        {    
           adr=(adr+1) % m; 
           i++;
        }//查找插入位置
        ha[adr].key=k;ha[adr].count=i;   //找到插入位置 
    }
    n++;
}
void CreatHT(HashTable ha,int &n,int m,int p,KeyType keys[],int nl)
{
    for(int i=0;i<m;i++
    {
       ha[i].key=NULLKEY;
       ha[i].count=0;
    }
    n=0;
    for(i=0;i<nl;i++)
        InsertHT(ha,p,keys[i],int &n);
}


  • 拉链法:

typedef struct node
{
    KeyType key;     //关键字域
    struct node*next;     //下一个结点指针
}NodeType;      //单链表结点类型
typedef struct
{
    NodeType *firstp;       //首结点指针
}HashTable;     //哈希表单元类型
void InsertHT(HashTable ha[],int &n,int p,KeyType k)  //将关键字k插入到哈希表中
{
    int adr;
    adr=k%p;   //计算哈希函数值
    NodeType *q;
    q=(NodeType*)malloc(sizeof(NodeType));
    q->key=k;  //创建一个结点q,存放关键字k
    q->next=NULL;
    if(ha[adr].firstp==NULL)
        ha[adr].firstp=q;
    else      //若单链表adr不为空
    {
        q->next=ha[adr].firstp;  //采用头插法插入到ha[adr]的单链表中
        ha[adr].firstp=q;
    }
    n++;   //哈希表中结点的总个数增1
}
void CreatHT(HashTable ha[],int &n,int m,int p,KeyType keys[],int nl)  //由关键字序列keys[0..nl-1]创建哈希表
{
    for(int i=0;i<m;i++)         //哈希表置初值
        ha[i].firstp=NULL;
    n=0;
    for(i=0;i<nl;i++)
        InsertHT(ha,n,p,keys[i]);     //插入n个关键字
}


  1. 查找:
  • 开放地址法:

  • 拉链法:

几种解决哈希冲突的方法的平均查找长度的比较:

1.2 谈谈你对查找的认识及学习体会。

查找中需要应用到之前学习过的一些数据结构还有算法,本章新学习到的查找算法相较于之前学习过的,在时间效率上有显著优势。在数据的储存是采用合适的结构能够使查找效率提高很多。
学习了三大快的查找,分别是顺序表查找、树表查找还有哈希表查找,了解到了二叉排序树和AVL树在查找中的应用,B-树B+树在索引文件系统、数据库和磁盘中的应用。在进行其他操作之前要做的就是查找,所以好的查找算法很重要。

2.PTA题目介绍

2.1 7-5(哈希链) 航空公司VIP客户查询

2.1.1 该题的设计思路

2.1.2 该题的伪代码

文字+代码简要介绍本题思路

2.1.3 PTA提交列表

2.1.4 本题设计的知识点
1,2,3罗列。。。

2.2 题目2(2分)
2.3 题目3(2分)
下面同上

posted @ 2020-05-24 19:44  一个敢敢  阅读(204)  评论(0编辑  收藏  举报