第九章 查找表
数据结构教程 第5版 第9章-查找
4、影响查找的因素
采用何种查找方法? 使用哪种数据结构来表示“表”,即表中记录是按何种方式组织的? 表中关键字的次序。是对无序集合查找还是对有序集合查找?
5/51
5. 查找方法的性能指标
查找运算时间主要花费在关键字比较上,通常把查找过程中执行的关键字平均 比较个数(称为平均查找长度)作为衡量一个查找算法效率优劣的标准。
int BinSearch(RecType R[],int n,KeyType k)
{
int low=0,high=n-1,mid;
while (low<=high)
//当前区间存在元素时循环
{ mid=(low+high)/2;
if (R[mid].key==k) //查找成功返回其逻辑序号mid+1
1
1
4
2
3
3
2
姓名 张三 李四 王五 刘六
存储
姓名 张三 李四 王五 刘六
学 生 表
学号 1 4 3 2
地址 0 1 2 3
索引表
学号 1 2 3 4
地址 0 3 2 1
提取
排序
38/51
存储地址
0 1 2 3
主数据表
学号 1 4 3 2
姓名 张三 李四 王五 刘六
索引表
学号 1 2 3 4
地址 0 3 2 1
36/51
9.2.3 索引存储结构和分块查找 1、索引存储结构
索引存储结构 = 主数据表 + 索引表
索引表中的每一项称为索引项,索引项的一般形式是: (关键字,地址)
关键字唯一标识一个记录,地址作为指向该关键字对应记录的指针,也可以 是相对地址。
数据结构——查找
空指针
p=h->next;
while ((p!=NULL) && (p->key!=k)) p=p->next;
return p;
}
从顺序查找过程可见(不考虑越界比较),顺序查 找不论给定值k为何,若第1个记录符合给定值,只 要比较1次。若第n个记录符合给定值,要比较n次, 即(查找第i个记录所需比较次数)Ci=i。若每个记录的 查找概率相等,且每次查找都是成功的。则在等概 率的情况下,顺序查找的平均查找长度为:
ASL
n i 1
Pi Ci
1 n
n
i
i 1
1 . n(n 1) n2
n 1 2
n 2
有时在查询之后,还需要将“查询”结果为 “不在查找表中”的数据元素插入查找表;或 者,从查找表中删除其“查询”结果为“在查 找表中”的数据元素
查询:根据给定的某个值,在查找表中确定一个其关 键字等于给定值的数据元素或(记录)
关键字:是数据元素(或记录)中某个数据项的值, 用以标识(识别)一个数据元素(或记录)
a[1]~a[n]中。
int seq_search (Se_List a,keytype k)
{ //未设置监视哨的顺序表查找,查找关键字 值等于指定值k的记录,
//若查找成功,返回记录存放位置的下标值, 否则返回-1
int i;int find; for(i=0;i<a.length;i++) if(a[i].key==k) { find=1;break;} return (find?i:-1); }
int seq_search (Se_List a,keytype k)
数据结构第九章查找PPT培训课件
k=elem [i].key, (0≤i≤n),则停止比较。
如果 i>0,则查找成功;否则,查找失败。
输入:查找表ST,查找条件(关键字)k
输出:成功时:记录序号,失败时:0
int sequsearch(SSTable ST,keytype k)
{
int i=ST.length; //从第n个记录开始查找
折半查找算法2
int binsrch(SSTable ST,keytype k) {int low,mid,hig;
low=1; hig=ST.length;
while (low<=high)
{ mid=(low+high)/2;
if (k<ST.elem [mid].key) hig=mid-1;//查左子表
break;
//查找成功,退出循环
else low=mid+1; //查右子表
}
if (ST.elem[mid].key==k)
{ printf("success\n”); return mid;
} else
{ printf("fail\n”); return 0;
} }
//查找成功 //查找失败
n=15,满二叉树
2 5 8 10 12
n=12,非满二叉树
➢结点内的数据表示数据元素的序号(如例中表示有15个元素组成 的有序表的判定树)
➢根结点表示首先要和关键字k进行比较的数据元素的序号(如8), 比较相等时,查找成功,否则,当k小于根结点对应元素的关键字 时,下步就和左子结点(如序号4)对应元素的关键字比较,否则, 下步就和右子结点(如序号12)对应元素的关键字比较。
第九章查找3哈希表
解决方案:可采用二次探测法或伪随机探测法,以 改善‚堆积‛问题。
9.3
三.处理冲突的方法
哈希表
例2:设哈希表长为11,哈希函数 H(key)=key MOD 11, 试用开放定址法中二次探测再散列解决冲突 Hi(key)=(H(key)+di) MOD 11 (di=12,-12,22,-22,…,k2,-k2 ), 试对下列关键字序列(19,13,33,02,16,29,24) 构造哈希表HT。
9.3
哈希表
0
1 BAI 2 CHEN
例:假设在例2的记录集合中添 加关键字{DAI,ZHOU,…}。 4、冲突 对不同的关键字可能得到同一 哈希地址的现象叫做冲突。
……
3 DIAO
… 6 GAO … 18 SUN 19 TANG
关 键 码 集 合
…
22 WU 23 XIAO 24 YI 25 ZHAO
9.3
三.处理冲突的方法
3.链地址法
哈希表
9.3
三.处理冲突的方法
1.开放定址法 2.再哈希法
哈希表
3.链地址法(拉链法) 4.建立公共溢出区
P258
9.3
三.处理冲突的方法
例:关键码集合 {47, 7, 29, 11, 16, 92, 22, 8, 3},散列 函数为H(key)=key mod 11,用公共溢 出区法处理冲突, 构造的散列表为:
哈希表
二.哈希函数的构造方法
1、直接定址法 思想:哈希函数为关键字的某个线性函数
H(key)= a.key+b 或 H(key)=key
适应情况:事先知道关键码,关键码集合不是 很大且连续性较好。 优点:不会产生冲突
缺点:占用连续空间,空间效率低
查找-数据结构
平均查找长度:为确定记录在查找表中 的位置,需和给定值进行比较的关键字 个数的期望值称为查找算法在查找成功 时的平均查找长度,简称ASL。
对于含有n个记录的表,查找成功时的平 均查找长度为: n ASL PiCi i 1
其找到中表:中Pi为其查关找键表字中与第给i定个值记相录等的的概第率,i个C记i为 录时和给定值已进行过比较的关键字个数。
(1)若*p 为叶子结点,直接删除即可。
45
45
12
3
37
53
f
100
24
p
61
60
90
12
53
3
删除24
f->lchild = null; delete p;
37
100
61
60
90
78
78
(2)若*p结点只有左子树PL或只有右子树PR,此 时只要令PL或PR直接成为*f的左子树即可
f
F
f
F
p
P
p
二叉排序树的插入
基本思想:
若二叉排序树为空,则待插结点作为根结点插入 到空树中;
若待插结点的关键字值和根结点的关键字值相等, 则说明树中已有此结点,无需插入;
若待插结点的关键字值小于根结点的关键字值, 则将待插结点插入到根的左子树中;
若待插结点的关键字值大于根结点的关键字值, 则将待插结点插入到根的右子树中;
mid low
mid low
mid low
mid low
mid
mid
mid
mid
6
3
9
1
47
10
2
58
11
由此可见,二分查找过程恰好是走了一条从判 定树的根到被查结点的路径,比较的关键字个 数恰为该结点在判定树中的层数。
数据结构 第9章 查找4-哈希表
7、随机数法 Hash(key) = random ( key ) (random为伪随机函数)
适用于:关键字长度不等的情况。造表和查找都很方便。
小结:构造哈希函数的原则:
① ② ③ ④ ⑤ 执行速度(即计算哈希函数所需时间); 关键字的长度; 哈希表的大小; 关键字的分布情况; 查找频率。
三、冲突处理方法
14 H(14)=14%7=0
6个元素用7个 地址应该足够!
1
2
23 9
3
4
39 25 11
5
6
H(25)=25%7=4 H(11)=11%7=4
有冲突!
在哈希查找方法中,冲突是不可能避免的,只能 尽可能减少。
所以,哈希方法必须解决以下两个问题:
1)构造好的哈希函数
(a)所选函数尽可能简单,以便提高转换速度; (b)所选函数对关键码计算出的地址,应在哈希地址集中 大致均匀分布,以减少空间浪费。
讨论:如何进行散列查找?
根据存储时用到的散列函数H(k)表达式,迅即可查到结果! 例如,查找key=9,则访问H(9)=9号地址,若内容为9则成功; 若查不到,应当设法返回一个特殊值,例如空指针或空记录。
缺点:空间效率低!
若干术语
哈希方法 (杂凑法)
选取某个函数,依该函数按关键字计算元素的存储位置, 并按此存放;查找时,由同一个函数对给定值k计算地址, 将k与地址单元中元素关键码进行比较,确定查找是否成 功。
3. 乘余取整法
4. 数字分析法
5. 平方取中法
常用的哈希函数构造方法有:
6. 折叠法
7. 随机数法
1、直接定址法
(a、b为常数) 优点:以关键码key的某个线性函数值为哈希地址, 不会产生冲突. 缺点:要占用连续地址空间,空间效率低。
第9章 查找表e
2. 顺序表的顺序查找 下面是顺序表的类型定义:
#define MAX_NUM 100
typedef struct elemtype{ keytype key; anytype otheritem;
//用于定义表的长度
}Se_List[MAX_NUM],Se_Item;
假设在查找表中,数据元素个数为n(n<MAX_NUM),
• 若所有结点的空指针域设置为一个指向一个方形结点的指针,称 方形结点为判定树的外部结点;对应的,圆形结点为内部结点。
• 查找不成功的过程 就是走了一条从根结点到外部结点的路径。
9.1.3 分块查找(索引顺序查找) 这是一种顺序查找的另一种改进方法。 先让数据分块有序,即分成若干子表,要求每个子表中的数 值(用关键字更准确)都比后一块中数值小(但子表内部未必 有序)。 然后将各子表中的最大关键字构成一个索引表,表中还要包 含每个子表的起始地址(即头指针)。 例: 最大关键字 起始地址
记录的全部信息或指示找到记录的存储位置;若表中
不存在关键字等于给定值的记录,则称查找不成功, 此时查找的结果可以给出一个空记录或空指针。若按 主关键字查找,查找结果是唯一的;若按次关键字查 找,结果可能是多个记录,即结果可能不唯一。
查找表的存储结构 查找表是一种非常灵活的数据 结构,对于不同的存储结构,其查找方法不同。为了 提高查找速度,有时会采用一些特殊的存储结构。本 章将介绍以线性结构、树型结构及哈希表结构为存储
(1)在查找表中查看某个特定的数据元素是否在查找 表中,(2)检索某个特定元素的各种属性,则称这类 查找表为静态查找表。静态查找表在查找过程中查找 表本身不发生变化。对静态查找表进行的查找操作称
为静态查找。
动态查找表 若在查找过程中可以将查找表中不存 在的数据元素插入,或者从查找表中删除某个数据元 素,则称这类查找表为动态查找表。动态查找表在查 找过程中查找表可能会发生变化。对动态查找表进行 的查找操作称为动态查找。
第九查找
Data Structure
作业
设有序顺序表中的元素依次为017, 094, 154, 170, 275, 503, 509, 512, 553, 612, 677, 765, 897, 908。试画出对其进行折半搜索时的二叉判定树, 并 计算搜索成功的平均搜索长度和搜索不成功的平均 搜索长度。
查找失败:
n+1
int Search_Seq(SSTable ST,KeyType key) {
//在顺序表ST中顺序查找其关键字等于key的数据元素。 //若找到,则函数值为该元素在表中的位置,否则为0。
ST.elem[0].key = key; //0号单元作为监视哨
for ( i=ST.length; !EQ (ST.elem[i].key , key); --i ); //从后往前找
high=2 mid=1 7<14
low=2
mid=2 14=14
Data Structure
high=13
例:查找值为22的记录的过程:
0 1 2 3 4 5 6 7 8 9 10 11 12 13
7 14 18 21 23 29 31 35 38 42 46 49 52
low=1 18<22 mid=7 31>22 mid=3 high=6
Lw — —在块中查找元素的平均查找长度
若将表长为 n的表平均分成 b块,每块含 s个记录,并设表中每个 记录的 查找概率相等,则:
(1)用顺序查找确定所在块 :ASLbs
=
1 b
b j =1
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第九章查找表查找表是由同一类型的数据元素(或记录)构成的集合。
对查找表经常进行的操作:1)查询某个“特定的”数据元素是否在查找表中;2)检索某个“特定的”数据元素的各种属性;3)在查找表中插入一个数据元素;4)从查找表中删去某个数据元素。
静态查找表仅作上述1)和2)操作的查找表动态查找表有时在查询之后,还需要将“查询”结果为“不在查找表中”的数据元素插入查找表;或者,从查找表中删除其“查询”结果为“在查找表中”的数据元素关键字是数据元素(或记录)中某个数据项的值,用以标识(识别)一个数据元素(或记录)若此关键字可以识别唯一的一个记录,则称之谓“主关键字”若此关键字能识别若干记录,则称之谓“次关键字”查找根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素或(记录)若查找表中存在这样一个记录,则称“查找成功”,查找结果:给出整个记录的信息,或指示该记录在查找表中的位臵;否则称“查找不成功”,查找结果:给出“空记录”或“空指针”如何进行查找?取决于查找表的结构,即:记录在查找表中所处的位臵。
然而,查找表本身是一种很松散的结构,因此,为了提高查找的效率,需要在查找表中的元素之间人为地附加某种确定的关系,换句话说,用另外一种结构来表示查找表。
本章讨论的重点:查找表的各种表示方法及其相应的查找算法9.1 静态查找表ADT StaticSearchTable {数据对象D:D是具有相同特性的数据元素的集合。
每个数据元素含有类型相同的关键字,可唯一标识数据元素。
数据关系R:数据元素同属一个集合。
基本操作P:Create(&ST, n);操作结果:构造一个含n个数据元素的静态查找表ST。
Destroy(&ST);初始条件:静态查找表ST存在;操作结果:销毁表ST。
Search(ST, key);初始条件:静态查找表ST存在,key为和查找表中元素的关键字类型相同的给定值;操作结果:若ST中存在其关键字等于key的数据元素,则函数值为该元素的值或在表中的位臵,否则为“空”。
Traverse(ST, Visit());初始条件:静态查找表ST存在,Visit是对元素操作的应用函数;操作结果:按某种次序对ST的每个元素调用函数Visit()一次且仅一次,一旦Visit()失败,则操作失败。
} ADT StaticSearchTableC++的语言描述:template<class Elem>class SSTable{public:virtual Elem *Search(KeyType key);// 若静态查找表中存在其关键字和key相等的// 元素,则返回指向该元素的指针,否则返回//“空”指针。
virtual void Traverse(void visit(Elem& item));// 按某种次序对静态查找表中每个元素调用// 函数visit( )一次且仅一次。
}; // SSTable下面讨论静态查找表的各种实现方法一、顺序查找表以顺序表或线性链表表示静态查找表template<class Elem>class SqSTable:public SSTable{private:SqList< Elem > ST;public:SqSTable(int size); // 构造函数SqSTable(SqSTable ra); // 复制构造函数SqSTable(int size, const Elem * elemVal);// 构造一个含size个元素的静态查找表,// 其元素值由elemVal给出。
~SqSTable(void){}; // 析构函数virtual Elem *Search(KeyType key);// 若顺序查找表中存在其关键字和key相等// 的数据元素,则返回指向该元素的指针,// 否则返回“空指针”。
virtual void Traverse(void visit(Elem& item));// 对顺序查找表中每个元素,依次顺序调用函数// visit一次,并且仅调用一次}; // SqSTable在此重点讨论“查找”算法的实现。
template<class Elem>Elem *SqSTable<Elem>::Search(KeyType key){int i;if ST<Elem>.location(key, i) return getElem(i) else return NULL}回顾顺序表的查找算法:template <class Elem>int SqList::location( const Elem& e) {Elem *p;int k = 1;p = elemPtr;while ( k<=cursize && (compare(*p++,e)))k++;if ( k<= cursize) return k;else return 0;} //location上述算法中的基本操作是:compare,为了避免“出界”,同时需作k<=cursize的判断,在表长>1000时,将使算法的执行时间几乎增加一倍。
为此,改写顺序表的查找算法如下:template <class Elem>int SqList<Elem>::Search_Seq(const KeyType key){// 在顺序表ST中顺序查找其关键字等于key的数// 据元素。
若找到,则函数值为该元素在表中的位// 臵,否则为0。
elemPtr[0].key = key; // 设“哨兵”int i = cursize; //令i指向表尾,从后往前搜索while (compare(elemPtr[i].key, key)) i--;return i; //找不到时,i为0} // Search_Seq定义:查找算法的平均查找长度(A verage S earch L ength)为确定记录在查找表中的位臵,需和给定值进行比较的关键字个数的期望值 ∑==ni i i C P ASL 1其中: n 为表长,P i 为查找表中第i 个记录的概率,且 11=∑=n i i PC i 为找到该记录时,曾和给定值比较过的关键字的个数对顺序表而言,C i = n-i+1ASL = nP 1 +(n-1)P 2 + +2P n -1+P n在等概率查找的情况下,nP i 1= 顺序表查找的平均查找长度为:21111+=+-=∑=n )i (n n ASL n i ss在不等概率查找的情况下,ASL ss 在P n P n-1 P 2P 1时取极小值若查找概率无法事先测定,则查找过程采取的改进办法是,在每次查找之后,将刚刚查找到的记录直接移至表尾的位臵上。
二、有序查找表上述顺序查找表的查找算法简单,但平均查找长度较大,特别不适用于表长较大的查找表以有序表表示静态查找表template<class Elem>class OrdSTable:public SSTable{pravite:OrderedList<Elem> ST ;…}; // OrdSTable此时的查找算法可基于折半查找来完成int OrderedList<Elem>::Search_Bin( KeyType key ){// 在有序表中折半查找其关键字等于key的记录。
// 若找到,则返回该记录在表中的位臵,否则为0。
low = 1; high = ST.length; // 臵区间初值while (low <= high) {mid = (low + high) / 2; //取查找区间的中间位臵if (EQ (key ,elemPtr[mid].key) ) return mid;// 找到待查记录else if (LT (key , elemPtr[mid].key)) high = mid - 1;//继续在前半区间进行查找else low = mid + 1; //继续在后半区间进行查找}return 0; // 有序表中不存在待查记录} // Search_Bin分析折半查找的平均查找长度构造一棵二叉树,将C i=i的结点放在这棵树的第i层用以描述折半查找的过程,称之谓“判定树”例如: 折半查找在n=11 时的判定树63 91 4 7 102 5 8 11一般情况下,表长为n的折半查找的判定树的深度和含有n个结点的完全二叉树的深度相同假设 n=2h -1 并且查找概率相等则 1)1(l o g 12112111-++=⎥⎦⎤⎢⎣⎡⨯==∑∑=-=n n n j n C n A S L hj j n i i bs 在n>50时,可得近似结果 1)1(l o g 2-+≈n A S L bs三、静态查找树表在不等概率查找的情况下,折半查找不是最好的查找方法 例如:关键字: A B C D EPi: 0.2 0.3 0.05 0.3 0.15Ci: 2 3 1 2 3此时的 ASL = 2.4若改变Ci 的值 2 1 3 2 3则 ASL = 1.9定义: 使 ∑∑+=='+=111n i n i i C qi piCi ASL 达最小的判定树称为最优二叉树, 其中: 1111=+∑∑===n i ni qi pi 构造最优二叉树的时间复杂度为 O (n 3)介绍一种次优二叉树的构造方法:令 w i = αp i选择二叉树的根结点,使 ∑∑-=+=-=∆111i j j h i j j i w w P 达最小构造次优二叉树的算法Status SecondOptimal(BiTree &T, ElemType R[], float sw[], int low, int high) { // 由有序表R[low..high]及其累计权值表sw// (其中sw[0]==0)递归构造次优查找树T 。
i = low; min = abs(sw[high]-sw[low]);dw = sw[high]+sw[low-1];for (j=low+1; j <=high; ++j)// 选择最小的ΔP i 值if abs(dw-sw[j]-sw[j-1]) < min) {i = j; min = abs(dw-sw[j]-sw[j-1]);}if (!(T = (BiTree)malloc (sizeof (BiTNode))))return ERROR;T->data = R[i]; // 生成结点if (i==low) T->lchild = NULL; // 左子树空else SecondOptimal(T->lchild, R, sw, low, i-1);// 构造左子树if (i==high) T->rchild = NULL; // 右子树空else SecondOptimal(T->rchild, R, sw, i+1, high);// 构造右子树return OK;} // SecondOptimal次优查找树采用二叉链表的存储结构template<class Elem>class SOSTable:public SSTable{pravite:SOSTree<Elem> ST ;…}; // SOSTableSOSTable<Elem>::SOSTable(OrderedList st) {// 由有序表st构造一棵次优查找树ST// ST的数据元素含有权域weightif (st.length = 0) T = NULL;else {FindSW(sw, ST); // 按照有序表ST中// 各数据元素的weight域// 求累计权值表swSecondOpiamal(T, ST.elem, sw, 1, ST.length); }return OK;} // SOSTree四、索引顺序表对比顺序表和有序表的查找性能之差别:顺序表有序表表的特性无序表有序表存储结构顺序结构或链表结构链表结构插删操作易于进行需移动元素ASL值大小索引顺序表= 索引+ 顺序表一般情况下,索引是一个有序表查找方法:1)由索引确定记录所在区间;2)在顺序表的某个区间内进行查找。