0%

什么是jsp

是动态网页,可以嵌入java 代码 ,jsp 爷爷是servlet

基础语法

1
2
3
4
5
6
7
8
9
10
11
12
13
<%-- page指令,可以配置session,errorPage,iserrorpage等等 --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%-- 包含指令:用于设置公共的部分(eg:页头、也脚) --%>
<%@include file="/index.jsp"%>
<%!
// ! 定义在方法外面,可用做类的方法、属性
void function() {
}
%>
<%
String aa = "xaa"; //java 代码
%>
<%=aa%> <%-- 相当于out.print(aa); --%>

jsp九大隐式对象

  • Reqeust
  • Response
  • Session
  • Application
  • Config
  • Page
  • Out
  • Exception (jsp独有)
  • pageContext (jsp独有)

常见问题

idea配置

idea添加tomcat出现application server libraries not found

原因: 权限不足

解决: sudo chown -R 【用户名】 【tomcat目录】

抽象类

思想

动物->抽象类,猴子->子类

注意点:
  1. 抽象类不能被实例化,实例化的工作应该交由它的子类来完成,它只需要有一个引用即可。
  2. 抽象方法必须由子类来进行重写。
  3. 只要包含一个抽象方法的类,该类必须要定义成抽象类。
  4. 抽象类中可以包含具体的方法,当然也可以不包含抽象方法。
  5. 子类中的抽象方法不能与父类的抽象方法同名。
  6. abstract不能与final并列修饰同一个类。
  7. abstract 不能与private、static、final或native并列修饰同一个方法。
    实例

子类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MainActivity extends baseActity {
TextView textView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.aa);
super.initdata("s");
}

@Override
public void send(String data) {
textView.setText(data);
}
}

抽象类:

1
2
3
4
5
6
7
8
9
public abstract class baseActity extends AppCompatActivity {
int i = 0;

void initdata(String a) {
send(a + i++);
}

public abstract void send(String data);
}

参考

 java提高篇(四)—–抽象类与接口

快速排序

Sorting_quicksort_anim

思想

快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。

步骤为:

  1. 从数列中挑出一个元素,称为”基准”(pivot)
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
    递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

    时间复杂度

    最好时间复杂度 $O(nlog(n))$
    最坏时间复杂度 $O(n^2)$

线性时间选择

问题描述

如何找出数组A中的第 k 小的元素? (1<=k<=n)
timeselect

步骤:

  1. 将n个元素分成5个一组,共ceiling(n/5)组。其中最后1组有n mod 5(余数)个元素。
  2. 用插入排序对每组排序,取其中值。若最后1组有偶数个元素,取较小得中值
  3. 递归的使用本地算法寻找ceiling(n/5)个中位数的中值x //第一次递归调用本身
  4. 用x作为划分元对数组A进行划分,并设x是第k个最小元
  5.  if i=k then return x;
     else if i<k then 找左区间的第i个最小元; //第二次递归调用本身
     else 找右区间的第i-k个最小元
    

流水作业调度

问题描述

n个作业{1,2,…,n}要在由2台机器M1和M2组成的流水线上完成加工。每个作业加工的顺序都是先在M1上加工,然后在M2上加工。M1和M2加工作业i所需的时间分别为ai和bi。

最优解:n个作业的加工顺序、完成n个作业所需的最短时间
最优值:T(N,0)

Johnson法则

参考

0018算法笔记——【动态规划】流水作业调度问题与Johnson法则

0-1背包问题

250px-Knapsack.svg

问题描述

给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。

子问题最优值:m(i,j)
原问题最优值:m(1,c)
m(i,j)意为背包容量为j,可选择物品为,i,i+1,……,n时0,1问题的最优值。

贪心算法解

动态规划解

贪心算法

Greedy_algorithm_36_cents.svg

思想

是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是最好或最优的算法。

步骤:

  1. 建立数学模型来描述问题。
  2. 把求解的问题分成若干个子问题。
  3. 对每一子问题求解,得到子问题的局部最优解。
  4. 把子问题的解局部最优解合成原来解问题的一个解。
    eg: 0-1背包问题、哈弗曼编码

    二分搜索

    Binary_search_into_array
    时间复杂度 $O(log(n))$
    最优时间复杂度 $O(1)$
    平均时间复杂度 $O(log(n))$

思想

一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。

步骤:

