主要是自己的学习记录,不具备体系
数组
一维数组
二维数组
缓存与局部性原理
这里只讨论空间局部性,CPU读取内存(速度较慢)数据后,会将其放入高速缓存中,若后来计算在使用到该数据,缓存中有的话就不要读内存。而缓存的最小存储单位是缓存行(cache line),一般是64bytes,一次读的数据少了不划算,所以会读入当前数据的临近数据
所以外层循环行比外层循环列更快
链表
概述
内存中存储时不连续的
模运算优化:模2*n时
优先级队列
实现一:无序数组
优先级相关的信息在数组中的存储是无序的,出队列时进行排序,获取优先级最大的数据,入队列时直接添加即可。
实现二:有序数组
优先级相关的信息在数组中的存储是无序的,出队列时直接获取数组尾部元素,获取优先级最大的数据,入队列时进行插入排序。
实现三: 堆实现
基于树的数据结构,通常用完全二叉树(除了最后一层其他都是填满的)实现
树
根据前序中序遍历结果恢复树
less
中序遍历,遍历到小的加入结果中,注意因为是搜索树且中序遍历,所以比key大的就可以退出
根据前序遍历结果简历二叉搜索树
公共祖先:p、q都在某一节点的两侧,那么该节点就是最近的公共祖先
B树
在磁盘读取时通常运用到B树,相同的数据B树的高度会比avi树,红黑树、二叉搜索树等更低。
哈希表
.entrySet()是用来获取Map中所有键值对的集合,返回的是一个Set类型,其中每个元素都是一个Map.Entry对象,包含了键和值两个部分。通过遍历这个集合,可以方便地获取Map中的所有键值对并进行操作。
查找最高频单词
import java.util.*;
public class Solution819 {
public String mostCommonWord(String paragraph, String[] banned) {
// String[] split = paragraph.toLowerCase().split("[^A-Za-z]+");
char[]chars = paragraph.toLowerCase().toCharArray();
Set<String> set = Set.of(banned);
HashMap<String,Integer>map = new HashMap<>();
StringBuilder sb = new StringBuilder();
for(char ch:chars){
if(ch>='a'&&ch<='z'){
sb.append(ch);
}else{
String key = sb.toString();
if(!set.contains(key)){
map.compute(key,(k,v)->v==null?1:v+1);
}
sb = new StringBuilder();
}
}
if(sb.length()>0){
String key = sb.toString();
if(!set.contains(key)){
map.compute(key,(k,v)->v==null?1:v+1);
}
}
int max=0;
String maxKey=null;
for(Map.Entry<String,Integer>e:map.entrySet()){
Integer value=e.getValue();
if(value>max){
max=value;
maxKey=e.getKey();
}
}
return maxKey;
}
}
排序算法
冒泡排序
package sort;
import java.util.Arrays;
public class bubble {
// j未排序区域的右边界
// 递归实现
private static void bubbleSort(int[] a, int j) {
if (j == 0) {
return;
}
int x = 0;//优化,记录最近一次交换位置的地方
for (int i = 0; i < j; i++) {
if (a[i] > a[i + 1]) {
int t = a[i];
a[i] = a[i + 1];
a[i + 1] = t;
x = i;
}
}
bubbleSort(a, x);
}
// 非递归实现
private static void bubbleSort2(int[] a) {
int j = a.length - 1;
do {
int x = 0;//优化,记录最近一次交换位置的地方
for (int i = 0; i < j; i++) {
if (a[i] > a[i + 1]) {
int t = a[i];
a[i] = a[i + 1];
a[i + 1] = t;
x = i;
}
}
j = x;
} while (j != 0);
}
public static void main(String[] args) {
int[] a = new int[]{1, 2, 5, 6, 3, 2};
bubbleSort(a, a.length - 1);
System.out.println(Arrays.toString(a));
bubbleSort2(a);
System.out.println(Arrays.toString(a));
}
}
选择排序
package sort;
import java.util.Arrays;
public class pick {
private static void pickSort(int[] a) {
for (int right = a.length - 1; right > 0; right--) {
int max = right;
//假定最后一个元素时最大的,与前面的元素进行比较
for (int i = 0; i < right; i++) {
if (a[i] > a[max]) {
max = i;
}
}
if(max!=right) {
swap(a, right, max);
}
}
}
private static void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
public static void main(String[] args) {
int[] a = new int[]{1, 2, 5, 6, 3, 2};
pickSort(a);
System.out.println(Arrays.toString(a));
}
}
堆排序
package sort;
import java.util.Arrays;
public class heap {
private static void heapSort(int[] a){
heapify(a,a.length);
System.out.println(Arrays.toString(a));
for(int right=a.length-1;right>0;right--){
swap(a,0,right);
down(a,0,right);
}
}
private static void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
// 建堆
private static void heapify(int[]a,int size){
for(int i=size/2-1;i>=0;i--){
down(a,i,size);
}
}
// 下潜
private static void down(int[] a,int parent,int size){
int left = parent*2+1;
int right = left+1;
int max=parent;
if(left<size&&a[left]>a[max]){
max=left;
}
if(right<size&&a[right]>a[max]){
max=right;
}
if(max!=parent){
// 找到了更大的孩子
swap(a,max,parent);
down(a,max,size);
}
}
public static void main(String[] args) {
int[] a = new int[]{1, 2, 5, 6, 3, 2,7};
heapSort(a);
System.out.println(Arrays.toString(a));
}
}
插入排序
package sort;
import java.util.Arrays;
public class insert {
private static void insertSort(int[] a){
insertion(a,1);
}
private static void insertion(int[] a ,int low){
if(low==a.length){
return;
}
int t=a[low];
int i=low-1;
// 自右向左寻找插入位置,如果比待插入元素大,则不断右移,空出插入位置
while (i>=0&&a[i]>t){
a[i+1]=a[i];
i--;
}
// 找打插入位置
// 1 3 6 5 对于5而言已经在while循环将5与6交换,所以无需重复赋值
if(i+1!=low){
a[i+1]=t;
}
insertion(a,low+1);
}
public static void main(String[] args) {
int[] a = new int[]{1, 2, 5, 6, 3, 2};
insertSort(a);
System.out.println(Arrays.toString(a));
}
}
希尔排序
相比插入排序更好,可以简单形象理解为,迈的步子更大,交换次数更少。
package sort;
import java.util.Arrays;
public class hill {
private static void hillSort(int[] a) {
// gap 4 2 1
for (int gap = a.length >> 1; gap >= 1; gap = gap >> 1) {
for (int low = gap; low < a.length; low++) {
int t = a[low];
int i = low - gap;
// 自右向左寻找插入位置,如果比待插入元素大,则不断右移,空出插入位置
while (i >= 0 && a[i] > t) {
a[i + gap] = a[i];
i--;
}
// 找打插入位置
// 1 3 6 5 对于5而言已经在while循环将5与6交换,所以无需重复赋值
if (i + gap != low) {
a[i + gap] = t;
}
}
}
}
public static void main(String[] args) {
int[] a = new int[]{1, 2, 5, 6, 3, 2};
hillSort(a);
System.out.println(Arrays.toString(a));
}
}
归并排序
归并加插入,没有必要一直分治到只有一个元素,但元素个数较少时可以直接进行插入排序
单边循环快排
package sort;
import java.util.Arrays;
public class quick {
private static void quickSortLomuto(int[] a) {
quick(a,0,a.length-1);
}
private static void quick(int[] a,int left,int right){
if(left>=right){
return;
}
int p=partition(a,left,right);
quick(a,left,p-1);
quick(a,p+1,right);
}
private static void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
private static int partition(int[] a, int left, int right) {
int pv = a[right];//基准点元素值
int i = left;
int j = left;
while (j < right) {
if (a[j] < pv) {
//j找的是比pv小的,找到了比较i、j的值,不相等则交换
if (i != j) {
swap(a, i, j);
}
//i=j,i继续向前走
i++;
}
j++;
}
swap(a, i, right);
return i;
}
public static void main(String[] args) {
int[] a = new int[]{1, 2, 5, 6, 3, 2};
quickSortLomuto(a);
System.out.println(Arrays.toString(a));
}
}
双边循环快排
package sort;
import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;
public class quickShuang {
private static void quickSortHoare(int[] a) {
quick(a, 0, a.length - 1);
}
private static void quick(int[] a, int left, int right) {
if (left >= right) {
return;
}
int p = partition(a, left, right);
quick(a, left, p - 1);
quick(a, p + 1, right);
}
private static void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
private static int partition(int[] a, int left, int right) {
// 随机选择基准点
int idx = ThreadLocalRandom.current().nextInt(right-left+1)+left;
swap(a,left,idx);
int pv = a[left];//基准点元素值
int i = left;
int j = right;
while (i < j) {
while (i < j && a[j] > pv) {
// j从右向左找小的
j--;
}
while (i < j && a[i] <= pv) {
i++;
}
swap(a, i, j);
}
swap(a, i, left);
return i;
}
public static void main(String[] args) {
int[] a = new int[]{1, 2, 5, 6, 3, 2};
quickSortHoare(a);
System.out.println(Arrays.toString(a));
}
}
计数排序
package sort;
import java.util.Arrays;
public class count {
private static void countSort(int[] a) {
int max = a[0];
int min = a[0];
// min求出最小值,处理有负数的情况
for (int i = 1; i < a.length; i++) {
if (a[i] > max) {
max = a[i];
}
if (a[i] < min) {
min = a[i];
}
}
int[] count = new int[max - min + 1];
for (int v : a) {
count[v - min]++;
}
int k = 0;
for (int i = 0; i < count.length; i++) {
// i代表原始数据元素,count[i]代表出现次数
while (count[i] > 0) {
a[k] = i + min;
count[i]--;
k++;
}
}
}
public static void main(String[] args) {
int[] a = new int[]{1, 2, 5, 6, 3, 2};
countSort(a);
System.out.println(Arrays.toString(a));
}
}
桶排序
将数据分段翻入每个桶中,每个桶里再排序
如果桶数据分布不均匀,优化可以求出最大值最小值决定有多少个桶
基数排序
最低有效数字,先排低位再排高位(可以理解为高位优先级、权重更大)
图
最小生成树
Prim算法,以顶点为中心拓展权重最小的边
Kruskal算法,每次选取最小权重的边,且加入后不构成环,也就是顶点之间不能联通(使用到了并查集)