1 数据结构与算法
1.1 排序算法
1.1.1 冒泡排序
-
冒泡排序的原理
(1) 我们假设从小到大排序,首先从头到尾遍历序列,如果后一元素小于前一元素,交换两个元素的位置,直到遍历到序列末尾,这时确定了序列最后一个位置的元素。
(2) 然后继续以上操作,直到所有元素的位置都确定。 -
代码实现
package com.java.sort;
/**
* @author WHT
* @create 2021-10-15 10:58
*/
public class BubbleSort {
public static void main(String[] args) {
int[] arr = {5,4,3,2,1};
bubbleSort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
public static void bubbleSort(int[] arr) {
//假设从小到大排序。
//1.从头到尾遍历数组,若arr[i+1]<arr[i], swap(arr[i+1],arr[i])。
//经过一轮遍历后,arr[n-1]是最大值。
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j+1] < arr[j]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
}
/**
//优化思路:若某次遍历,没有发生交换,表示整个数组已经排好序,可以return。
public static void bubbleSort(int[] arr) {
//假设从小到大排序。
//1.从头到尾遍历数组,若arr[i+1]<arr[i], swap(arr[i+1],arr[i])。
//经过一轮遍历,arr[n-1]是最大值。
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
int flag = 0;
for (int j = 0; j < n - i - 1; j++) {
if (arr[j+1] < arr[j]) {
flag = 1;
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
if (flag == 0) {
return;
}
}
}
**/
1.1.2 选择排序
-
选择排序的原理
(1) 我们假设从小到大排序,首先从头到尾遍历序列,找到最小的元素,与第一个元素交换。
(2) 然后继续以上操作,直到所有元素的位置都确定。 -
代码实现
package com.java.sort;
/**
* @author WHT
* @create 2021-09-23 23:37
*/
public class SelectSort {
public static void main(String[] args) {
int[] arr = {5,4,3,2,1};
selectSort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
public static void selectSort(int[] arr) {
//假设从小到大排序。
//1.从头到尾遍历数组,找到最小值,与第一个数交换。
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
}
1.1.3 插入排序
-
插入排序的原理
(1) 我们假设从小到大排序,刚开始有序序列只有一个元素,即第一个元素。
(2) 然后我们从有序序列的后一个元素开始遍历,将该元素插入到有序序列的对应位置,直到所有元素都插入到前面的有序序列中。 -
代码实现
package com.java.sort;
/**
* @author WHT
* @create 2021-10-15 15:20
*/
public class InsertSort {
public static void main(String[] args) {
int[] arr = {5,4,3,2,1};
insertSort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
public static void insertSort(int[] arr) {
//假设从小到大排序。
//1.从头到尾遍历数组,将当前值arr[i]插入前面已经排好序的序列中。
int n = arr.length;
for (int i = 1; i < n; i++) {
int insertVal = arr[i];
for (int j = i - 1; j >= 0; j--) {
if (insertVal >= arr[j]) {
arr[j + 1] = insertVal;
break;
}
arr[j + 1] = arr[j];
if (j == 0) {
arr[0] = insertVal;
}
}
}
}
}
1.1.4 希尔排序
-
希尔排序的原理
(1) 我们假设从小到大排序,首先设定增量gap=arr.length/2,将序列按增量gap分成若干组,每组序列各自使用插入排序。
(2) 然后以gap=gap/2的方式缩小增量,直到增量为1。 -
代码实现
package com.java.sort;
/**
* @author WHT
* @create 2021-10-15 20:37
*/
public class ShellSort {
public static void main(String[] args) {
int[] arr = {5,4,3,2,1};
shellSort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
public static void shellSort(int[] arr) {
//假设从小到大排序。
//1.首先设定增量gap=arr.length/2,将序列按增量gap分成若干组,每组序列各自使用插入排序。
//2.然后以gap=gap/2的方式缩小增量,直到增量为1。
int n = arr.length;
for (int gap = n / 2; gap > 0; gap = gap / 2) {
for (int i = gap; i < n; i++) {
int insertVal = arr[i];
for (int j = i - gap; j >= 0; j = j - gap) {
if (insertVal >= arr[j]) {
arr[j + gap] = insertVal;
break;
}
arr[j + gap] = arr[j];
if (j < gap) {
arr[j] = insertVal;
}
}
}
}
}
}
1.1.5 快速排序
-
快速排序的原理
(1) 我们假设从小到大排序,选择序列的某一元素作为中轴元素pivot,接着将比pivot小的元素放在pivot的左边,比pivot大的元素放在pivot的右边。
(2) 然后分别对pivot左右两边的序列做递归操作,直到只剩1个元素为止。 -
代码实现
package com.java.sort;
/**
* @author WHT
* @create 2021-10-15 16:31
*/
public class QuickSort {
public static void main(String[] args) {
int[] arr = {5,4,3,2,1};
quickSort(arr, 0, arr.length - 1);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
public static void quickSort(int[] arr, int left, int right) {
//假设从小到大排序。
//1.选择数组中间元素作为中轴元素pivot,将比pivot小的元素放在pivot左边,比pivot大的元素放在pivot右边。
int pivot = (left + right) / 2;
int l = left;
int r = right;
while (l < r) {
while (arr[l] < arr[pivot]) {
l++;
}
while (arr[r] > arr[pivot]) {
r--;
}
if (l == r) {
break;
}
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
}
//2.然后对pivot左右两边的序列分别做第1步的操作,直到只剩1个元素为止。
//左半部分递归。
if (left < pivot) {
quickSort(arr, left, pivot - 1);
}
//右半部分递归。
if (right > pivot) {
quickSort(arr, pivot + 1, right);
}
}
}
1.1.6 归并排序
-
归并排序的原理
(1) 我们假设从小到大排序,首先将序列按mid=(left+right)/2分成两部分,接着对左右两部分分别做归并排序,直到分解到只剩1个元素为止。
(2) 然后合并左右两部分。 -
代码实现
package com.java.sort;
/**
* @author WHT
* @create 2021-10-15 21:08
*/
public class MergeSort {
public static void main(String[] args) {
int[] arr = {5,4,3,2,1};
mergeSort(arr, 0, arr.length - 1);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
public static void mergeSort(int[] arr, int left, int right) {
//假设从小到大排序。
//1.首先将序列按mid=(left+right)/2分成两部分,接着对左右两部分分别做归并排序。
//2.然后合并。
if (left < right) {
int mid = (left + right) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, right, mid);
}
}
public static void merge(int[] arr, int left, int right, int mid) {
//1.创建一个额外空间temp。
//2.按从小到大顺序将左右两部分的元素存入temp中。
//3.将temp中的元素拷贝到arr中。
int[] temp = new int[right - left + 1];
int i = left;
int j = mid + 1;
int k = 0;
while (i <= mid && j <= right) {
if (arr[i] < arr[j]) {
temp[k] = arr[i];
i++;
k++;
}
else {
temp[k] = arr[j];
j++;
k++;
}
}
while (i <= mid) {
temp[k] = arr[i];
i++;
k++;
}
while (j <= right) {
temp[k] = arr[j];
j++;
k++;
}
k = 0;
for (int t = left; t <= right; t++) {
arr[t] = temp[k];
k++;
}
}
}
1.2 链表
1.3 二叉树
1.3.1 二叉树的中序遍历
代码实现
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
inorder(root, res);
return res;
}
public void inorder(TreeNode root, List<Integer> res) {
if (root == null) {
return;
}
inorder(root.left, res);
res.add(root.val);
inorder(root.right, res);
}
}
2 计算机网络
-
HTTP 请求的过程:
(1)建立起客户机和服务器的连接。
(2)建立连接后,客户机发送一个请求给服务器。
(3)服务器收到请求给予响应信息。
(4)客户端浏览器将返回的内容解析并呈现,断开连接。 -
HTTP请求的方法:
-
为什么服务器会有缓存这一项功能?如何实现的?
原因:
(1)缓解服务器压力。
(2)降低客户端获取资源的延迟:缓存通常位于内存中,读取缓存的速度更快。并且缓存服务器在地理位置上也有可能比源服务器来得近,例如浏览器缓存。
实现方法:
(1)让代理服务器进行缓存。
(2)让客户端浏览器进行缓存。
- GET 和 POST 的区别:
(1)get是获取数据,post是修改数据。
(2)get把请求的数据放在url上,以?分割URL和传输数据,参数之间以&相连,所以get不太安全。而post把数据放在HTTP的包体内(requrest body)。
(3)get提交的数据最大是2k( 限制实际上取决于浏览器), post理论上没有限制。
(4)GET产生一个TCP数据包,浏览器会把http header和data一并发送出去,服务器响应200(返回数据); POST产生两个TCP数据包,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
(5)GET请求会被浏览器主动缓存,而POST不会,除非手动设置。
(6)本质区别:GET是幂等的,而POST不是幂等的。
这里的幂等性:幂等性是指一次和多次请求某一个资源应该具有同样的副作用。简单来说意味着对同一URL的多个请求应该返回同样的结果。
-
一个TCP连接可以对应几个HTTP请求?
如果维持连接,一个 TCP 连接是可以发送多个 HTTP 请求的。 -
在浏览器中输入url地址后显示主页的过程?
(1)根据域名,进行DNS域名解析。
(2)拿到解析的IP地址,建立TCP连接。
(3)向IP地址,发送HTTP请求。
(4)服务器处理请求。
(5)返回响应结果。
(6)关闭TCP连接。
(7)浏览器解析HTML并呈现内容。 -
Session知识大总结
- 除了可以将用户信息通过 Cookie 存储在用户浏览器中,也可以利用 Session 存储在服务器端,存储在服务器端的信息更加安全。
- Session 可以存储在服务器上的文件、数据库或者内存中。也可以将 Session 存储在 Redis 这种内存型数据库中,效率会更高。
- 使用 Session 维护用户登录状态的过程如下:
(1)用户进行登录时,用户提交包含用户名和密码的表单,放入 HTTP 请求报文中。
(2)服务器验证该用户名和密码,如果正确则把用户信息存储到 Redis 中,它在 Redis 中的 Key 称为 Session ID。
(3)服务器返回的响应报文的 Set-Cookie 首部字段包含了这个 Session ID,客户端收到响应报文之后将该 Cookie 值存入浏览器中。
(4)客户端之后对同一个服务器进行请求时会包含该 Cookie 值,服务器收到之后提取出 Session ID,从 Redis 中取出用户信息,继续之前的业务操作。
-
Session 的工作原理是什么?
session 的工作原理是客户端登录完成之后,服务器会创建对应的 session,session 创建完之后,会把 session 的 id 发送给客户端,客户端再存储到浏览器中。这样客户端每次访问服务器时,都会带着 session id,服务器拿到 session id 之后,在内存找到与之对应的 session 这样就可以正常工作了。 -
Cookie与Session的对比
Cookie是客户端保持状态的方法。
Session是服务器保持状态的方法。 -
SQL注入攻击了解吗?
攻击者在HTTP请求中注入恶意的SQL代码,服务器使用参数构建数据库SQL命令时,恶意SQL被一起构造,并在数据库中执行。
如何解决?
在JDBC中,使用PreparedStatement类进行预编译。我们可以事先将sql语句传入PreparedStatement中,将要传入到sql语句中的参数使用占位符"?"来代替,那么该sql语句就会进行预编译,之后将获取的参数通过PreparedStatement中的set(类型)方法传入编译后的sql语句中,这样sql语句就会先被编译再进行传值,用户输入的信息不会直接参与到sql语句的编译当中,就防止了sql注入的问题。
3 计算机概念
- 日志
日志的级别:OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL。
4 面向对象编程
-
注解
从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。 -
面向对象的三大特性
(1)抽象:抽象指把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或对象操作,对不可信的进行信息隐藏。
(2)继承:继承指子类自动共享父类的数据结构和方法的机制。子类可以在父类的基础上进行扩展。
(3)多态:多态指相同的操作或函数可作用于多种类型的对象上并获得不同的结果。(包括覆盖、重载)
5 数据库
5.1 MySQL的常见命令
show databases; #查看所有的数据库
use 库名; #打开指定的库
show tables; #显示库中的所有表
show tables from 库名; #显示指定库中的所有表
create table 表名(
字段名 字段类型,
字段名 字段类型
); #创建表
desc 表名; #查看指定表的结构
select * from 表名; #显示表中的所有数据
5.2 DQL语言
5.2.1 基础查询
SELECT 要查询的东西
【FROM 表名】;
5.2.2 条件查询
select
要查询的字段|表达式|常量值|函数
from
表
where
条件;
模糊查询:like
5.2.3 排序查询
select
要查询的东西
from
表
where
条件
order by 排序的字段|表达式|函数|别名 【asc|desc】;
5.2.4 分组查询
select 查询的字段,分组函数
from 表
group by 分组的字段
5.2.5 多表连接查询
select 字段,...
from 表1
【inner|left outer|right outer|cross】join 表2 on 连接条件
【inner|left outer|right outer|cross】join 表3 on 连接条件
【where 筛选条件】
【group by 分组字段】
【having 分组后的筛选条件】
【order by 排序的字段或表达式】
5.2.6 子查询
5.2.7 分页查询
select 字段|表达式,...
from 表
【where 条件】
【group by 分组字段】
【having 分组后的筛选条件】
【order by 排序的字段】
limit 【起始的条目索引,】条目数;
5.2.8 联合查询
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
.....
select 字段|常量|表达式|函数 【from 表】 【where 条件】
5.3 DML语言
5.3.1 插入
insert into 表名(字段名,...)
values(值1,...);
5.3.2 修改
- 修改单表语法:
update 表名 set 字段=新值, 字段=新值
【where 条件】
- 修改多表语法:
update 表1 别名1, 表2 别名2
set 字段=新值, 字段=新值
where 连接条件
and 筛选条件
5.3.3 删除
- 单表的删除:
delete from 表名 【where 筛选条件】
- 多表的删除:
delete 别名1,别名2
from 表1 别名1,表2 别名2
where 连接条件
and 筛选条件;