ArrayList和LinkedList的区别
首先两者都是List接口的不同实现,并且线程都是不安全的,ArrayList底层使用动态数组来存储元素,LinkedList内部使用双向链表来存储元素;ArrayList占用的内存在声明的时候就已经确定了,默认为10当超出后,会自动扩容为原来的1.5倍,LinkedList在声明的时候不需要指定大小,元素增加与删除的时候大小会随之改变
对于ArrayList:
get()方法的时间复杂度为O(1),因为直接从底层数组下标获取,与数组长度无关
add()方法默认将元素添加到数组的末尾,但是需要考虑到数组的扩容情况,如果不需要扩容它的时间复杂度也是O(1),如果需要扩容的话内部执行的Arrays.copyof()方法是耗时的关键,需要把原有数组中的元素复制到扩容的新数组中;
add(int,E)方法将新的元素插入到指定的位置,考虑到需要复制底层的数组,根据最坏的打算,时间复杂度为O(n)
remove()方法将指定位置上的元素移除,因为需要复制底层的数组,所以时间复杂度也为O(n);
对于LinkedList:
get方法的时间复杂度为O(n),因为遍历了整个链表,在下标小于链表长度一半的时候,从前往后,否则从后往前遍历,如果下标为0或者List.size()-1的话时间复杂度为O(1)
add方法默认添加到链表的尾部,时间复杂度为O(1)
add(int index,E ele)方法插入到指定位置,需要先查找再进行插入,所以也是O(n)
remove方法也是一样,需要先查找再进行删除,时间复杂度为O(n)
栈和队列的区别?
栈:先进后出,删除和增加操作只针对表头部
队列:先进先出,删除在表尾,增加在表头
HashMap1.7和1.8结构区别
数组+链表->数组+红黑树+链表
Mysql的索引
索引的定义
索引常用于实现数据的快速检索,在Mysql中有两种方式可以访问表的行数据:
顺序访问:从头到尾的变量,效率低下
索引访问:提前对某列建立一个索引,查找数据的时候可以根据该列上的索引找到对应行记录的位置,从而快速的查找到数据,索引存储了指定列数据值的指针,根据指定的排序顺序对这些指针进行排序
索引的分类
物理分类
- B+树索引:叶子节点包含的地址直接执行表中的数据行,并且叶子结点保存了指向下一个叶子节点的指针;非叶子节点只记录参与索引的字段值
- Hash索引:把任意长度的输入通过散列算法变成固定长度的输入,输出就是散列值,只支持等值比较=,>=等,并且不支持键的部分匹配
- B树索引,节点不仅有字段值还有指向真实记录的指针
唯一性索引:unique索引不允许索引列拥有相同值;
主键索引:不允许值重复或者为空
全文索引:用于varchar和text类型的列上创建,并且只能在MyISam引擎中创建
B+数和B树的对比?
B+树中间节点没有存储数据记录只有索引,B树每个节点中的每个关键字都有数据记录,这就意味着相同大小的磁盘,对比每个节点B+树能存储更多的数据,B+树更加矮和胖,IO操作更少
也正因此B+树每次查找都需要找到叶子节点,性能稳定,B树情况号的时候是根节点,坏点的时候是叶子节点,性能不稳定
B树的范围查找需要不断的以来中序遍历,需要同时找到范围的上限和下限,整个过程比较耗时;B+树只需要找到范围的下限然后通过叶子节点的链表顺序遍历,直到找到上限就可以了
Redis的基本数据结构
String类型:key-value类型,value不仅可以是String也可以是数字
Hash类型:适合用于存储对象<String,Map<String,Object>>
List类型:底层是个链表
Set类型:相对于List可以自动排重
Sorted Set类型:每个元素都会关联一个double类型的分数,通过分数来进行大小排序
此外还有地理位置统计,Hyperloglog基数计算,BitMaps位图
快速排序?
private static void quickSort(int[] arr){
if(arr==null||arr.length==0)return;
int begin=0;
int end=arr.length-1;
quickSortHelper(arr,begin,end);
}
private static void quickSortHelper(int[] arr, int begin, int end) {
if(end<=begin)return;//递归终止条件
int i=begin;
int j=end;
int index=arr[begin];//这样的写法index不能是随机数,只能是第一个
while (i<j){
//这一块也不能写反,得先移动j
while (i<j&&arr[j]>=index){
j--;
}
arr[i]=arr[j];
//再移动i
while (i<j&&arr[i]<=index){
i++;
}
arr[j]=arr[i];
}
arr[i]=index;
quickSortHelper(arr,begin,i-1);
quickSortHelper(arr,i+1,end);
}
手撕冒泡?
public static void bubbleSort(int[] arr) {
int n=arr.length;
int count=0;
for (int i = 0; i < n; i++) {
boolean swap=false;
for (int j = 0; j < n - i - 1; j++) {
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
swap=true;
}
}
if(!swap) break;//已经排好序了
}
}
手撕归并?
public void merge(int[] nums, int left, int right) {
int mid = left + ((right - left) >> 1);
if (left < right) {
merge(nums, left, mid);
merge(nums, mid + 1, right);
mergeSort(nums, left, mid, right);
}
}
public void mergeSort(int[] nums, int left, int mid, int right) {
int[] temp = new int[right - left + 1];
int index = 0;
int index1 = left, index2 = mid + 1;
while (index1 <= mid && index2 <= right) {
if (nums[index1] <= nums[index2]) {
temp[index++] = nums[index1++];
} else {
temp[index++] = nums[index2++];
}
}
//把左边剩余的数移入数组
while (index1 <= mid) {
temp[index++] = nums[index1++];
}
//把右边剩余的数移入数组
while (index2 <= right) {
temp[index++] = nums[index2++];
}
//把新数组中的数覆盖nums数组
System.arraycopy(temp,0,nums,left,right-left+1);
}
快排和归并的区别?
归并排序,简单来说就是先将数组不断细分成最小的单位,然后每个单位分别排序,排序完毕后合并,重复以上过程最后就可以得到排序结果。
快速排序,简单来说就是先选定一个基准元素,然后以该基准元素划分数组,再在被划分的部分重复以上过程,最后可以得到排序结果。