给予一个包含n个带值元素的数组A或是记录A0 … An−1,使得A0 ≤ … ≤ An−1,以及目标值T,还有下列用来搜索T在A中位置的子程序[3]。

  1. 令L为0,R为n− 1。
  2. 如果L > R,则搜索以失败告终。
  3. 令m(中间值元素)为“(L + R) / 2”加上下高斯符号。
  4. 如果Am < T,令L为m + 1并回到步骤二。
  5. 如果Am > T,令R为m - 1并回到步骤二。
  6. 当Am = T,搜索结束;回传值m。
    这个迭代步骤会持续通过两个变量追踪搜索的边界。有些实际应用会在算法的最后放入相等比较,让比较循环更快,但平均而言会多一层迭代

矩阵连乘

jx

问题描述

给定n个矩阵:A1,A2,…,An,其中Ai与Ai+1是可乘的,i=1,2…,n-1。确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。输入数据为矩阵个数和每个矩阵规模,输出结果为计算矩阵连乘积的计算次序和最少数乘次数。

最优二叉搜索树

分治法

步骤:

  1. 分解:将原问题分解为若干个规模较小,相对独立,与原问题形式相同的子问题。
  2. 解决:若子问题规模较小且易于解决时,则直接解。否则,递归地解决各子问题。
  3. 合并:将各子问题的解合并为原问题的解。

eg: 快速排序

动态规划

基本思想

通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法

基本要素:

重叠子问题、最优子结构性质

试用情况

  1. 最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。
  2. 无后效性。即子问题的解一旦确定,就不再改变,不受在这之后、包含它的更大的问题的求解决策影响。
  3. 子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。

eg: 背包问题

合并排序(归并排序)

Merge-sort-example-300px
时间复杂度 $O(nlog(n))$
最优时间复杂度 $O(n)$
平均时间复杂度 $O(nlog(n))$

基本思想

将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。

哈弗曼编码

350px-Huffman_tree_2.svg
这个句子“this is an example of a huffman tree”中得到的字母频率来建构霍夫曼树。句中字母的编码和频率如图所示。编码此句子需要135 bit(不包括保存树所用的空间)

Huffman_algorithm

  • 平移动画

TranslateAnimation animation=new TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
fromXDelta 起点x
fromYDelta 起点y
toXDelta 终点x
toYDelta 终点y
以控件的中心为原点坐标,起点终点都是在原点坐标为基准

