数据结构期末复习------查找汇总

数据结构复习------查找汇总

值期末考试之际,汇总查找的相关内容

期末了!

零、基础概念

  • 关键字:可以标识一个记录的数据项

    • 主关键字:可以唯一标识一个记录的数据项
    • 次关键字:可以识别若干记录的数据项
  • 查找:

    • 静态查找:查询某个特定的元素,不插入新元素或删除元素
    • 动态查找:查找的过程中,同时插入查找表中不存在的数据元素
  • 查找表:

    • 静态查找表:

      • 顺序表,顺序查找

      • 线性链表,顺序查找

      • 有序的顺序表,折半查找

        ​ 斐波那契查找法,插值查找法

      • 索引顺序表/分块表,分块查找

    • 动态查找表:

      • 二叉排序树,平衡二叉树(AVL树)
      • B树,B+树,键树
    • 哈希(Hash)表

  • 平均查找长度:查找一个记录时比较关键字次数的平均值

一、静态查找表

1、顺序表与顺序查找法

元素类型为记录(结构)------包含关键字和名称

#define maxsize 100
typedef struct node{
  keytype key;
  char name[6];
}ElemType;
typedef struct{
  ElemType elem[maxsize+1];//maxsize+1个记录,elem[0]为监视哨
  int length;
}SSTable;
SSTable ST1,ST2;

算法1:不使用监视哨

int sequsearch(SSTable ST,keytype k){
  int i=ST.length;									//从第n个记录开始查找
  while(i>=1&&k!=ST.elem[i].key)i--;//继续扫描
  if(i)
    printf("success\n");						//查找成功!
  else																	
    printf("fail\n");								//查找失败!
  return i;													//返回记录的下标i,没找到就返回0了
}

算法2:使用监视哨elem[0]

int sequsearch(SSTable ST,keytype k){
  int i=ST.length;								//从第n个记录开始查找
  ST.elem[0].key=k;								//将k填入0位置
  while(k!=ST.elem[i].key)i--;		//继续扫描
  return i;												//返回记录的下标i
}

分析:

  • 查找成功

    ​ ASL=(n+1)/2

  • 查找失败

    使用监视哨elem[0],为n+1

    不使用监视哨elem[0],为n

    ASL=3(n+1)/4

2、有序的顺序表的查找和折半查找法

折半查找(binary search,对半查找,二分查找)–一种分治的思想

算法1:

int binsearch(SSTable ST,keytype k){
  int low,mid,high;
  low=1;
  high=ST.length;
  while(low<=high){
    mid=(low+high)/2;
    if(k<ST.elem[mid].key)			//分三种情况
      high=mid-1;
    else if(k==ST.elem[mid].key)
      break;
    else	low=mid+1;
  }
  if(ST.elem[mid].key==k){
    printf("success\n");
    return mid;
  }
  else{
    printf("fail\n");
    return 0;
  }
}

算法2:

int binsearch(SSTable ST,keytype k){
  int low,mid,high;
  low=1;high=ST.length;
  while(low<=high){
    mid=(low+high)/2;
    if(k<ST.elem[mid].key)high=mid-1;				//查左子表
    else if(k==ST.elem[mid].key)return mid;	//找到
    else low=mid+1;													//查右子表
  }
  return 0;
}

判定树:描述折半查找的二叉树

若n=2k-1,则判定树为满二叉树,其深度为k=log2(n+1)

假定Pi=1/n,比较关键字的次数:

  • 最少 C=1

  • 最多 C=log2(n+1)

  • ASL=(n+1)/nlog2(n+1)-1

3、索引顺序表(分块表)与分块查找法

  • 条件:分块表“按块有序”,索引表“按key有序”

  • n个记录分为b块,每块的记录数s=n/b

  • 查找方法与ASL

  • 顺序查找、折半查找

    ASL(1)=(b+1)/2

  • 在某一块中顺序查找

    ASL(2)=(s+1)/2

  • ASL=(b+1)/2+(s+1)/2=(b+s)/2+1=1/2(n/s+s)+1

  • 最加分块:s=根号n

ASLmin=根号n+1=O(根号n)

二、动态查找表

1、二叉排序树(二叉查找树)

定义:二叉树中的任一结点大于其非空左子树的所有结点,而小于其非空右子树的所有结点,则称这颗二叉树为二叉排序树。

对于一颗二叉排序树进行中序遍历,所得的结点序列一定是递增有序的。

二叉排序树的存储结构
struct node{
  struct {
    int key;										//关键字
  }data;
  struct node *lchild,*rchild;	//左右子树的指针
}*root,*t;
插入一个元素到二叉排序树的算法

(递归实现插入元素)

