时间复杂度
顺序列表查找
有序列表查找
- 二分查找:取中间的值进行比较,核心算法为 mid = (low+high)/2,适用于表中的值不均匀分部。
- 插值查找:取离目标值最近的值进行比较,核心算法:mid = low+(high - low) * (key - a [low])/ a[high] -a[low],适用于表中的值均匀分部。
时间复杂度都是O(logn)。
无序列表查找
如给定一个数组查找某个值在数组的下标。
public static void main(String[] args) {
int findKey = 1;
int []a = {10,20,50,1,42,35};
int index = getIndex(a, findKey);
System.out.println(index);
}
public static int getIndex(int a[] , int findKey){
for (int i = 0, j = a.length; i < j; i ++){
if (a[i] == findKey){
return i;
}
}
return 0;
}
以上是比较常用的写法,但是我们可以进一步优化,省掉 i<j的判断步骤。复制一个新的数组将长度+1,并存放要查找的值作为查找结束标识的哨兵。如果getIndex放回的下标大于当前a数组的长度,表明是结束哨兵的标识,结论是a数组不存在改值。
public static int getIndex(int a[] , int findKey){
int[] b = Arrays.copyOf(a, a.length+1);
b[a.length] = findKey;
int i = 0;
while (b[i] != findKey){
i++;
}
return i;
}
时间复杂度:O(n)
树
简单定义:树的结点只包含一个数据元素及对应多个子树。
1、二叉查找树
出现的原因:兼顾有序快速查找和无序快速删除插入。
问题:二叉树出现极端左轻右重或者左重右轻的情况,导致查找效率变慢。
2、平衡二叉树查找树
出现的原因:防止二叉树出现极端现象,维持左右树的深度最大不超过1。
平衡因子(BF):二叉树节点的左子树深度减去右子树的深度的值。
维持方式:当最小不平衡子树的BF大于1时,进行右旋(顺时针旋转),当BF小于-1时,进行左旋。当最小不平衡子树的BF与它的子树BF符号不统一,即一正一负,则需要先旋转结点到符号统一再进行一次反向旋转。
时间复杂度:O(logn)
B树
特点:其每一个结点的孩子树多于两个,且每一个结点可以存储多个元素。
出现的原因:树中的结点只能存一个值,当数据量多的时候,一下子加载不了过多数据,需要多次读磁盘,导致性能下降。
问题:当需要遍历所有数据的话,B树会存在结点和数据被多次重复访问的情况。
如上图使用中序遍历结果为:页面2-》页面1-》页面3-》页面1-》页面4-》页面1-》页面5。
可以发现页面1结点和数据被重复访问,造成了不必要的硬盘访问引起的性能消耗。
B+树
出现的原因:它的出现就是为了解决B树遇到的存在结点和数据被多次重复访问的问题。下面附上B+树示意图
特点:结点存的是索引,叶子结点存的是数据;所有叶子结点都链接在一起。保持从小到大的排序。
时间复杂度:O(logn)
哈希表
出现的原因:之前的方法都需要进行一次比较,有时候没必要。
问题:不理想会出现地址(hoshcde)冲突。
时间复杂度:理想情况下O(1)。
冲突解决方式:
- 线性探测法:遇到冲突就移动一下个位置,直到遇到有空位置的。
- 再散列函数法:遇到冲突就使用另外一种散列函数获取地址。
- 链地址法:冲突的用链表形式拼接。
- 公共溢出法:冲突的值再存入另外一个哈希表中。