第7章学习小结
Posted cq20
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第7章学习小结相关的知识,希望对你有一定的参考价值。
查找分为线性表的查找、树表的查找、散列表的查找。
一些定义:
查找表:由同一类型的数据元素(或记录)构成的集合(在查找时对表做修改操作,如插入和删除,则称为动态查找表;否则称为静态查找表)
关键字:数据元素(或记录)中某个数据项的值(如果一个查找表里只存储了关键字,意义不是很大
平均查找长度ASL:从1到第n个数据元素 查找第 i 个记录的概率 * 找到第 i 个记录所需的比较次数 之和
类型定义
//数据元素类型定义 typedef struct { KeyType key ; //关键字域 InfoType otherinfo ; //其他域 }ElemType ; //顺序表的定义 typedef struct { ElemType *R ; //存储空间基地址 int length ; //当前长度 }SSTable ;
一、线性表的查找
顺序查找
(1)顺序查找方法既适用于线性表的顺序存储结构,又适用于线性表的链式存储结构,表内元素不要求有序。
(2)空间复杂度:O(1)
时间复杂度:O(n)
查找成功时(设表中每个记录的查找概率相等),ASL = (1+2+...+n)/ n = (n+1)/ 2
查找不成功时,ASL = n+1
int Search_Seq(SSTable ST, KeyType key) {//在顺序表ST中顺序查找其关键字等于key的数据元素。 //若找到,则函数值为该元素在表中的位置;否则为0。 ST.R[0].key = key ; //哨兵 for(int i = ST.length ; ST.R[i].key != key ; --i) ; //从后往前找 return i ; }
(3)优点:算法简单,对表结构无任何要求,既适用于顺序结构,也适用于链式结构,无论记录是否按关键字有序均可应用。
缺点:平均查找长度较大,查找效率较低,所以当 n 很大时,不宜采用顺序查找。
折半查找
(1)折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列
(2)空间复杂度:O(1)
时间复杂度:O(log2n)
int Search_Bin(SSTable ST, KetType key) { int low = 0 ; int high = ST.length - 1 ; while(low <= high) { int mid = (low + high) / 2 ; if(key == ST.R[mid].key) return mid ; //找到待查元素 else if(key < ST.R[mid].key) high = mid - 1 ; //继续在前一子表进行查找 else low = mid + 1 ; //继续在后一子表进行查找 } return 0 ; //表中不存在待查元素 }
//递归算法 int Search_Bin(SSTable ST, KeyType key, int low, int high) { if(low > high) return 0 ; int mid = (low + high) / 2 ; if(key == ST.R[mid].key) return mid ; else if(key < ST.R[mid].key) return Search_Bin(ST, key, low, mid-1) ; else return Search_Bin(ST, key, mid+1, high) ; }
(3)优点:比较次数少,查找效率高。
缺点:对表结构要求高,只能用于顺序表存储的有序表
适合一次排序,多次查找。因此,针对有序且静态数据(在动态数据集合中,考虑树查找)
数据量小,不需要二分(数组:连续内存空间)
数据量太大也不可以用二分
分块查找(块内无序,块间有序)
(1)分块查找的平均查找长度为 ASL = 查找索引表确定所在块的平均查找长度 + 在块中查找元素的平均查找长度
(2) 优点:快速查找 + 动态变化
缺点:要增加一个索引表的存储空间并对初始索引表进行排序
二、树表的查找
二叉排序树:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值
它的左、右子树也分别为二叉排序树
或者是空树
(中序遍历一棵二叉树时可以得到一个结点值递增的有序排列)
//二叉排序树的二叉链表存储表示 typedef struct { KeyType key ; InfoType otherinfo ; }ElemType ; typedef struct BSTNode { ElemType data ; //每个结点的数据域包括关键字项和其他数据项 struct BSTNode *lchild, *rchild ; //左右孩子指针 }BSTNode, *BSTree ; //二叉排序树的递归查找 BSTree SearchBST(BSTree T, KeyType key) { if( (!T ) || key == T->data.key) return T ; else if (key < T->data.key) return SearchBST(T->lchild, key) ; else return SearchBST(T->rchild, key) ; }
(1)时间复杂度:最好的情况(类似于折半查找):log2n
最坏的情况(类似于顺序查找):(n + 1) / 2
平衡二叉树:左子树和右子树的深度之差的绝对值不超过1
左子树和右子树也是平衡二叉树
或者是空树
平衡因子:该结点左子树和右子树的深度之差,则平衡二叉树上所有结点的平衡因子只可能是-1,0,1
平衡调整方法:保持有序+平衡
B+树、B-树:多叉树
三、散列表的查找
散列表:一个有限连续的地址空间。通常散列表的存储空间是一个一维数组,散列地址是数组的下标。
冲突:不同的关键字得到同一散列地址
同义词:具有相同函数值的关键字
(1)散列函数的构造方法:数字分析法、平方取中法、折叠法、除留余数法
(2)处理冲突的方法:开放地址法(线性探测法、二次探测法、伪随机探测法)
链地址法(把具有相同散列地址的记录放在同一个单链表中,称为同义词链表)
//开放地址法散列表的存储表示 #define m 20 //散列表的表长 typedef struct { KeyType key ; InfoType otherinfo ; }HashTable[m] ; //散列表的查找 #define NULLKEY 0 //单元为空的标记 int SearchHash(HashTable HT, KeyType key) { H0 = H(key) ; //根据散列函数H(key)计算散列地址 if(HT[H0].key == NULLKEY) return -1 ; else if(HT[H0].key == key) return H0 ; else { for(int i=1 ; i<m ; ++i) { Hi = (H0 + i) % m ; //根据线性探测法计算下一个散列地址Hi if(HT[Hi].key == NULLKEY) return -1 ; else if(HT[Hi].key == key) return Hi ; } //for return -1 ; } //else }
(3)装填因子:表中填入的记录数 / 散列表的长度(越大说明表中已填入的记录越多,发生冲突的可能性就越大)
(4)在查找概率相等的前提下,
平均长度 ASL = (1/n) * Ci ( i = 1, 2, 3, 4...) ( n为散列表中记录的个数,Ci为成功查找第 i 个纪录所需的比较次数)
以上是关于第7章学习小结的主要内容,如果未能解决你的问题,请参考以下文章