声明下:本博主基础薄弱,仅仅为了面试了解部分数据结构知识,详见大神博客,地址为:点击打开链接
表:
形如A0,A1,A2...An-1的一般数据表。
实现
基于数组实现的表(ArrayList)
- 内存分布连续;
- 可无限扩容的数组,扩容时,新建双倍容量的数组,将旧数组中的元素copy至新数组中,然后将旧数组引用指向新数组,即表示扩容;jdk7以上:ArrayList扩容为原来的1.5倍
- 优点:随机访问,时间复杂度为表:O(1)
- 缺点:插入和删除缓慢,要平均移动N/2个数组元素,时间复杂度为O(N),数组末尾插入和删除除外,O(1)。
基于链实现的表(LinkedList双链)
- 内存分布不连续,即节点之间内存不连续;
- 单链:链尾next指针指向null,双链:链尾指针指向链头元素。
- 一个节点包含:表元素和next链节点指针,指向下一个元素;
- 优点:插入和删除方便,只需要修改节点指针指向即可p=p.next,O(1)
- 缺点:随机访问缓慢,需要从链头开始遍历至查询的元素,O(N),但是链头元素除外;
集合使用注意:
- iterator迭代器:如果在迭代过程中,对集合本身进行增加、修改、删除等操作,会引发ConcurrentModificationException异常,因为集合本身发生变化,iterator迭代不知道集合数目发生变化,所以会引起异常。所以要使用iterator自带的remove方法,当然java8以后ListIterator新加了Add方法
- Remove方法:如果该集合多适用于删除场景,可以将list集合设置为LikedList集合,时间复杂度为O(1)
散列:(HashMap)
解决hash散列冲突方法:
- 分离链接法(HashMap):数组+链表:使用Hash算法避免冲突发生,HashMap重写hashcode方法,数组长度一般定义为2的n次幂,使用hashcode(key) & (length-1)与运算的到一个散列值,然后进行17或者20进行或运算,得到一个散列值;见博主hashmap 底层原理
- 线性探测法和平方探测法:当2位置出现冲突时,会查看3的位置,依次排查一遍,平方即探测平方位置上的的值是否为空;
- 再散列;
- 建立一个公共溢出区:将数组表一分为二,一部分基础表一部分为存放冲突元素的;
栈stack:
插入和删除在同一个位置上进行,先进后出
应用:编译器检查语法错误
队列Queue:
插入在队尾,删除在队头,即先进先出,
应用:排队系统,秒杀系统
树:
基本概念:
- 高度指结点的高度,即某结点到叶子结点的距离
- 深度指:树的深度,即根节点到某结点之间的距离
- 度指结点的子树个数;
二叉树:
每个结点的子节点树不超过两个即为二叉树。
二叉查找树:
对于树的每个结点X,它的左子树所有子节点值小于X,右子树的所有子节点大于X
平均深度为:O(logN),
N为树的高度,这里注意在计算机科学领域中,若无特殊说明,
对数都是以2为底的
。
二叉树的性质:
- 总结点数-1=总的连接数;例如度为0的结点数为n0,度为1的结点数为n1,度为2的结点数为n2,则n总结点数为n0+n1+n2,
n-1=n0+n1+n2=0Xn0+n1+2n2(总链条数)------>n0=n2+1
- 高度为k的二叉树中,最多有2^n -1个结点(满二叉树),最少有2^(k-1)个结点数
二叉树的遍历:
- 先序遍历;父辈先执行,儿子后执行
- 中序遍历;先处理左子树,然后执行当前结点,然后右子树
- 后序遍历;儿子先执行,父辈后执行
- 层序遍历;即从上到下按层次访问该树,每一层单独输出一行,每一层要求访问的顺序为从左到右。我们在遍历的过程中将该层节点的孩子节点压入一个队列,这样就可以实现从上到下一层一层地遍历该二叉树
这里介绍几个数据查找的方法:
折半查找或者二分法:
要求:顺序表,有序
特点:平均查找时间O(logN)
方法:先和中间的元素比较,如果相等即返回,如果大于中间元素,则从中间元素后开始查找,如果小于中间元素,则从开始重新查找。
代码示例如下:
方法一:
public int compare(String[] strings, String value) {
int low = 0;
int length = strings.length - 1;
while (low < length) {
//如果中间的值比目标值大,则取0-(mid-1)之间进行筛选
int mid = (low + length) / 2;
if (strings[mid].compareToIgnoreCase(value) > 0) {
length = mid - 1;
} else if (strings[mid].compareToIgnoreCase(value) < 0) {
//如果中间值比目标值小,则取(mid+1)-length之间的 进行筛选
low=mid+1;
}
return mid;
}
return -1;
}
方法二:
//first指开始查找元素的索引,size指末尾段元素的索引 public static int search(int[] a,int first,int size,int target){ int middle; if (size<0){ return -1; } middle=first+size/2; if (target<a[middle]){ return search(a,first,size/2,target); } if (target>a[middle]){ return search(a,middle+1,(size-1)/2,target); } if (target==a[middle]){ return middle; } return -1; }
顺序查找法:不需要排序,直接一个一个查找
平均步长为:(N+1)/2,时间复杂度为:O(N)
代码如下:
public static int binarySearch(String[] strings, String value){
for (int i=0;i<strings.length;i++){
if (strings[i].equals(value)){
return i;
}
}
return -1;
}