从如今开始个人博客讲介绍有关计算机基础之数据结构的内容,我将会把核心的内容讲解出来,但愿能给你们带来帮助。
算法
查找是在集合中寻找知足某种条件的数据元素的过程,分为查找成功和查找失败。
用于查找的数据元素集合称为查找表,由同一类型的数据元素组成,能够是数组或者链表。能够根据是否要动态修改查找表才能查找到元素分为静态查找表和动态查找表。
关键字是数据元素中惟一标识某元素的某个数据项的值,使用基于关键字的查找,查找结果是惟一的。
查找效率须要有一个评判标准,最通用的方法是用平均查找长度ASL评判。在查找过程当中,ASL是全部查找过程当中进行关键字比较次数的平均值。数学定义为:
其中,n是查找表的长度,P(i)是查找第i个数据元素的几率,通常认为每一个元素的P(i)都相等,为1/n,C(i)是找到第i个数据元素所需进行比较的次数。
数组
顺序查找又称线性查找,主要用线性表进行查找,分为对通常的无序线性表的顺序查找和对按关键字有序的顺序表的顺序查找。
数据结构
这是最简单的查找方法,基本思想是从线性表的一端开始,逐个检查关键字是否知足给定的条件,查找成功返回在线性表中位置,查找失败返回查找失败的信息。
算法结构以下:性能
typedef struct{ ElemType *elem; //元素存储空间的基址,建表时按实际长度分配,0号位留空放哨兵 int TableLen; //表的长度 }SSTable int Search_Seq(SSTable ST,ElemType Key){ ST.elem[0] = key; //哨兵 for(i = ST.TableLen;ST.elem[i] != key;--i); //从后往前找 return i; //不存在关键字为key的元素,i为0时退出for循环 }
将ST.elem[0]称为"哨兵",目的是使得算法里循环没必要判断数组是否越界。当知足i == 0时能够直接跳出,避免不须要的判断语句,提升程序效率。
平均查找长度分析:有n个元素的线性表,当定位到第i个元素时,须要进行n-i+1次关键字的比较(从后往前比较),则C(i)=n-i+1。查找成功时,当每一个P(i)都相等,为1/n时,顺序查找的平均查找长度为:
查找失败时,与各关键字的比价次数是n+1次,则ASL(不成功)=n+1。
由上面的分析能够知道,顺序表的优势是对数据存储没有要求,顺序链表和链式链表皆可,对表中记录的有序性也没有要求。缺点是当n比较大时,效率比较慢,ASL比较大。
3d
有序表的顺序查找成功查找时和通常顺序表的查找同样,可是查找失败时,由于在查找以前就知道表是关键字有序的,则查找失败时能够不用再比较表的另外一端就能返回查找失败的信息,提升效率,下降ASL。
这里只分析查找失败的ASL,查找成功时的ASL和前面的同样。查找失败时,查找指针必定走到了某个失败结点,是咱们虚构的空结点,实际上并不存在。因此查找结点失败时所查找的长度等于它上面的圆形结点所在的层数,则ASL为:
(1+2+3+4+..+n+n)÷(n+1) = n/2 + n/n+1
其中q(j)是到达第j个失败结点的几率,相等查找几率的情形下为1/(n+1),l(j)是第j个失败结点所在的层数。
指针
折半查找又称二分查找,用二分法进行查找,仅适用于有序的顺序表,不能用于链表。
code
首先用要查找的关键字k与中间位置的结点的关键字相比较,这个中间结点把线性表分红了两个子表,若比较结果相等则查找完成;若不相等,再根据k与该中间结点关键字的比较大小肯定下一步查找哪一个子表,这样递归进行下去,直到找到知足条件的结点或者该线性表中没有这样的结点。查找成功,返回查找的元素;查找不成功,返回查找失败的信息。
折半查找有非递归和递归两种方法。
blog
int Binary_Search(SeqList L,ElemType key){ int low = 0,high = L.TableLen - 1,mid; while(low <= high){ mid = (low + high) / 2 if(L.elem[mid] == key) return mid; else if(L.elem[mid] > key) high = mid - 1; else low = mid + 1; } return -1; }
int Binary_Search(SeqList L,ElemType key,int low,int high){ mid = (low + high) / 2 if(low <= high){ if(L.elem[mid] == key) return mid; else if(L.elem[mid] > key) return Binary_Search(L,key,low,mid - 1); else return Binary_Search(L,key,mid + 1,high); } return -1; } // di一次传入的数据,这里*L指向顺序表,也能够不加*,要具体而定 Binary_Search(*L,key,0,*L.TableLen - 1)
折半查找能够用一个平衡二叉树来描述,称为断定树,以下:
书中的圆形结点表示一个记录,结点中的值为该记录的关键字值;树中最下面的叶节点都是方形的,表示查找不成功的状况。从中能够看到,查找成功的长度是从根节点到目的圆结点的路径上的结点数,而查找不成功时的查找长度为从根节点到对应失败结点的父结点的路径上的结点数。这个二叉树按中序遍历元素逐步递增。若序列有n个元素,则对应的断定树有n个圆形的非叶节点和n+1个方形的叶结点。
排序
用折半查找查找到给定值的比较次数不会超过树的高度,在等几率查找时,查找成功的平均查找长度为:
其中,h是树高,而且元素个数为n时树高h为 ,因此折半查找成功的时间复杂度为 ,通常状况下比顺序查找的效率高。
查找失败的时候,则计算失败结点父结点的高度,而后ASL为:
每一层失败结点的父结点高度*失败节点个数之和与失败结点总数之差。
递归
折半查找须要线性表具备随机存取的特性,则只适用于顺序存储结构,且要求元素按关键字有序排列。
分块查找又称索引顺序查找,分块查找是折半查找和顺序查找的一种改进方法,折半查找虽然具备很好的性能,但其前提条件时线性表顺序存储并且按照关键码排序,这一前提条件在结点树很大且表元素动态变化时是难以知足的。而顺序查找能够解决表元素动态变化的要求,但查找效率很低。分块查找吸取了顺序查找和折半查找各自的优势,既有动态结构,又适合于快速查找。
分块查找要求把一个大的线性表分解成若干块,每块内的节点能够任意存放,但块与块之间必须排序。此外,还要创建一个索引表,把每块内的最大关键码值做为索引表的关键码值,按块的顺序存放到一个辅助数组中。查找时,首先在索引表中进行查找,肯定要找的节点所在的块。因为索引表是排序的,所以,对索引表的查找能够采用顺序查找或折半查找;而后,在相应的块内采用顺序查找,便可找到对应的节点。
分块查找的平均查找长度是索引查找和块内查找平均长度之和。若一个查找表长度为n,均匀分为b块,每块有s个记录,在等几率状况下,块内和索引表中均采用顺序查找,则ASL为:
ASL=(b+1)/2+(s+1)/2
此时,若s=√n,则平均查找长度取最小值√n+1 。
若对索引表进行折半查找时,则平均查找长度为:
ASL=(s+1)/2+log2(b+1)-1 这里要注意,log2(b+1)取最大值上限。