线性表查找算法
![线性表查找算法](https://img.360docs.net/img9d/04qlek6kbtol1m7d90yw-d1.webp)
![线性表查找算法](https://img.360docs.net/img9d/04qlek6kbtol1m7d90yw-e2.webp)
第3章 线性表的查找算法
这里所说的查找,就是在一个给定的数据集合中搜素你指定的那个元素,查找的结果只能有两种:一种是找到所指定的元素,即查找成功,这时输出该元素在线性表中的位置信息;另一种结果是线性表中不存在该元素,宣告查找失败。
查找的方法很多,根据数据在表中的排列方式不同,可以选择不同的查找方法,其效率往往差别很大。本章,我们将分别叙述常用的几种查找方法。
3.1 顺序查找
顺序查找是最简单的查找方法,也是适应性最广的方法。它是从头开始,依次将表中的各个元素与指定的元素进行比较,直至在线性表中找到指定元素,输出位置信息,或者查遍整个线性表仍未找到而宣告失败。顺序查找算法非常直观简单,以字数据为例,程序流程图如图1所示,程序如下:
_________________________________________________________________________ //语法:
// C语言:
// int F_Find_In_Order(unsigned int Data_Addr,unsigned int Data_Length,
// unsigned int Value);
// 汇编:
// R1=[Data_Addr];
// R2=[Data_Length];
// R3=[Value];
// PUSH R1,R3 TO [SP];
// CALL F_Find_In_Order;
// [Find_Out]=R1
// POP R1,R3 FROM [SP]
//
//参数说明:Data_Addr:线性表首地址
// Data_Length:查找数据缓冲区的大小,即数据元素的个数
// Value:要查找的数据
//返回值: R1---查找到的对象
//破坏的寄存器:R1,R2,R3,R4
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// .IRAM
北阳电子内部技术资料
2 第一章 凌阳单片机简介
.PUBLIC G_Find_Flag;
.VAR G_Find_Flag=0; //查找结果标志单元,查找成功为1,反之为零
.CODE
.PUBLIC _F_Find_In_Order
.PUBLIC F_Find_In_Order
_F_Find_In_Order:
F_Find_In_Order: .PROC
PUSH BP,BP TO [SP];
BP=SP; //BP指向堆栈
BP+=4; //BP指向第一个参数位置
R4=[BP++]; //取线性表首址
R2=[BP++]; //取线性表元素个数
JZ L_Exit_Find_10; //为零,结束查找
R3=[BP]; //取查找对象
L_Find_Loop:
R1=[R4]; //取线性表中一个数据元素
CMP R3,R1; //比较数据元素和查找目标
JE L_Exit_Find_00; //是查找目标,查找结束
R4+=1; //不是查找目标,指向下一个数据元素
R2-=1; //数据元素减一
JNZ L_Find_Loop; //所有元素比较完吗?
R1=0 //返回值置零
[G_Find_Flag]=R1; //设置失败标志
JMP L_Exit_Find_10; //退出查找
L_Exit_Find_00:
R4=1; //设置成功标志
[G_Find_Flag]=R4;
L_Exit_Find_10:
POP BP,BP FROM [SP];
RETF
.ENDP
_________________________________________________________________________
- 2 -
第一章 凌阳单片机简介3
图1 无序线性表的顺序查找算法流程图
3.2折半查找
当线性表中的数据元素是无序排列时,只能采用顺序查找算法,不查完最后一个元素就不能判断线性表中没有这个元素,如果线性表先用排序算法进行过整理,成为有序线性表,则可以用折半查找算法来提高效率。
折半查找算法先取线性表的中间元素与查找对象进行比较,如果正好是要查找对象,则查找成功;如果该元素比查找对象大,则要查找的对象只可能在线性表的前半部分,因为后半部分的元素比查找对象更大,可以将后半部分从查找范围中舍去,使查找范围缩小一半,下一步在剩下的一半中继续取其中间元素进行比较和判断,又可以舍去这一部分的一半,在另一半重复上述操作。如此进行下去,直至找到指定对象(成功)或查找范围消失(失败)。因为这种算法每次将查找范围折半,取其中间元素进行比较判断,故称为折半查找算法。
在折半查找的过程中,时刻要变化查找范围,为此需要三个指针变量来配合操作,它们分别指向查找范围的低端(前端)、中点、高端(后端)。开始时整个线性表都在查找范围之中,低端指针指向线性表的首址,高端指针指向线性表的最后一个元素。
北阳电子内部技术资料
4 第一章 凌阳单片机简介
中点指针的值可以由低端指针和高端指针平均求得。当中点元素的值大于查找对象时,说明查找对象只可能在低半部分,新的查找范围和原来的查找范围相比,低端没有变化,高端位置应该调整到比当前中点位置还低一的地方。反之,当中点元素的值小于查找对象时,说明查找对象只可能在高半部分,新的查找范围和原来的查找范围相比,高端没有变化,低端位置应该调整到比当前中点位置还高一的地方,每进行一次查找范围的调整,都应该对新的查找范围进行核实,如果低端指针的值比高端指针的值还要大,则新的查找范围是没有意义的,表示查找范围已经消失,查找以失败告终,以字数据为例,折半查找算法程序流程图如图2所示,程序如下:
图2 有序线性表的折半查找算法流程图
_________________________________________________________________________ //语法:
// C语言:
// int F_Find_Reduce_By_Half(unsigned int LowAddr,unsigned int
// Number,unsigned int Value);
// 汇编:
// R1=[LowAddr];
// R2=[Number];
// R3=[Value];
// PUSH R1,R3 TO [SP];
// CALL F_Find_Reduce_By_Half;
- 4 -
第一章 凌阳单片机简介5 // [Find_Out]=R1
// POP R1,R3 FROM [SP]
//
//参数说明:LowAddr:线性表首地址
// Number:查找数据缓冲区的大小,即数据元素的个数
// Value:要查找的数据
//返回值: R1---查找到的对象
//破坏的寄存器:R1,R2,R3,R4
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// .IRAM
.PUBLIC G_Find_Flag;
.VAR G_Find_Flag=0; //查找结果标志单元,查找成功为1,反之为零
.VAR I_HighAddr=0; //高地址指针
.CODE
.PUBLIC _F_Find_Reduce_By_Half
.PUBLIC F_Find_Reduce_By_Half
_F_Find_Reduce_By_Half: .PROC
F_Find_Reduce_By_Half:
PUSH BP,BP TO [SP]
BP=SP; //BP指向堆栈
BP+=4; //BP指向第一个参数位置
R1=[BP++]; //取线性表首址
R2=[BP++]; //取数据元素个数
JZ L_EXIT_FIND; //数据元素个数为零,退出查找
R3=[BP]; //取要查找的数据
R4=R1; //线性表首址暂存R4
R4+=R2; //线性表首址加数据元素个数
R4-=1; //线形表最后一个元素的地址
[I_HighAddr]=R4; //保存高地址
L_Find_DATA:
R4-=R1; //高地址减去低地址
JNB L_Find_DATA_00;//高地址小于低地址结束查找
L_EXIT_FIND:
R1=0 //返回值单元清零
[G_Find_Flag]=R1; //设置查找不成功标志
PUSH BP,BP TO [SP];
RETF;
L_Find_DATA_00:
R4=[I_HighAddr]; //取高地址
R4+=R1; //高地址加低地址
R4=R4 LSR 1; //地址和除二取中间地址
北阳电子内部技术资料
6 第一章 凌阳单片机简介
R2=[R4]; //取中间数
CMP R2,R3; //是要查找的数吗?
JZ L_FIND_OUT; //是要查找的数
JNB L_Find_DATA_10;//大于要查找的数
R4+=1; //小于要查找的数,高地址加一
R1=R4; //高地址送给R1作为当前低地址,高地址不变
JMP L_Find_DATA;
L_Find_DATA_10:
R4-=1; //高地址减一
[I_HighAddr]=R4; //高地址减一,作为当前高地址,低地址不变JMP L_Find_DATA;
L_FIND_OUT:
R1=R2; //查找结果存于R1作为返回值
R2=1; //R2置一
[G_Find_Flag]=R2; //设置查找成功标志
POP BP,BP FROM [SP];
RETF;
.ENDP;
_________________________________________________________________________
3.3分块查找
分块查找又称索引查找,在生活中我们经常使用这种查找方法。例如,我们要在一本书中查找所需资料,一般是先查它的目录,找到这些资料所在章节的起始页面,然后直接翻到这一页,再从这一页仔细开始阅读,查找所需资料,这显然比从头开始查找要快捷的多。我们之所以能在厚厚的书籍中迅速找到所要的内容,是因为事先把所有的内容按照一个特定的规律分成若干块(章),每一块中又分成若干小块(节),安排好了它们的位置(页面),然后给出一张目录表,有了这张目录表,才使查找变得迅速。这张目录表又称为索引表,所以这种查找算法又称为索引查找算法。我们以一个大批数据的集合为例,把它们分成若干块,每一块内部的元素可以是有序的(块内有序),也可以是无序的(块内无序),但要求后一块中的各个元素都比前一块中的任何元素都大(块间有序)。然后列出一张索引表,索引表的每一项对应一个数据块,故索引表的项数等于数据块的的块数。索引表中的每一项又包含两个内容,一个内容是对应数据块的起始地址,另一个内容是对应数据块中所有数据的最大值。当数据量很大时,可以建立多级索引表。显然,建立索引表需要开销一些存储单元,整个数据的分块和索引表的建立是事先完成的。
分块查找算法分为两步完成,第一步将查找对象依次和索引表中各块的的最大值进行比较,确定有可能包含查找对象的那一块的首址,同时由该块首址和下一块的首址计算出该块的范围;第二步在指定块内进行查找,如果块内有序就可以采用折半查找法,如果块内无序就只好采用顺序查找算法。为了得到最后一块数据块的范围,我们可以在索引表的最后增加一项虚拟块的边界地址,虚拟块的最大值没有意义。下面我们以查找一个字数据对象为例来说明分块查找的过程,数据块内是无序的。程序流程图如图3所示,程序如下:
- 6 -
第一章 凌阳单片机简介7
图3 分块查找算法流程图
_________________________________________________________________________ //语法:
// C语言:
// int F_Find_In_Block(unsigned int Index_Addr,unsigned int
// Number,unsigned int Value);
// 汇编:
// R1=[Index_Addr];
// R2=[Number];
// R3=[Value];
// PUSH R1,R3 TO [SP];
// CALL F_Find_In_Block;
// [Find_Out]=R1
北阳电子内部技术资料
8 第一章 凌阳单片机简介
// POP R1,R3 FROM [SP]
//
//参数说明:LowAddr:线性表首地址
// Number:查找数据缓冲区的大小,即数据元素的个数
// Value:要查找的数据
//返回值: R1---查找到的对象
//破坏的寄存器:R1,R2,R3,R4
//////////////////////////////////////////////////////////////////// .IRAM
.PUBLIC G_Find_Flag;
.VAR G_Find_Flag=0; //查找结果标志单元,查找成功为1,反之为零
.VAR I_Max_Data=0; //每块中最大的数据
.VAR I_Block_Addr=0; //每块的起始地址
.CODE
.PUBLIC _F_Find_In_Block
.PUBLIC F_Find_In_Block
_F_Find_In_Block: .PROC
F_Find_In_Block:
PUSH BP,BP TO [SP];
BP=SP; //BP指向堆栈
BP+=4; //BP指向第一个参数位置
R1=[BP++]; //索引表首址
R2=[R1];
[I_Block_Addr]=R2; //数据块地址
R2=[BP++]; //数据块的个数
JZ L_Exit_Find_00; //数据块的个数为零,退出查找
R3=[BP]; //要查找的数据
L_Find_Block:
R4=[++R1]; //取数据块最大元素的地址
R4=[R4]; //取数据块最大元素
CMP R4,R3; //与查找元素比较
JNB L_Find_Block_Out;//大于查找元素
R2-=1; //小于查找元素,数据块个数减一
CMP R2,0; //每一个数据块都查找过吗?
JB L_Exit_Find_00; //每一个数据块都查找过
PUSH R2,R2 TO [SP]; //R2入栈
R1-=1; //R1减一
R2=[R1]; //取出数据块首址
[I_Block_Addr]=R2; //数据块首址保存
R1+=2; //指向下一个数据块的首址
POP R2,R2 FROM [SP]; //R2出栈
JMP L_Find_Block;
- 8 -
第一章 凌阳单片机简介9
L_Find_Block_Out:
R2=[++R1]; //取下一个数据块的首址
R4=[I_Block_Addr]; //取数据块首址
R2=R2-R4; //计算数据块中元素个数
L_Find_Data_00:
R1=[R4++]; //在数据块中用顺序查找法查找目标元素
R2-=1;
JZ L_Exit_Find_00;
CMP R1,R3;
JNZ L_Find_Data_00;
R2=1; //设置查找成功
[G_Find_Flag]=R2;
JMP L_Exit_Find;
L_Exit_Find_00:
R1=0; //返回单元清零
[G_Find_Flag]=R1; //设置查找不成功标志
L_Exit_Find:
POP BP,BP FROM [SP];
RETF;
.ENDP;
_________________________________________________________________________
3.4 串的匹配
串也是一种线性表。一般情况下,串的一个元素占一个字节(在十六位单片机中占一个字),如字符串;所以称串为有限的字符序列。串类似于数组,串的存储结构有顺序存储和链式存储。顺序存储的串便于访问(如匹配),而链式存储的串便于插入和删除等操作,在单片机中,基本上都是采用顺序存储方式。对于一个串,我们起码要知道它的两条属性,一是它在存储器中的首址,二是它的长度;若长度为零,称为空串。一个串可以包含若干个子串;所谓子串就是指串中任意个连续字符组成的子序列。
设串S=“MICROCOMPUTER”;串T1=“MIC”;T2=“CROCO”;则T1,T2就是串S的子串,我们不妨称S为主串。当然,一个子串中又可以子串,它们自然也是串S的子串。
所谓串的匹配又称为模式匹配,实际上也是一种查找。就是在一个主串S中寻找一个给定的模式串T;若匹配成功,则模式串T就是主串S的子串,且给出串T在串S 中的位置。
例如,设主串=“THE WONDERFUL MACHINE!”,待匹配的模式串有两个,分别是T1=“RFUL”;和T2=“MACHIN”。则,串T1在主串S中的位置序号是10,串T2在主串S 中的位置序号是15。这里的位置序号是相对于主串S的第一个元素,改变搜索起点,这些位置也相对变化。在实际模式匹配算法中,当匹配成功时,一般返回模式串在主串中的起始位置。
有一种简单直观的模式匹配法,简称BF算法(Brute-Force算法),这种算法的基本思路是:把模式串当作一个模板,先和主串前端对齐,然后进行比较,如果完全相
北阳电子内部技术资料
10 第一章 凌阳单片机简介
- 10 -
同则匹配成功。如果有差异则将模板向后移动一个位置,即将模板的前端和主串的第二个元素对齐,继续进行下一轮比较,直到匹配成功或者将模板移动到主串之后而匹配失败。
当主串和模式串一样长时,进行一轮匹配操作便可得到结果(主串中是否包含模式串),如果主串比模式串长度大一,则最多需要进行两轮匹配操作便可得到结果。依次类推,设主串S 的长度为N ,模式串T 的长度为M (不大于N ),则最多只要进行N-M+1轮匹配操作就可以得到结果。在每轮匹配操作的过程中,将模式串的各个元素依次和主串中的元素进行比较,由于模式串的长度为M ,故最多进行M 次比较便可得到结果(本轮匹配操作是成功还是失败)。主串一般比较长,如果是一个固定文件(如词典)通常是固化在EPROM 中,如果是动态文件(如正在输入和编辑中的文件)则存放在片外RAM 中,模式串一般简短,为了操作方便,将其存放在片内RAM 中为宜。我们以一个不超过256字的主串为例,BF 算法的程序流程图如图4所示,程序如下:
__________________________________________________________________________ //语法:
//C 语言: // int F_Find_By_Brute_Force(unsigned int Main_String_Addr,unsigned int
// Main_String_Length,unsigned int Find_String_Addr, // unsigned int Find_String_Length);
//汇编:
// R1=
[Main_String_Addr];
// R2=[Main_String_Length];
// R3=[Find_String_Addr];
// R4=[Find_String_Length]
// PUSH R1,R4 TO [SP];
// CALL F_Find_By_Brute_Force;
// [Find_Out]=R1
// POP R1,R4 FROM [SP]
//参数说明: Main_String_Addr: 主串首地址
// Main_String_Length: 主串长度
// Find_String_Addr: 模式串首地址
// Find_String_Length: 模式串长度
//返回值: R1---查找到的对象
//破坏的寄存器:R1,R2,R3,R4
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// .IRAM
.PUBLIC G_Find_Flag;
.VAR G_Find_Flag=0; //查找结果标志单元,查找成功为1,反之为零 .VAR I_MainStr_Temp_Addr=0; //主串首地址
.VAR I_FindStr_Temp_Addr=0; //模式串地址
.VAR I_FindStr_Temp_Length=0; //模式串长度
.VAR I_MainStrTempAddr=0; //主串地址暂存单元
第一章 凌阳单片机简介11
.VAR I_FindStrTempAddr=0; //模式串地址暂存单元
.CODE
.PUBLIC _F_Find_By_Brute_Force
.PUBLIC F_Find_By_Brute_Force
_F_Find_By_Brute_Force: .PROC
F_Find_By_Brute_Force:
PUSH BP,BP TO [SP];
BP=SP+1; //BP指向堆栈
BP+=3; //BP指向第一个参数位置
R1=[BP++]; //主串首址
[I_MainStr_Temp_Addr]=R1; //主串首址暂存
[I_MainStrTempAddr]=R1;
R2=[BP++]; //主串长度
R3=[BP++]; //模式串首址
[I_FindStr_Temp_Addr]=R3; //模式串首址暂存
[I_FindStrTempAddr]=R3;
R4=[BP++]; //模式串长度
[I_FindStrTempAddr]=R4;
R2-=R4; //主串长度减去模式串长度
JB L_Exit_Find_00; //模式串长度大于主串长度,退出匹配操作R2+=1; //模式串长度小于主串长度,得到最大匹配操
//作遍数
L_BF_10:
R1=[R1]; //取主串的一个元素
R3=[R3]; //取模式串一个元素
CMP R1,R3; //相等吗?
JNZ L_BF_20; //不相等
R1=[I_MainStr_Temp_Addr]; //相等,主串指针加一指向下一个元素
R1+=1;
[I_MainStr_Temp_Addr]=R1;
R3=[I_FindStr_Temp_Addr]; //模式串指针加一指向下一个元素R3+=1;
[I_FindStr_Temp_Addr]=R3;
R4-=1; //模式串元素比较完否?
JNZ L_BF_10; //未完
R4=1; //比较完成
[G_Find_Flag]=R4; //设置匹配成功标志
R1=[I_MainStr_Temp_Addr]; //当前比较位置
R2=[I_FindStrTempAddr]; //取模式串长度
R1-=R2; //得到模式串匹配位置
POP BP,BP FROM [SP];
RETF;
北阳电子内部技术资料
12 第一章 凌阳单片机简介
L_BF_20:
R1=[I_MainStrTempAddr]; //主串指针加一
R1+=1;
[I_MainStrTempAddr]=R1; //保存当前主串指针位置
[I_MainStr_Temp_Addr]=R1; //初始化比较位置
R3=[I_FindStrTempAddr]; //取出模式串首址
[I_FindStr_Temp_Addr]=R3; //恢复模式串地址
R4=[I_FindStrTempAddr]; //恢复模式串比较次数
R2-=1; //所有元素比较完否?
JNZ L_BF_10; //未完
L_Exit_Find_00:
R1=0; //比较结束,返回单元清零
[G_Find_Flag]=R1; //设置不成功标志
L_Exit_Find:
POP BP,BP FROM [SP];
RETF
.ENDP
__________________________________________________________________________ 在BF算法中,当某一轮匹配失败之后,下一轮主串S的比较起始位置只能比上一轮的起始位置向前增加一个元素的地址,因此,BF算法的运行效率是很低的。我们完全可以充分利用上一轮匹配操作的结果和模式串本身的特点来提高本轮匹配操作的效率。例如,设主串为S=“ABCSERFABCDGKURQAC”,模式串为T=“ABCD”,第一轮匹配操作从主串和模式串的第一个元素开始比较,主串的前三个元素和模式串相同,比较到第四个元素时匹配失败(主串的第四个元素不是“D”)。按BF算法,下一轮应该将主串的“BCSE”和模式串进行匹配操作。事实上模式串第一个元素的内容是“A”没有必要从主串的第二个元素和第三个元素开始进行匹配操作,可以直接从刚才比较失败的第四个元素开始进行匹配操作(主串第四个元素虽然不是“D”,但有可能是“A”)。这样处理后,主串的指针在整个模式匹配过程中就不用后退了,从而大大提高了效率。在很多情况下模式串的第一个元素和其它元素是不同的可以采用这种改进的模式匹配算法来提高效率。如果不满足这个条件,,例如,模式串为“ABABC”,则算法要复杂一些,有一种称为KMP的算法可以处理这种情况,有兴趣的读者可以阅读参考文献[2]中的有关内容。事实上,我们这里的改进算法就是KMP算法的一个特例,只是因为它符合大多数实际情况,没有必要搞得象标准的KMP算法那样复杂。在满足模式串的第一个元素和模式串的其它元素都不相同的条件下,改进算法的程序流程图如图5所示,程序如下:
__________________________________________________________________________ //语法:
// C语言:
// int _F_Find_By_Q_Brute_Force(unsigned int Main_String_Addr,unsigned // int Main_String_Length,unsigned int
// Find_String_Addr, unsigned int
// Find_String_Length);
// 汇编:
- 12 -
第一章 凌阳单片机简介13
// R1=[Main_String_Addr];
// R2=[Main_String_Length];
// R3=[Find_String_Addr];
// R4=[Find_String_Length]
// PUSH R1,R4 TO [SP];
// CALL _F_Find_By_Q_Brute_Force;
// [Find_Out]=R1
// POP R1,R4 FROM [SP]
//参数说明: Main_String_Addr: 主串首地址
// Main_String_Length: 主串长度
// Find_String_Addr: 模式串首地址
// Find_String_Length: 模式串长度
//返回值: R1---查找到的对象
//破坏的寄存器:R1,R2,R3,R4
////////////////////////////////////////////////////////////////////////// .IRAM
.PUBLIC G_Find_Flag;
.VAR G_Find_Flag=0; //查找结果标志单元,查找成功为1,反之为零
.VAR I_MainStr_Temp_Addr=0; //主串首地址
.VAR I_FindStr_Temp_Addr=0; //模式串地址
.VAR I_FindStr_Temp_Length=0; //模式串长度
.VAR I_MainStrTempAddr=0; //主串地址暂存单元
.VAR I_FindStrTempAddr=0; //模式串地址暂存单元
.CODE
.PUBLIC _F_Find_By_Q_Brute_Force
.PUBLIC F_Find_By_Q_Brute_Force
_F_Find_By_Q_Brute_Force: .PROC
F_Find_By_Q_Brute_Force:
PUSH BP,BP TO [SP];
BP=SP+1; //BP指向堆栈
BP+=3; //BP指向第一个参数位置
R1=[BP++]; //主串首址
[I_MainStr_Temp_Addr]=R1; //主串首址暂存
[I_MainStrTempAddr]=R1;
R2=[BP++]; //主串长度
R3=[BP++]; //模式串首址
[I_FindStr_Temp_Addr]=R3; //模式串首址暂存
[I_FindStrTempAddr]=R3;
R4=[BP++]; //模式串长度
[I_FindStrTempAddr]=R4;
CMP R2,R4 //主串长度减去模式串长度
JB L_Exit_Find_00; //模式串长度大于主串长度,退出匹配操作
L_Q_BF_10:
R1=[R1]; //取主串的一个元素
北阳电子内部技术资料
14 第一章 凌阳单片机简介
R3=[R3]; //取模式串一个元素
CMP R1,R3; //相等吗?
JNZ L_Q_BF_20; //不相等
R1=[I_MainStr_Temp_Addr]; //相等,主串指针加一指向下一个元素
R1+=1;
[I_MainStr_Temp_Addr]=R1;
R3=[I_FindStr_Temp_Addr]; //模式串指针加一指向下一个元素
R3+=1;
[I_FindStr_Temp_Addr]=R3;
R2-=1; //主串尚未参与比较的元素个数减一
R4-=1; //模式串元素比较完否?
JNZ L_Q_BF_10; //未完
R1=1; //比较完成
[G_Find_Flag]=R1; //设置匹配成功标志
R1=[I_MainStr_Temp_Addr]; //当前比较位置
R2=[I_FindStrTempAddr]; //取模式串长度
R1-=R2; //得到模式串匹配位置
POP BP,BP FROM [SP];
RETF;
L_Q_BF_20:
R3=[I_FindStr_Temp_Addr]; //取当前比较位置
CMP R3,[I_FindStrTempAddr]; //是模式串的第一个元素吗?
JNZ L_Q_BF_30; //不是
R1=[I_MainStrTempAddr] //是第一个元素
R1+=1; //主串位置后移一位
[I_MainStrTempAddr]=R1;
[I_MainStr_Temp_Addr]=R1;
R2-=1; //主串未参与比较元素个数减一
R4=[I_FindStrTempAddr]; //设置模式串比较次数
L_Q_BF_30:
R3=[I_FindStrTempAddr];
CMP R2,R3; //未参与比较元素个数是否小于模式串长度 JB L_Exit_Find_00 //小于,退出匹配操作
R3=[I_FindStrTempAddr]; //大于等于恢复模式串首址
[I_FindStr_Temp_Addr]=R3;
JMP L_Q_BF_10; //继续比较
L_Exit_Find_00:
POP R2,R2 FROM [SP]
R1=0; //比较结束,返回单元清零
[G_Find_Flag]=R1; //设置不成功标志
L_Exit_Find:
POP BP,BP FROM [SP];
RETF
.ENDP
- 14 -
第一章 凌阳单片机简介15 __________________________________________________________________________
图4 模式匹配的BF算法
北阳电子内部技术资料
16 第一章 凌阳单片机简介
图5 改进的模式匹配BF算法
3.5 查找算法应用实例
- 16 -
第一章 凌阳单片机简介 北阳电子内部技术资料
17
有一台野外数据采集仪,将采集的数据保存在带掉点保护的片外RAM 中,它可以在野外工作一段较长的时间,
记录大量的数据,返回基地后
再通过串行通讯将数据传送
给通用计算机。在该仪器中,每一次采集的数据作为一个数据包,各个数据包顺序存放
在片外RAM 。每个数据包由起
始标志、数据块、结束标志组成。起始由六个字节组成,前三个字节的内容均为“FF”,后三个字节分别为BCD 码的月份、日期和批次,例如3月25
日第7批数据的起始标志为
“FF FF FF 03
07”。结束标志也由6个字节组成,前三个字节的内容均为
“EE”,后三个字节也是BCD 码的月份、日期和批次。数据块由若干数据元素组成,每个数据元素均为三个字节,第一个字节为类型码(说明数据类型),后两个字节为数值。为
了保证起始标志和结束标志
的专一性,在数据块中就不能出现连续的三个“FF”或三个
“EE”。为此,数据元素中的
数值部分用不包含“FF ”和“EE”的BCD 码表示。片外RAM
的容量为8K ,地址范围为
2000H-3FFFH ,其中2000H-203FH 为系统参数存储
区,用来存储采集数据的地址
范围为2040H-3FFFH。由于每个数据包的大小是不定的为
了节省存储空间,将各个数据
包顺序存放,并将2040H-3FFFH 的存储空间看成
环行空间,即3FFFH 单元的下
一个单元就是2040H 单元(绕过系统参数区)。在这些约定
下,为了读取某个数据包的数据,必须先找到这个数据包的起始标志,起始标志后面就是所需数据区。查找起始标志的算法显然是属于模式匹配法,模式串的前三个字节为固定的“FF”,后三个字节为变量,它的内容由人们指定。为了提高效率,不能采用
图6 查找起始标志的算法
18 第一章 凌阳单片机简介
BF算法;另一方面,由于前三个字节相同,也不能采用前面介绍的改进算法。针对这里的具体情况,我们将查找过程分为两步,先查找连续的“FF”字节片段,如果该片段的长度达到或超过三个字节再判断其后面的三个字节中的内容是否为指定的月份、日期和批次。由于片外RAM空间为环行结构,起始标志有可能正好处于折回位置例如在3FFEH和3FFFH中装下两个字节的“FF”,再在2040H-2043H装下剩下的四个字节“FF 03 25 07”。为了不遗漏这种情况,查找范围的长度必须略大于整个数据区,这里定为2000H(总数)-40H(参数区)+8=1FC8H。综上所述,查找起始标志的算法流程图如图6所示,程序如下:
__________________________________________________________________________ //数据格式:字
//语法:
// C语言:
// int F_Find_By_Flag(unsigned int Month,unsigned int Day,unsigned int // Number,unsigned int Flag,unsigned int Data_Addr, // unsigned int Data_Length);
// 汇编:
// R1=[Month];
// R2=[Day];
// R3=[Number];
// R4=[Flag]
// PUSH R1,R4 TO [SP];
// R1=[Data_Addr];
// R2=[Data_Length]
// PUSH R1,R2 TO [SP];
// CALL F_Find_By_Flag;
// [Find_Out]=R1
// POP R1,R2 FROM [SP]
// POP R1,R4 FROM [SP]
//参数说明:Month: 查找月份
// Day: 查找日期
// Number:查找批号
// Flag: 数据区起始标志
// Data_Addr:数据区首地址
// Data_Length:数据区长度
//返回值: R1---查找到的对象
//破坏的寄存器:R1,R2,R3,R4
////////////////////////////////////////////////////////////////////// .IRAM
.PUBLIC G_Find_Flag;
.VAR G_Find_Flag=0; //查找结果标志单元,查找成功为1,反之为零
.VAR I_Flag_Count=0; //起始标志计数单元
.VAR I_Month=0; //查找月份单元
.VAR I_Day=0; //查找日期单元
.VAR I_Number=0; //查找批号单元
- 18 -
第一章 凌阳单片机简介19
.VAR I_Flag=0; //查找标志单元
.VAR I_End_Addr=0; //数据区结束地址
.VAR I_Data_Addr=0; //数据区首址
.CODE
.PUBLIC _F_Find_By_Flag
.PUBLIC F_Find_By_Flag
_F_Find_By_Flag: .PROC
F_Find_By_Flag:
PUSH BP,BP TO [SP];
BP=SP+1; //BP指向堆栈
BP+=3; //BP指向第一个参数位置
R1=[BP++]; //月份
[I_Month]=R1;
R1=[BP++]; //日期
[I_Day]=R1;
R1=[BP++]; //批号
[I_Number]=R1;
R1=[BP++]; //起始标志
[I_Flag]=R1;
R1=[BP++]; //数据区首址
[I_Data_Addr]=R1;
R2=[BP++]; //缓冲区长度
R1+=R2; //计算结束地址
[I_End_Addr]=R1; //保存结束地址
R1=[I_Data_Addr];
R2=[BP] ; //最大访问长度
JZ L_Exit_Find_00; //访问长度为零,退出查找操作
L_FN_10:
R3=[R1]; //取一个数据
CMP R3,[I_Flag]; //是起始标志位吗?
JNZ L_FN_20; //不是
R3=[I_Flag_Count]; //是,取出计数器中的计数值
R3+=1; //计数值加一
[I_Flag_Count]=R3; //计数值保存于计数器
JMP L_FN_30; //继续查找
L_FN_20:
R3=[I_Flag_Count];
CMP R3,3; //已经有3个或3个以上的起始标志吗?
JB L_FN_30; //没有,继续查找
R3=0; //有,清除计数器
[I_Flag_Count]=R3;
R3=[R1]; //前面已经有3个或3个以上的起始标志,读取当前内容
CMP R3,[I_Month]; //是指定月份吗?
北阳电子内部技术资料
20 第一章 凌阳单片机简介
JNZ L_FN_30; //不是,继续查找
R3=[++R1]; //取下一个数据
CMP R3,[I_Day]; //是指定日期吗?
JNZ L_FN_30; //不是,继续查找
R3=[++R1]; //取下一个数据
CMP R3,[I_Number]; //是指定的批号吗?
JNZ L_FN_30; //不是,继续查找
R1=R1+1; //是,指针指向数据区
R2=1; //设置,查找成功标志
[G_Find_Flag]=R2;
POP BP,BP FROM [SP];
RETF
L_FN_30:
R1+=1; //调整指针指向下一个数据
CMP R1,[I_End_Addr];
JB L_Return_Here
R1=[I_Data_Addr]; //高于查找范围,恢复地址指针
L_Return_Here:
R2-=1; //所有元素都比较完了吗?
JNZ L_FN_10; //未完,继续比较
R1=0; //比较结束,返回单元清零
[G_Find_Flag]=R1; //设置不成功标志
L_Exit_Find_00:
POP BP,BP FROM [SP];
RETF;
.ENDP
______________________________________________________________________________________
- 20 -
数据结构顺序表的查找插入与删除
一、上机实验的问题和要求: 顺序表的查找、插入与删除。设计算法,实现线性结构上的顺序表的产生以及元素的查找、插入与删除。具体实现要求: 1.从键盘输入10个整数,产生顺序表,并输入结点值。 2.从键盘输入1个整数,在顺序表中查找该结点的位置。若找到,输出结点的位置;若找 不到,则显示“找不到”。 3.从键盘输入2个整数,一个表示欲插入的位置i,另一个表示欲插入的数值x,将x插 入在对应位置上,输出顺序表所有结点值,观察输出结果。 4.从键盘输入1个整数,表示欲删除结点的位置,输出顺序表所有结点值,观察输出结果。 二、源程序及注释: #include
实现顺序表各种基本运算的算法
实现顺序表各种基本运算的算法 要求:编写一个程序(algo2_1.cpp)实现顺序表的各种基本操作,并在此基础上设计一个主程序(exp2_1.cpp)完成如下功能: (1)初始化顺序表L (2)依次采用尾插法插入a,b,c,d,e元素 (3)输出顺序表L (4)输出顺序表L的长度 (5)判断顺序表L是否为空 (6)输出顺序表L的第3个元素 (7)输出元素a的位置 (8)在第4个元素位置上插入f元素 (9)输出顺序表L (10)删除L的第3个元素 (11)输出顺序表L (12)释放顺序表L /*文件名:exp2-1.cpp*/ #include
线性表的顺序存储结构定义和基本操作算法实现
#include "" /***********************线性表的顺序存储结构定义*******************/ #define MAX 11 /*线性表可能达到的最大长度值*/ typedef int datatype; typedef struct {datatype data[MAX]; int last;}list; /************************1.线性表的初始化***************************/ void init(list *lp) {lp->last=0;} /************************2.求线性表的长度***************************/ int length(list *lp) { return (lp->last);} /***************3.插入运算,在表第i个位置插入一个值为 x的新元素******/ void insert(list *lp,int i,datatype x) { int j; if(lp->last==MAX-1) printf("Overflow!\n"); /*表已满*/ else if(i<1||i>lp->last+1) printf("Error!\n"); /*插入位置错误*/ else {for(j=lp->last;j>=i;j--) lp->data[j+1]=lp->data[j]; /*数据元素后移*/ lp->data[i]=x; /*插入x */ lp->last++; /*表长度加1*/ } } /***************4.删除运算,在表中删除第i个数据元素***************/ void delete(list *lp,int i) { int j; if(i<1||i>lp->last) /*检查空表及删除位置的合法性*/ printf("The %dth element is not exist!",i); /*不存在第i个元素*/ else {for(j=i+1;j<=lp->last;j++) lp->data[j-1]=lp->data[j]; /*向前移动元素*/ lp->last--; /*表长度减1 */ } } /*****************5.查找运算,在表中查找x数据元素*****************/ int locate(list *lp,datatype x) { int i=lp->last; while(i>0 && lp->data[i]!=x)i--; return i; }
线性表的顺序存储结构定义和基本操作算法实现
/************线性表的顺序存储结构定义和基本操作算法实现************/ #include "stdio.h" /***********************线性表的顺序存储结构定义*******************/ #define MAX 11 /*线性表可能达到的最大长度值*/ typedef int datatype; typedef struct {datatype data[MAX]; int last;}list; /************************1.线性表的初始化***************************/ void init(list *lp) {lp->last=0;} /************************2.求线性表的长度***************************/ int length(list *lp) { return (lp->last);} /***************3.插入运算,在表第i个位置插入一个值为x的新元素******/ void insert(list *lp,int i,datatype x) { int j; if(lp->last==MAX-1) printf("Overflow!\n"); /*表已满*/ else if(i<1||i>lp->last+1) printf("Error!\n"); /*插入位置错误*/ else {for(j=lp->last;j>=i;j--) lp->data[j+1]=lp->data[j]; /*数据元素后移*/ lp->data[i]=x; /*插入x */ lp->last++; /*表长度加1*/ } } /***************4.删除运算,在表中删除第i个数据元素***************/ void delete(list *lp,int i) { int j; if(i<1||i>lp->last) /*检查空表及删除位置的合法性*/ printf("The %dth element is not exist!",i); /*不存在第i个元素*/ else {for(j=i+1;j<=lp->last;j++) lp->data[j-1]=lp->data[j]; /*向前移动元素*/ lp->last--; /*表长度减1 */ } } /*****************5.查找运算,在表中查找x数据元素*****************/ int locate(list *lp,datatype x) { int i=lp->last; while(i>0 && lp->data[i]!=x)i--; return i;
实验报告一顺序表的操作
《数据结构》实验报告一 系别:班级: 学号:姓名: 日期:指导教师: 一、上机实验的问题和要求: 顺序表的查找、插入与删除。设计算法,实现线性结构上的顺序表的产生以及元素的查找、插入与删除。具体实现要求: 从键盘输入10个整数,产生顺序表,并输入结点值。 从键盘输入1个整数,在顺序表中查找该结点的位置。若找到,输出结点的位置;若找不到,则显示“找不到”。 从键盘输入2个整数,一个表示欲插入的位置i,另一个表示欲插入的数值x,将x插入在对应位置上,输出顺序表所有结点值,观察输出结果。 从键盘输入1个整数,表示欲删除结点的位置,输出顺序表所有结点值,观察输出结果。二、程序设计的基本思想,原理和算法描述: (包括程序的结构,数据结构,输入/输出设计,符号名说明等) 三、源程序及注释:
#include <> /*顺序表的定义:*/ #define ListSize 100 /*表空间大小可根据实际需要而定,这里假设为100*/ typedef int DataType; /*DataType可以是任何相应的数据类型如int, float或char*/ typedef struct { DataType data[ListSize]; /*向量data用于存放表结点*/ int length; /*当前的表长度*/ }SeqList; /*子函数的声明*/ void CreateList(SeqList * L,int n); /*创建顺序表函数*/ int LocateList(SeqList L,DataType x); /*查找顺序表*/ void InsertList(SeqList * L,DataType x,int i); /*在顺序表中插入结点x*/ void DeleteList(SeqList * L,int i);/*在顺序表中删除第i个结点*/ void PrintList(SeqList L,int n); /*打印顺序表中前n个结点*/ void main() { SeqList L; int n=10,x,i; /*欲建立的顺序表长度*/ =0;
数据结构 第九章 查找 作业及答案
第九章查找 一、填空题 1. 在数据的存放无规律而言的线性表中进行检索的最佳方法是。 2. 线性有序表(a 1,a 2 ,a 3 ,…,a 256 )是从小到大排列的,对一个给定的值k,用二分法检索 表中与k相等的元素,在查找不成功的情况下,最多需要检索次。设有100个结点,用二分法查找时,最大比较次数是。 3. 假设在有序线性表a[1..20]上进行折半查找,则比较一次查找成功的结点数为1;比较两 次查找成功的结点数为 2 ;比较四次查找成功的结点数为 ,其下标从小到大依次是 ____,平均查找长度为。 4.折半查找有序表(4,6,12,20,28,38,50,70,88,100),若查找表中元素20,它将依次与表中元素比较大小。 5. 在各种查找方法中,平均查找长度与结点个数n无关的查找方法是。 6. 散列法存储的基本思想是由决定数据的存储地址。 7. 有一个表长为m的散列表,初始状态为空,现将n(n 一判断题 1.顺序查找法适用于存储结构为顺序或链接存储的线行表。 2.一个广义表可以为其他广义表所共享。 3.快速排序是选择排序的算法。 4.完全二叉树的某结点若无左子树,则它必是叶子结点。 5.最小代价生成树是唯一的。 6.哈希表的结点中只包含数据元素自身的信息,不包含任何指针。 7.存放在磁盘,磁带上的文件,即可意识顺序文件,也可以是索引文件。8.折半查找法的查找速度一定比顺序查找法快。 二选择题 1.将两个各有n个元素的有序表归并成一个有序表,其最少的比较次数是()。 A. n B. 2n-1 C. 2n D. n-1 2.在文件"局部有序"或文件长度较小的情况下,最佳内部排序的方法是()。 A. 直接插入排序 B.气泡排序 C. 简单选择排序 D. 快速排序 3.高度为K的二叉树最的结点数为()。 A. 2 4.一个栈的输入序列是12345,则占的不可能的输出序列是() A.54321 B. 45321 C.43512 D.12345 5.ISAM文件和V ASM文件属于() A索引非顺序文件 B. 索引顺序文件 C. 顺序文件 D. 散列文件 6. 任何一棵二叉树的叶子结点在先序,中序和后序遍历序列中的相对次序() A. 不发生变化 B. 发生变化 C. 不能确定 D. 以上都不对 7.已知某二叉树的后序遍历序列是dabec, 中序遍历序列是debac , 它的前序遍历是()。 A. acbed B. decab C. deabc D.cedba 三.填空题 1.将下图二叉树按中序线索化,结点的右指针指向(),Y的左指针指向() B D C X E Y 2.一棵树T中,包括一个度为1的结点,两个度为2的结点,三个度为3的结点,四各度为4的结点和若干叶子结点,则T的叶结点数为() 实现顺序表的各种基本运算 一、实验目的 了解顺序表的结构特点及有关概念,掌握顺序表的各种基本操作算法思想及其实现。 二、实验内容 编写一个程序,实现顺序表的各种基本运算: 1、初始化顺序表; 2 、顺序表的插入; 3、顺序表的输出; 4 、求顺序表的长度 5 、判断顺序表是否为空; 6 、输出顺序表的第i位置的个元素; 7 、在顺序表中查找一个给定元素在表中的位置; 8、顺序表的删除; 9 、释放顺序表 三、算法思想与算法描述简图 主函数main 四、实验步骤与算法实现 #in clude 实验二线性表的基本操作 一、实验目的 1.掌握用C++/C语言调试程序的基本方法。 2.掌握线性表的顺序存储和链式存储的基本运算,如插入、删除等。 二、实验要求 1.C++/C完成算法设计和程序设计并上机调试通过。 2.撰写实验报告,提供实验结果和数据。 3.分析算法,要求给出具体的算法分析结果,包括时间复杂度和空间复杂度,并简要给出算法设计小结和心得。 三、实验内容: 1. 分析并运行以下各子程序的主要功能。 程序1:顺序存储的线性表和运算 #include 1. 分别画出在线性表(a,b,c,d,e,f,g)中进行折半查找,以查关键字等于e、f和g的过程。 (1)查e Step 1: a b c d e f g ↑↑↑ low mid high d 实验一线性表的基本操作 一、实验目的 1. 熟悉C/C++语言上机环境; 2. 掌握线性表的基本操作:查找、插入、删除等运算在顺序存储、链式存储结构上的运算。 二、实验环境 1. 装有Visual C++6.0的计算机。 2. 本次实验共计2学时。 三、实验内容 1. 建立顺序表,基本操作包括:初始化、建立顺序表、输出顺序表、判断是否为空、取表中第i个元素、查找、插入和删除。并在主函数中完成对各种函数的测试。 2. 设有两个非递增有序的线性表A和B,均已顺序表作为存储结构。编写算法实现将A表和B表合并成一个非递增有序排列的线性表(可将线性表B插入线性表A中,或重新创建线性表C)。 3. 建立单链表,基本操作包括:初始化、判断是否为空、取表中第i个元素、查找、插入和删除。并在主函数中完成对各种函数的测试。 四、源程序 #include 一、选择题 ( )7、下面关于二分查找的叙述正确的是。 A)表必须有序,表可以顺序方式存储,也可以链表方式存储; C)表必须有序,而且只能从小到大排列; B)表必须有序且表中数据必须是整型,实型或字符型; D)表必须有序,且表只能以顺序方式存储; ( ) 14.长度为12的有序表采用顺序存储结构,使用二分查找技术,在等概率情况下,查找成功时的平均查找长度是。 A. 37/12 B. 62/13 C. 39/12 D. 49/13 ( ) 14、折半查找法要求查找表中各元素的关键字必须是排列。 A)递增或递减 B)递增 C)递减 D)无序 ( ) 13、一棵7阶B-树的根结点及非根分支结点所包含的关键字的个数至少分别为A)1,3 B)2,4 C)3,5 D) 6,6 2、设有100个元素,用折半查找法进行查找时,在查找成功的情况下,最大比较次数是_____ 。 A.100 B.50 C.99 D.7 4、指出在顺序表{2、 5、7、10、14、15、18、23、35、41、52}中,用二分法查找12,需做多少次比较。 ______ A、2 B、3 C、4 D、5 6、从二叉排序树中查找一个元素时,其时间复杂度大致为________。 A、 O(n) B、 O(1) C、 O(log2n) D、 O(n2) 1.顺序查找法适合于存储结构为()的线性表。 (A)散列存储(B)顺序存储或链接存储(C)压缩存储(D)索引存储 2.对线性表进行二分查找时,要求线性表必须()。 (A)以顺序方式存储(B)以链接方式存储 (C)以顺序方式存储,且结点按关键字有序排序 (D)以链接方式存储,且结点按关键字有序排序 3.采用顺序查找方法查找长度为n的线性表时,每个元素的平均查找长度为() (A)n (B)n/2(C)(n+1)/2(D)(n-1)/2 4.采用二分查找方法查找长度为n的线性表时,每个元素的平均查找长度为() (A)O(n2)(B)O(log2n)(C)O(n)(D)O(log2n) 5.二分查找和二叉排序树的时间性能()。 (A)相同? (B)不相同? (C)无法比较 6.有一个有序表为{1,3,9,12,32,41,45,62,75,77,82,95,100},当二分查找值为82的结点时,()次比较后查找成功。 (A)1(B)2(C)4(D)8 8.有一个长度为12的有序表,按二分查找法对该表进行查找,在表内各元素等概率情况下查找 已知线性表(a1 a2 a3 …an)按顺序存于内存,每个元素都是整数,试设计用最少时间把所有值为负数的元素移到全部正数值(假设0为正数)元素前边的算法:例:(x,-x,-x,x,x,-x …x)变为(-x,-x,-x…x,x,x)。 .两个整数序列A=a1,a2,a3,…,am和B=b1,b2,b3,…,bn已经存入两个单链表中,设计一个算法,判断序列B是否是序列A的子序列。 设用带头结点的双向循环链表表示的线性表为L=(a1,a2, …a n)。写出算法将L改造成:L=(a1,a3,…a n,…a4,a2)。 已知A、B、C是三个顺序表且其元素按递增顺序排列,每个表中元素均无重复。在表A删去既在表B中出现又在表C中出现的元素。试设计实现上述删除操作的算法Delete。 在一个递增有序的线性表中,有数值相同的元素存在。若存储方式为单链表,设计算法去掉数值相同的元素,使表中不再有重复的元素。例如:(7,10,10,21,30,42,42,42,51,70)将变作(7,10,21,30,42,51,70)。 假设有两个按元素值递增次序排列的线性表,均以单链表形式存储。请编写算法将这两个单链表归并为一个按元素值递减次序排列的单链表,并要求利用原来两个单链表的结点存放归并后的单链表。 试编写在带头结点的单链表中删除(一个)最小值结点的(高效)算法。void delete(Linklist &L) 在一个递增有序的线性表中,有数值相同的元素存在。若存储方式为单链表,设计算法去掉数值相同的元素,使表中不再有重复的元素。例如:(7,10,10,21,30,42,42,42,51,70)将变作(7,10,21,30,42,51,70)。 设有一个正整数序列组成的有序单链表(按递增次序有序,且允许有相等的整数存在),试编写能实现下列功能的算法:(要求用最少的时间和最小的空间) ⑴确定在序列中比正整数x大的数有几个(相同的数只计算一次,如序列 {20,20,17,16,15,15,11,10,8,7,7,5,4}中比10大的数有5个); ⑵在单链表将比正整数x小的数按递减次序排列; ⑶将正整数(比)x大的偶数从单链表中删除。 算法设计与分析各种查找算法的性能测试 目录 摘要 (3) 第一章:简介(Introduction) (4) 1.1 算法背景 (4) 第二章:算法定义(Algorithm Specification) (4) 2.1 数据结构 (4) 2.2顺序查找法的伪代码 (5) 2.3 二分查找(递归)法的伪代码 (5) 2.4 二分查找(非递归)法的伪代码 (6) 第三章:测试结果(Testing Results) (8) 3.1 测试案例表 (8) 3.2 散点图 (9) 第四章:分析和讨论 (11) 4.1 顺序查找 (11) 4.1.1 基本原理 (11) 4.2.2 时间复杂度分析 (11) 4.2.3优缺点 (11) 4.2.4该进的方法 (12) 4.2 二分查找(递归与非递归) (12) 4.2.1 基本原理 (12) 4.2.2 时间复杂度分析 (13) 4.2.3优缺点 (13) 4.2.4 改进的方法 (13) 附录:源代码(基于C语言的) (15) 声明 ................................................................................................................ 错误!未定义书签。 摘要 在计算机许多应用领域中,查找操作都是十分重要的研究技术。查找效率的好坏直接影响应用软件的性能,而查找算法又分静态查找和动态查找。 我们设置待查找表的元素为整数,用不同的测试数据做测试比较,长度取固定的三种,对象由随机数生成,无需人工干预来选择或者输入数据。比较的指标为关键字的查找次数。经过比较可以看到,当规模不断增加时,各种算法之间的差别是很大的。这三种查找方法中,顺序查找是一次从序列开始从头到尾逐个检查,是最简单的查找方法,但比较次数最多,虽说二分查找的效率比顺序查找高,但二分查找只适用于有序表,且限于顺序存储结构。 关键字:顺序查找、二分查找(递归与非递归) 实验一:线性表的基本操作 【实验目的】 学习掌握线性表的顺序存储结构、链式存储结构的设计与操作。对顺序表建立、插入、删除的基本操作,对单链表建立、插入、删除的基本操作算法。 【实验内容】 1.顺序表的实践 1) 建立4个元素的顺序表s=sqlist[]={1,2,3,4,5},实现顺序表建立 的基本操作。 2) 在sqlist []={1,2,3,4,5}的元素4和5之间插入一个元素9,实现 顺序表插入的基本操作。 3) 在sqlist []={1,2,3,4,9,5}中删除指定位置(i=5)上的元素9, 实现顺序表的删除的基本操作。 2.单链表的实践 3.1) 建立一个包括头结点和4个结点的(5,4,2,1)的单链表,实现单链 表建立的基本操作。 2) 将该单链表的所有元素显示出来。 3) 在已建好的单链表中的指定位置(i=3)插入一个结点3,实现单链表插 入的基本操作。 4) 在一个包括头结点和5个结点的(5,4,3,2,1)的单链表的指定位置 (如i=2)删除一个结点,实现单链表删除的基本操作。 5) 实现单链表的求表长操作。 【实验步骤】 1.打开VC++。 2.建立工程:点File->New,选Project标签,在列表中选Win32 Console Application,再在右边的框里为工程起好名字,选好路径,点OK->finish。至此工程建立完毕。 3.创建源文件或头文件:点File->New,选File标签,在列表里选C++ Source File。给文件起好名字,选好路径,点OK。至此一个源文件就被添加到了刚创 建的工程之中。 4.写好代码 5.编译->链接->调试 1、#include "stdio.h" #include "malloc.h" #define OK 1 #define OVERFLOW -2 #define ERROR 0 #define LIST_INIT_SIZE 100 #define LISTINCREMENT 10 typedef int ElemType; typedef int Status; typedef struct { ElemType *elem; int length; int listsize; } SqList; Status InitList( SqList &L ) { int i,n; L.elem = (ElemType*) malloc (LIST_INIT_SIZE*sizeof (ElemType)); if (!L.elem) return(OVERFLOW); printf("输入元素的个数:"); scanf("%d",&n); printf("输入各元素的值:"); for(i=0;i 第九章查找 单项选择题 1.顺序查找法适合于存储结构为的线性表。 A. 散列存储 B. 顺序存储或链接存储 C. 压缩存储 D. 索引存储 2.对线性表进行二分查找时,要求线性表必须。 A. 以顺序方式存储 B. 以顺序方式存储,且结点按关键字有序排列 C. 以链接方式存储 D. 以链接方式存储,且结点按关键字有序排列 3.采用顺序查找方法查找长度为n的线性表时,每个元素的平均查找长度为。 A. n B. n/2 C. (n+1)/2 D. (n-1)/2 4.采用二分查找方法查找长度为n的线性表时,每个元素的平均查找长度为。 A. O(n2) B. O(nlog2n) C. O(n) D. O (logn) 5.二分查找和二叉排序树的时间性能。 A. 相同 B. 不相同 6.有一个有序表为{1,3,9,12,32,41,45,62,75,77,82,95,100},当二分查找值为82的结点时,次比较后查找成功。 A. 1 B. 2 C. 4 D. 8 7.设哈希表长m=14,哈希函数H(key)=key%11。表中有4个结点: addr(15)=4 addr(38)=5 addr(61)=6 addr(84)=7 其余地址为空,如用二次探测再散列处理冲突,关键字为49的结点的地址是。 A. 8 B. 3 C. 5 D. 9 8.有一个长度为12的有序表,按二分查找法对该表进行查找,在表内各元素等概率情况下查找成功所需的平均比较次数为。 A. 35/12 B. 37/12 C. 39/12 D. 43/12 9.采用分块查找时,若线性表中共有625个元素,查找每个元素的概率相同,假设采用顺序查找来确定结点所在的块时,每块应分个结点最佳地。 A. 10 B. 25 C. 6 D. 625 10.如果要求一个线性表既能较快地查找,又能适应动态变化的要求,可以采用查找方法。 A. 分块 B. 顺序 C. 二分 D. 散列 填空题 1.顺序查找法的平均查找长度为;二分查找法的平均查找长度为;分块查找法(以顺序查找确定块)的平均查找长度为;分块查找法(以二分查找确定块)的平均查找长度为;哈希表查找法采用链接法处理冲突时的平均查找长度为。 2.在各种查找方法中,平均查找长度与结点个数n无关的查找方法是。 3.二分查找的存储结构仅限于,且是。 4.在分块查找方法中,首先查找,然后再查找相应的。 5.长度为255的表,采用分块查找法,每块的最佳长度是。 6.在散列函数H(key)=key%p中,p应取。 7.假设在有序线性表A[1..20]上进行二分查找,则比较一次查找成功的结点数为,则 实验一线性表基本操作的编程实现 【实验目的】 线性表基本操作的编程实现 要求: 线性表基本操作的编程实现(2学时,验证型),掌握线性表的建立、遍历、插入、删除等基本操作的编程实现,也可以进一步编程实现查找、逆序、排序等操作,存储结构可以在顺序结构或链表结构中任选,可以完成部分主要功能,也可以用菜单进行管理完成大部分功能。还鼓励学生利用基本操作进行一些更实际的应用型程序设计。 【实验性质】 验证性实验(学时数:2H) 【实验内容】 把线性表的顺序存储和链表存储的数据插入、删除运算其中某项进行程序实现。建议实现键盘输入数据以实现程序的通用性。为了体现功能的正常性,至少要编制遍历数据的函数。 【注意事项】 1.开发语言:使用C。 2.可以自己增加其他功能。 【思考问题】 1.线性表的顺序存储和链表存储的差异?优缺点分析? 2.那些操作引发了数据的移动? 3.算法的时间效率是如何体现的? 4.链表的指针是如何后移的?如何加强程序的健壮性? 【参考代码】(以下内容,学生任意选择一个完成即可) (一)利用顺序表完成一个班级学生课程成绩的简单管理 1、预定义以及顺序表结构类型的定义 (1) #include 题目:顺序表的实现 一、实验题目 顺序表的实现 二、实验目的 ⑴掌握线性表的顺序存储结构; ⑵验证顺序表及其基本操作的实现; ⑶理解算法与程序的关系,能够将顺序表算法转换为对应的程序。 三、实验内容与实现 ⑴建立含有若干个元素的顺序表; ⑵对已建立的顺序表实现插入、删除、查找等基本操作。实验实现 #include printf("%d ",a[k]); printf("\n"); } int Search(int p) //查找 { int j,h; for(j=0;j<12;j++) { if(a[j]==0) break; } for(h=0;h #include 数据结构实验报告 课题名称:线性表的操作算法姓名: 班级: 学号: 一、内容提要 1、掌握使用cFree上机调试线性表的基本方法; 2、分别用数组和链表作为存储结构,实现线性表的插入、删除、查找、排序、合并等操作。 二、实验要求 1、设计对线性表进行链式存储操作的内容; 2、写出相应程序; 3、保存和打印出程序的运行结果,并结合程序进行分析; 三、实验目的 1、理解数据结构中单链表的定义和建立。 2、掌握单链表中结点结构的C语言描述。 3、熟练掌握单链表的插入、删除、查找、排序、合并等算法的设计与C语言实现。 4、将理论与实际相结合,切实提高自己的逻辑能力和动手能力。 四、算法流程图 开始 创建 遍插删查查找查找合 历入除找前驱后继并 主函数 输出 结束 五、概要设计 1.界面设置 1.建立顺序表,输入数据元素 2.输出顺序表 3.在i位置插入元素e 4.删除第i个元素,返回其值 5.查找值为e的元素 6.清空顺序表 7.输出指定元素的前驱元素 8.输出指定元素的后继元素 9.将两个非递减的线性表la和lb合并成一个新的非递减的线性表0.结束程序运行 请输入您的选择(1,2,3,4,5,6,7,8,9,0) 2.功能函数说明与定义 //加载头文件 #include顺序查找法适用于存储结构为顺序或链接存储的线行表
数据结构实现顺序表的各种基本运算(20210215233821)
线性表的基本操作讲解
数据结构作业五
实验一 线性表的基本操作
第10章 查找
线性表算法题
各种查找算法的性能比较测试(顺序查找、二分查找)
线性表的基本操作实验报告
第9章 查找练习题及答案
实验一 线性表基本操作的编程实现
散列查找顺序表的实现实验报告
数据结构实验折半查找C语言实现
线性表的操作算法讲解