animation.setDuration(2000); 设置动画时间
animation.setFillAfter(false); 设置动画结束是否停留显示(false不显示),如果为true,不能通过隐藏控件让他消失
rb_anmia.setAnimationListener() 设置动画的监听(onAnimationStart,onAnimationEnd,onAnimationRepeat
view.startAnimation(animation); 启动动画

自定义控件的基本使用

  • 创建一个控件类继承ViewGroup
  • 复写onlayout
  • 复写测量onMeasure
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ArcMenu extends ViewGroup {
public ArcMenu(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int cent_x = getWidth() / 2; //viewgroup中心坐标
int cent_y = getHeight() / 2; //viewgroup中心坐标
for (int i = 0; i < getChildCount(); i++) {

View childView = getChildAt(i); //遍历子控件
int childWidth = childView.getMeasuredWidth(); //获得子控件的宽度,需要先测量
int childHeight = childView.getMeasuredHeight();

int cl = 0, ct = 0, cr = 0, cb = 0;
}

childView.layout(cl, ct, cr, cb); //见下图
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//测量所有子View的宽高
measureChildren(widthMeasureSpec, heightMeasureSpec);
}
}

childView.layout(cl, ct, cr, cb)
62o7O1.png

  • 在xml里面引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<com.xuan.hifusion.customcontrols.ArcMenu
android:id="@+id/car_arcmenu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center">

<ImageView
android:id="@+id/car_cent_line_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
app:srcCompat="@drawable/car_cent_line" />

<ImageView
android:id="@+id/car_light_off_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tag="右下"
android:visibility="invisible"
app:srcCompat="@drawable/car_light_off" />
</com.xuan.hifusion.customcontrols.ArcMenu>

定时心跳

场景描述:
  1. 一个发送数据出口
  2. 定时循环发送一个数据
  3. 当需要发送一个数据临时插入一个数据从出口发送
需要用到的操作符

repat 重复发送
delay 延时发送
just 快速创建被观察者,插入心跳数据
mergeDelayError 合并发送,错误延时

流程

主要是创建两个被观察者,一个负责心跳的发送,另外一个负责数据的发送

实现代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Observable alive=Observable.just(temp_send).delay(4000,TimeUnit.MILLISECONDS).repeat(); //心跳数据(每隔4s重复发一次)
Observable send= Observable.create(new Observable.OnSubscribe<byte[]>() {
@Override
public void call(Subscriber<? super byte[]> subscriber) {
subscriberSend=subscriber; //负责数据的发送
}
});
//合并,订阅
send_subscribe= Observable.mergeDelayError(alive,send).subscribe(new Action1<byte[]>() {
@Override
public void call(byte[] bs) {
send(bs); //数据出口
}
});

重复执行某个动作直到成功,或失败,或超时

场景描述:
  1. 重复执行某个动作
  2. 成功后中断继续执行操作
  3. 错误继续执行
  4. 未响应发出超时错误,并继续执行
  5. 达到超时次数,终止执行
需要用到的操作符

distinct 过滤
timeout 超时发出错误
retryWhen 错误重试
zipWith 合并(用于统计错误重试次数)
delay 延时(用于发送错误后等待一段时间继续发送)

流程

发出动作请求,等待结果,过滤结果。

  1. 结果为onError立马重新发出动作请求
  2. 等待指定时间没有结果,发出超时onError然后重新发出动作请求
  3. 结果为成功结果终止动作请求
  4. 直到成功为止,或者超过重试的指定次数
实现代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public Observable<String> xuanSend(final String str){
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
Log.d("TASK_SHOW","任务:"+str+",状态:开始执行,发送数据:空");
strTask=str;
subscriber.onNext(str+"中......");
subscriberTask=subscriber; //执行结果的入口

}
}).distinct().timeout(5000,TimeUnit.MILLISECONDS).retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {
@Override
public Observable<?> call(final Observable<? extends Throwable> observable) {
return observable.zipWith(Observable.range(1, 5), new Func2<Throwable, Integer, Object>() {
@Override
public Object call(Throwable throwable, Integer integer) {
if(throwable.getMessage()==null)
Log.d("TASK_SHOW","任务:"+str+",状态:异常结束,异常:"+"第"+integer+"次,执行超时");
else
Log.d("TASK_SHOW","任务:"+str+",状态:异常结束,异常:"+throwable.getMessage());
return 0;
}
}).delay(10000,TimeUnit.MILLISECONDS);
}
});
}

任务流(循环)

场景描述
  1. 一个动作完成后才执行下一个动作
  2. 所有动作完成后重复继续执行
需要用到的操作符

concat 连接操作符(只能连接9个,但是可以嵌套)
repat 循环

流程

使用flatmap创建一个基本异步任务,用concat实现连接,用reapt实现循环

实现代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//任务流
Observable<String> task=Observable.concat(mBle.connet(bleDevicesList.getmBleDevicesList_test()),mBle.enableRX(),mBle.xuanSend(sendData.setStart(false),Ble.START),mBle.xuanSend(sendData.setsafe(false,false),Ble.CANCELSAFE),mBle.disConnet());

task.repeat().subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
//所有任务完成,但是如果reapt(),始终是不会完成的
}
@Override
public void onError(Throwable e) {
//发生错误时
}
@Override
public void onNext(String result) {
//任务完成
}

});

时间复杂度

概念: 时间复杂度是用来衡量算法的执行时间上的效果。
计算方式:
1. 找出算法的基本语句

算法中执行次数最多的那条语句就是基本语句,通常是最内层循环的循环体。
eg: i++; //时间复杂度为O(1)

2. 计算语句执行的数量级

只需计算基本语句执行次数的数量级,这就意味着只要保证基本语句执行次数的函数中的最高次幂正确即可,可以忽略所有低次幂和最高次幂的系数。这样能够简化算法分析,并且使注意力集中在最重要的一点上:增长率。
eg:

1
2
3
4
int sum=0;                //(一次)
for(int i=1;i<=n;i++) //(n+1次)
for(int j=1;j<=n;j++) //(n²次)
sum++; //(n²次)

因为
$\Theta(2n^2 +n+1)=n^2$($\Theta$即:去低阶项,去掉常数项,去掉高阶项的常参得到),所以$T(n)=O(n^2)$。

3. 时间复杂度表示格式
  • $O(1)$
  • $O(log(n))$
  • $O(n)$
  • $O(nlog(n))$
  • $O(n^2)$
  • $O(n^3)$
  • $O(2^n)$
  • $O(n!)$
  • $O(n^n)$