面向对象实战
编程要提高效率
如:0-100的求和问题,最简单的可以用一个for循环解决。
但如果用数学上总结的高斯求和(1+100) * 50,会更快更有效率。
对象设计(面向对象、多态运用)
1、设计一个Person抽象类,包含吃饭运动学习三种运动,分为工人、学生、老师三种职业
2、设计一个接口考试
,只有老师和学生会考试(只有老师和学生才实现这个接口)
3、设计一个方法,模拟让人类进入考场,要求只有会考试的人才能进入,并且考试
1、设计一个Person抽象类,包含吃饭运动学习三种运动,分为工人、学生、老师三种职业
package Person;
import java.sql.PseudoColumnUsage;
public abstract class Person { //设计一个Person抽象类,里面包含吃饭、运动、学习三种行为
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
public abstract void eat();
public abstract void sport();
public abstract void study();
}
三者差不多,就列一个吧
package Person;
public class Student extends Person{
public Student(String name, int age){
super(name, age);
}
@Override
public void eat(){
System.out.println("有些人多,有些人少");
}
@Override
public void sport(){
System.out.println("有些人大,有些人小");
}
@Override
public void study(){
System.out.println("读书是必须的");
}
}
2、设计一个接口考试
,只有老师和学生会考试(只有老师和学生才实现这个接口)
在老师和学生类中添加接口和方法的实现
package Person;
import Test.*;
public class Student extends Person implements Test{
public Student(String name, int age){
super(name, age);
}
@Override
public void eat(){
System.out.println("有些人多,有些人少");
}
@Override
public void sport(){
System.out.println("有些人大,有些人小");
}
@Override
public void study(){
System.out.println("读书是必须的");
}
@Override
public void test(){
System.out.println("我会考试");
}
}
3、设计一个方法,模拟让人类进入考场,要求只有会考试的人才能进入,并且考试
import Person.Person;
import Test.*;
import Person.*;
public class Main {
public static void main(String[] args) {
Worker worker1 = new Worker("工人1", 30);
test(worker1);
Teacher teacher1 = new Teacher("王老师", 35);
test(teacher1);
Student student1 = new Student("施同学", 23);
test(student1);
}
private static void test(Person person){
if(person instanceof Test){ //如果实现了该接口
Test e = (Test) person; //强制类型转换,因为肯定是exam的实现
e.test();
} else {
System.out.println("没有考试接口");
}
}
}
二分搜索
现在有一个有序数组(从小到大,数组长度0<n<1000000)如何快速寻找我们想要的数在哪个位置,如果存在请返回下标,不存在返回-1即可。
思路梳理
1、从中间开始找,跟两边对比,确定下一个二分的方向。
2、截断原来数组的一般,再重复1的步骤。
由于循环有对半的过程,因此时间复杂度有O(logn)
public class Main {
public static void main(String[] args) {
int[] arr = new int[]{1, 4, 5, 6, 7, 10, 12, 14, 20, 26};
System.out.println(binary_search(arr, 10));
System.out.println(binary_search(arr, 11));
}
public static int binary_search(int[] arr, int target){
int start = 0, end = arr.length - 1; //定义范围的起始和终点位置
while(end >= start){ //设定继续寻找的条件
int mid = (start + end + 1) / 2; //这里+1是为了防止奇数时找到中间前一位,偶数+1不影响。
if(arr[mid] == target) return mid;
if(arr[mid] < target) start = mid + 1;
if(arr[mid] > target) end = mid - 1;
}
return -1; //没找到的情况
}
}
快速排序
快速排序其实是一种排序执行效率很高的排序算法,它利用分治法来对待排序序列进行分治排序,它的思想主要是通过一趟排序记录分隔成独立的两部分,其中的一部分比关键字小,后面一部分比关键字大,然后再对这前后的两部分分别采用这种方式进行排序,通过递归的运算最终达到整个序列有序。
递归方法:
public class Main {
public static void main(String[] args) {
System.out.println(test(100));
}
static int test(int i){
if (i==0) return 0;
return test(i-1) + i;
}
}
就是从100进去,然后到第二个return,进入第二次方法,…,最后倒数第一个方法返回了0,那么倒数第二个就是返回0+1,倒数第三个就是1+2,…,慢慢再把数值返回到最外层。
快速排序思路:
先贴一个图解链接快速排序图解
再加上自己总结的内容:
1、定义left和right索引定位
2、拿到第一个位置的数作为基准
3、从right向左开始和基准做比较,出现第一个right比基准小的,那么就把right对应的索引空出来作为坑,对应位置移到第一个基准的索引处。把
4、再从left向右开始和基准比较,出现第一个left比基准大的,就把left对应的索引空出来作为坑,对应的数放到3中的坑中。
5、重复步骤直到left=right后,这么一趟排序就完成了。数组就分成了三部分,左边是比基准小的,右边是比基准大的,中间是基准。
6、对分好的两个区域重复3、4、5步。
需要的东西:基准元素,左右断点、基准数。
import javax.swing.event.MenuDragMouseListener;
public class Main {
public static void main(String[] args) {
int[] arr = new int[]{8, 2, 3, 5, 4, 7, 9, 1, 0};
fast_ordering(arr, 0, arr.length - 1);
for(int i = 0; i < arr.length; i++){
System.out.print(arr[i] + " ");
}
}
static void fast_ordering(int[] arr, int start, int end){
if (start >= end) return; //设置结束条件
int base = arr[start]; //基准
int left = start;
int right = end;
while(left < right){
while(left < right && base <= arr[right]) right--;
arr[left] = arr[right]; //把对应位置的坑让给他
while(left < right && base >= arr[left]) left++;
arr[right] = arr[left];
}
arr[left] = base; //一趟排完
fast_ordering(arr, start, right - 1); //递归前一部分
fast_ordering(arr, right + 1, end); //递归后一部分
}
}
0/1背包问题
给定n件五排,每一个物品的重量为w[n],每个物品的价值为v[n]。现挑选物品放入背包中,假定背包能承受的最大重量为capacity, 求装入物品的最大价值是多少?
第一种方法:回溯法、剪枝
回溯法:
先选A,再分叉B,C,再分叉…
由于存在capacity,因此有些会走不下去,所以要进行剪枝处理。
代码段:
public class Main {
static int[] w = {2, 3, 4, 5}; //static静态变量能够省去new实例化对象过程 weight
static int[] v = {3, 4, 5, 6}; //value
static int capacity = 8;
public static void main(String[] args) {
System.out.println(test(0, 0)); //开始的下标、最开始的重量
}
static int test(int index, int weight){
if(index >= 4) return 0; //结设置递归束条件
if(capacity < weight + w[index]) return 0;
return Math.max(v[index] + test(index + 1, weight + w[index]), test(index + 1, weight));
//使用Math.max选两者之中大的,第一个是选这个分支,加上重量往下走,第二个是不选这个分支,不加这个重量往下走。
//
}
}
第二种方法:动态规划
其实就是从下往上写
当第三行的剩余7开始,就可以看到3和4的组合9比单个的4大,所以要换。
代码段为了方便,表就是从上往下写。
public class Main {
static int[] w = {2, 3, 4, 5}; //static静态变量能够省去new实例化对象过程 weight
static int[] v = {3, 4, 5, 6}; //value
static int capacity = 8;
public static void main(String[] args) {
//System.out.println(test(0, 0)); //开始的下标、最开始的重量
dynamic_arranging();
}
static int test(int index, int weight){
if(index >= 4) return 0; //结设置递归束条件
if(capacity < weight + w[index]) return 0;
return Math.max(v[index] + test(index + 1, weight + w[index]), test(index + 1, weight));
//使用Math.max选两者之中大的,第一个是选这个分支,加上重量往下走,第二个是不选这个分支,不加这个重量往下走。
//
}
static void dynamic_arranging(){
int[][] arr = new int[5][capacity + 1]; //创建表, 第一维为n+1,多一排0以防数组越界。
for (int i = 1; i <= 4; i++){ //开始填表 注意i从1开始,所以i-1是当前位置。
for (int j = 1; j <= capacity; j++){
if(w[i - 1] <= j) {
arr[i][j] = Math.max(arr[i - 1][j], arr[i - 1][j - w[i - 1]]+ v[i - 1]); //判断是原来的大还是当前的加上上一行中剩余空间的价值加上 关键行
}else{
arr[i][j] = arr[i - 1][j];
}
}
}
for (int i = 0; i < arr.length; i++){
for (int j = 0; j < arr[i].length; j ++){
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
}
这一块确实有点绕,不理解的话可以在关键那一行设置个中断,带入一个具体值去算一下就理解了。