数据结构——查找(c)

数据结构——查找(c)


一、查找

(1)数据元素
数据项 / 项 / 字段:项是具有独立含义的标识单位,是数据不可分割的最小单位。项具有一定的类型,依项的取值类型而定。
组合项:由若干项、组合项构成。
数据元素:数据元素是由若干项、组合项构成的数据单位,是在某一问题中作为整体进行考虑和处理的基本单位。(数据元素有型和值之分)

(2)查找、查找表
查找 在数据集合中寻找满足某种条件的数据元素的过程称为查找。
查找表 (查找结构) 是由同一类型的数据元素(或记录)构成的集合。
分为静态查找表动态查找表两种

关键字 是数据元素(或记录)中某个数据项的值,用它可以标识(识别)一个数据元素(或记录)。
1.若此关键字可以惟一的标识一个记录,则为主关键字
2.称用以识别若干记录的关键字为次关键字
当数据元素只有一个数据项时,其关键字即为该数据元素的值。

(3)对查找表的常见操作
①查找:根据给定的某个值,在查找表中确定一个其关键字等于给定值的记录或数据元素。
1.若表中存在这样的一个记录,则称查找是成功的,此时查找的结果为给出整个记录的信息,或指示该记录在查找表中的位置。
2.若表中不存在关键字等于给定值的记录,则称查找不成功,此时查找的结果可给出一个“空”记录或“空”指针。
②插入、删除某个数据元素

(4)查找算法的评价指标:
查找长度:在查找运算中, 需要对比关键字的次数称为查找长度,反映了查找操作时间复杂度。
平均查找长度(ASL):为确定记录在查找表中的位置,需和给定值进行比较的关键字个数的期望值称为查找算法在查找成功时的平均查找长度。
A S L = ∑ i = 1 n p i c i \displaystyle ASL= \sum_{i=1}^n p_i c_i ASL=i=1npici

n为查找表的长度
p i \displaystyle p_i pi为查找第i个元素的概率
c i \displaystyle c_i ci为找到表中其关键字与给定值相等的记录时,和给定值已进行过比较的关键字的个数。

注:评价一个查找算法的效率时,通常考虑查找成功和查找失败两种情况的ASL

二、静态查找表

静态查找表:仅进行查找操作而不改变表中的数据。

0.静态查找表的存储结构

typedef struct{
   
	KeyType key;
	OtherInfoType info;
}ElemType;
typedef struct{
    //查找表的数据结构(顺序表)
	ElemType *elem; //动态数组基址,数据元素存储空间基址,建表时,按实际长度分配,0号单元留空
	int length; //表的长度
}SSTable;

1.顺序查找

顺序查找,又叫“线性查找”,通常用于线性表。

(1) 无序表的顺序查找

①一般方式:
从顺序表尾部依次向头部对比查找元素key
  查找成功,返回元素下标
  查找失败,返回0

int Sq_search(SSTable ST, KeyType key){
   
	//从尾到头查找
	int i = ST.length;
	//在无序表中查找元素key,查找成功时,返回元素在表中的位置
	//否则返回0
	while(i>0 && ST.elem[i] != key)
		i--;
	return i;
}

②设置监视哨
目的在于免于查找过程中每一步都要检测整个表是否查找完毕。
从顺序表尾部依次向头部对比查找元素key
  查找成功,返回元素下标
  查找失败,返回0
查找性能:
A S L 成功 = ∑ i = 1 n 1 n ( n − i + 1 ) = n + 1 2 \displaystyle ASL_{成功}= \sum_{i=1}^n \frac{1}{n}(n-i+1)=\frac{n+1}{2} ASL成功=i=1nn1(ni+1)=2n+1
A S L 失败 = n + 1 \displaystyle ASL_{失败}= n+1 ASL失败=n+1
时间复杂度:O(n)

int Sq_search(SSTable ST, KeyType key){
   
	//在无序表中查找元素key,查找成功时,返回元素在表中的位置
	//否则返回0
	int i = ST.length;
	ST.elem[0].key = key; //监视哨:下标为0的位置存放待查找的元素
	while(ST.elem[i].key != key) //从后往前找
		i--;
	return i;
}

(2) 优化 - 有序表的顺序查找

(假定为升序)
失败时无须与所有元素进行比较。