struct node *intree(struct node *t,ElemType x){
  if(t==NULL){											//如果为空,那么新开一个结点
    t=(struct node *)malloc(sizeof(struct node))
  	t->data=x;											//生成并插入结点x
    t->lchild=t->rchild=NULL;				//为叶子结点
  }
  else if(x.key<t->data.key)
    t->lchild=intree(t->lchild,x);	//插入到左子树
  else
    t->rchild=intree(t->rchild,x);	//插入到右子树
  return t;
}
二叉排序树的查找算法:

(返回值 失败:NULL 成功:非NULL,结点指针)

  • 递归实现:
struct node *search_tr(struct node*t,keytype k){
  if(t==NULL)	return NULL;							//查找失败
  else	if(k==k->data.key)				
    return t;						  		  				//查找成功
  else	if(k<t->data.key)
   		  return	search_tr(t->lchild,k);//查左子树
			else	
        return search_tr(t->rchild,k); //查右子树
}
  • 非递归实现:
struct node *search_tree(struct node*t,keytype k){
  while(t!=NULL)
    if(k==t->data.key)
      return t;					//查找成功
  	else
    	if(k<t->data.key)
      	t=t->lchild;		//查左子树
  		else
      	t=t->rchild;		//查右子树
  return t;							//查找失败
}
二叉排序树的删除算法

在二叉排序树中删除一个结点时,必须将因删除节点而断开的二叉链表重新连接起来,同时确保二叉排序树的性质不会失去。

  • 删除叶结点
  • 被删及结点缺左子树(或右子树)
  • 被删结点左右子树都存在

分析:

  • 最好情况(满二叉树)

    ASL=(n+1)/nlog2(n+1)-1=O(log2n)

  • 最坏情况(单枝树)

    ASL=(n+1)/2

  • 平均值

    ASL=O(log2n)

2、平衡二叉树(高度平衡二叉树)

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

AVL树:任何结点的平衡因子的绝对值小于等于1的二叉树

AVL树的存储结构:

typedef int DataType;
typedef struct node{
  DataType data;
  int balance;
  struct node *leftChild,*rightChild;
}AVLNode;
typedef AVLNode * AVLTree;

平衡化旋转

如果在一棵平衡的二叉搜索树中插入一个新结点,造成了不平衡,此时必须调整树的结构,使之平衡化。

平衡化旋转的两类:

  • 单旋转(左旋和右旋)
  • 双旋转(左平衡和右平衡)

静态查找表和动态查找表查找方法的不足:

无法根据关键字的值,估计数据元素可能在的位置

三、哈希表和哈希法

存储数据元素时,利用一个Hash函数根据数据元素的关键字计算出该数据元素的存储位置,查找时,也是根据给定的数据元素的关键字计算出该数据元素可能存储位置,这样一来,存储和查找的效率相当高。

哈希表也称为散列表,其数据元素的存储一般是不连续的,通过Hash函数计算出的地址称为哈希地址或散列地址。

1、相关术语

Hash函数实现的是将一组关键字映像到一个有限的地址区间上,理想的情况是关键字得到不同的地址。

设K1和K2是关键字,若K1不等于K2是H(K1)=H(k2),则称K1和K2为同义词,他们发生了冲突。

要考虑的两个问题:

  • 选择一个好的哈希函数
  • 选择一种解决冲突的方法
2、构造哈希函数的方法
直接地址法:

取关键字过着关键字的某个线性函数值为哈希地址

除留余数法:

设哈希表的表长为m,哈希地址为key除以p所得的余数

p<=m,p为接近m的质数(素数)eg:m=130,p=127

或者不包含小于20的质因子的合数

解决冲突的方法:线性探测再散列(哈希)

平方取中法:

H(k)=取k2的中间某几位数字

eg:K=21 K2=0441 取中间两位,H(K)=44

折叠法:

将关键字分成位数相同的几部分,然后取这几部分的叠加和作为哈希地址

  1. 边界折叠法

    eg: k=056439725 H(k)=650+439+725=1814

  2. 位移折叠法

    k=056439527 056+439+527=1022 H(k)=022

数字分析法:

设哈希表中可能出现的关键字都是事先知道的,则可以取关键字的若干分布均匀的位组成哈希地址

eg:k=9020067 H(k)=206

随机数法:

H(k)=random(key)

random(key)为产生伪随机数的函数

灵活构造哈希函数

eg:H(k)=取k2的中间2位数*40/99

再用线性探测再散列法解决冲突

3、如何解决冲突
开放地址法(开式寻址法)
  • 线性探测再散列
  • 二次探测再散列
链地址法

将关键字为同义词的所有记录存入同一个链表中(表尾插入)。

eg:设H(k)=k的首字母再字母表中序号

建立公共溢出区

将发生冲突的所有记录都存入一个公共溢出区

eg:设H(k)=k的首字母再字母表中的序号

再哈希法

发生冲突时,再使用下一个哈希函数计算哈希地址

哈希表的平均查找长度依赖于哈希表的装填因子

你说的,乐观一点

给生活加点

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值