int Sq_search(SSTable ST, KeyType key){
   
	int i = ST.length;
	ST.elem[0].key = key; //监视哨
	while(ST.elem[i].key > key) 
		i--;
	if(key == ST.elem[i].key)
		return i;
	return 0;
}

查找性能:
A S L 成功 = ∑ i = 1 n 1 n ( n − i + 2 ) = n + 3 2 \displaystyle ASL_{成功}= \sum_{i=1}^n \frac{1}{n}(n-i+2)=\frac{n+3}{2} ASL成功=i=1nn1(ni+2)=2n+3
A S L 失败 = ∑ i = 1 n + 1 1 n ( n − i + 2 ) = n + 2 2 \displaystyle ASL_{失败}= \sum_{i=1}^{n+1} \frac{1}{n}(n-i+2)=\frac{n+2}{2} ASL失败=i=1n+1n1(ni+2)=2n+2

(3) 优化 - 被查概率大的放在靠前位置

2.折半查找(有序-顺序表)

折半查找,又称 “二分查找” ,仅适用于有序的顺序表。

(1)算法思想

先确定待查找记录所在的范围(区间),
①若待查找记录等于表中间位置上的记录,则查找成功;
②否则,缩小查找范围,即若待查找记录小于中间位置上的元素,则下一次到前半区间进行查找,
③若待查找记录大于中间位置上的元素,则下一次到后半区间进行查找。

算法实现

int B_search(SSTable ST, KeyType key){
   
	int low = 1; //low指向第一个元素位置
	int high = ST.length; //high指向最后一个元素位置
	int mid;
	while(low <= high){
   
		mid = [(low+high)/2];
		if(ST.elem[mid].key == key) //若待查找记录等于表中间位置上的记录,则查找成功
			return mid;
		else if(key < ST.elem[mid].key) //若待查找记录小于中间位置上的元素,则下一次到前半区间进行查找
			high = mid-1else //若待查找记录大于中间位置上的元素,则下一次到后半区间进行查找
			low = mid + 1; 
	}
	return 0; //查找失败
}

:若采用链表作为查找表的存储结构,能否进行折半查找?
答:不能,因为链表并不具备随机访问的特性。

(2)折半查找判定树

折半查找判定树:即描述折半查找过程的二叉树。
由mid所指元素将原有元素分割到左右子树中。
mid=⌊(high+low)/2⌋,所以↓↓↓↓↓
右子树结点数-左子树结点数=0或1在这里插入图片描述

特性:
①折半查找的判定树一定是平衡二叉树。
②若查找表中有n个关键字,则失败结点有n+1个
③折半查找的判定树中,只有最下面一层是不满的因此,元素个数为n时树高 h = ⌈ l o g 2 ( n + 1 ) ⌉ h=⌈log_2(n +1)⌉ h=log2(n+1)⌉(不包含失败结点)
查找成功的ASL ≤ h
查找成功的ASL ≤ h
因此,折半查找的时间复杂度= O ( l o g 2 n ) O(log_2n) O(log2n)

(3)查找性能

A S L 折半查找 = l o g 2 ( n + 1 ) − 1 \displaystyle ASL_{折半查找}=log_2(n+1)-1 ASL折半查找=log2(n+1)1

3.分块查找(索引顺序查找)

//索引表
typedef struct {
   
	ElemType maxValue;
	int low, high;
}Index;
//顺序表存储实际元素
ElemType List[100];

“索引表” 中保存每个分块的最大关键字和分块的存储区间。
特点:块内无序、块间有序。

(1)算法思想

在索引顺序表中查找指定元素时,分两步:
①先在索引表中确定元素所在的分块(可顺序、可折半);
②再在块中顺序查找。

用折半查找查索引
若索引表中不包含目标关键字,则折半查找索引表最终停在 low>high,要在low所指分块中查找:
原因:最终low左边一定小于目标关键字,high右边一定大于目标关键字。而分块存储的索引表中保存的是各个分块的最大关键字。
/(ㄒoㄒ)/~~ 若low超出索引表范围,查找失败。

(2)查找性能

设查找表中的元素被不均匀地分为b块,每块含有记录个数可能不相同
只能手动模拟进行计算
A S L = ∑ i = 1 n P i C i ASL=\sum_{i=1}^nP_iC_i ASL=

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值