3-2-选择排序
排序原理:
1.每一次遍历的过程中,都假定第一个索引处的元素是最小值,和其他索引处的值依次进行比较
**如果当前索引处的值大于其他某个索引处的值,则假定其他某个索引出的值为最小值,最后可以找到最小值所在的索引 **
2.交换第一个索引处和最小值所在的索引处的值
原始数据到第一趟排序:假定4是最小值,让4分别与数据的其他7位元素进行比较,如果有比4小的数,交换二者位置让那个数成为最小值放在第一位,然后继续比较,直到到了元素的最后一位
第六趟到第7趟排序:假定8是最小值,与后面的10,9进行比较,如果有比4小的数,交换二者位置让那个数成为最小值放在第一位,然后继续比较,直到到了元素的最后一位
123456789101112131415161718192021222324public static void sort(Comparable[] a){ for (int i = 0; i < a.length - 1; i++) { //定义一个变量,记录最小元素所在的索引,默认为参与选择排序的第一个元素所在的位置 ...
3-1-冒泡排序
排序原理:
1. 比较相邻的元素。如果前一个元素比后一个元素大,就交换这两个元素的位置。
2. 对每一对相邻元素做同样的工作,从开始第一对元素到结尾的最后一对元素。最终最后位置的元素就是最大值。
**初始状态到第一次冒泡 : **
比较 4,5,5比4大,不变。
比较5,6,6比5大,不变
比较6,3,3比6小,交换二者位置 4,5,3,6,2,1
比较6,2,2比6小,交换二者位置 4,5,3,2,6,1
比较6,1,1比6小,交换二者位置 4,5,3,2,1,6
假设数组长度为n,冒泡排序必须实现n-1次冒泡(令k = n)
第一次冒泡要有k-1次比较
第二次冒泡要有k-2次比较
第n-1次冒泡要有k-n-1次比较
123456789public static void sort(Comparable[] a){ for (int i = a.length-1;i > 0;i--){ for (int j = 0; j < i; j++) { if (greate ...
2-3-算法的空间复杂度分析
一、java中常见内存占用1.基本数据类型内存占用情况:
2.计算机访问内存的方式都是一次一个字节
3.一个引用(机器地址)需要8个字节表示:
例如: Date date = new Date(),则date这个变量需要占用8个字节来表示
4.创建一个对象,比如new Date(),除了Date对象内部存储的数据(例如年月日等信息)占用的内存,该对象本身也 有内存开销,每个对象的自身开销是16个字节,用来保存对象的头信息。
5.一般内存的使用,如果不够8个字节,都会被自动填充为8字节
6.java中数组被被限定为对象,他们一般都会因为记录长度而需要额外的内存,一个原始数据类型的数组一般需要24字节的头信息
(16个自己的对象开销,4字节用于保存长度以及4个填充字节)再加上保存值所需的内存。
二、算法的空间复杂度算法的空间复杂度计算公式记作:S(n)=O(f(n)),其中n为输入规模,f(n)为语句关于n所占存储空间的函数。
案例: 对指定的数组元素进行反转,并返回反转的内容。
根据大O推导法则,算法一的空间复杂度为O(1)
算法 ...
2-2-函数调用时间复杂度分析
案例一:123456789public static void main(String[] args) { int n=100; for (int i = 0; i < n; i++) { show(i); }}private static void show(int i) { System.out.println(i);}
show方法的时间复杂度为O(1),main方法的时间复杂度是O(n)
案例二:1234567891011public static void main(String[] args) { int n=100; for (int i = 0; i < n; i++) { show(i); }}private static void show(int i) { for (int j = 0; j < i; i++) { System.out. ...
2-1-算法时间复杂度分析
最高次项的指数大的,随着n的增长,结果也会变得增长特别快
算法函数中n最高次幂越小,算法效率越高
1.算法函数中的常数可以忽略;
2.算法函数中最高次幂的常数因子可以忽略;
3.算法函数中最高次幂越小,算法效率越高。
大O记法在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随着n的变化情况并确定T(n)的 量级。算法的时间复杂度,就是算法的时间量度,记作:T(n)=O(f(n))。
它表示随着问题规模n的增大,算法执行时间 的增长率和f(n)的增长率相同,称作算法的渐近时间复杂度,简称时间复杂度,其中f(n)是问题规模n的某个函数。
执行次数=执行时间
算法一:12345678910public static void main(String[] args) { int sum = 0;//执行1次 int n=100;//执行1次 sum = (n+1)*n/2;//执行1次 System.out.println("sum="+sum);}
算法二:123456 ...
1-1-数据结构分类
数据结构分类:
顺序存储结构: 把数据元素放到地址连续的存储单元里面,其数据间的逻辑关系和物理关系是一致的 ,比如我们常用的数组就是顺序存储结构。
链式存储结构: 是把数据元素存放在任意的存储单元里面,这组存储单元可以是连续的也可以是不连续的。此时,数据元素之间并 不能反映元素间的逻辑关系,因此在链式存储结构中引进了一个指针存放数据元素的地址,这样通过地址就可以找 到相关联数据元素的位置
逻辑结构分类:
集合结构:集合结构中数据元素除了属于同一个集合外,他们之间没有任何其他的关系。
线性结构:线性结构中的数据元素之间存在一对一的关系
树形结构:树形结构中的数据元素之间存在一对多的层次关系
图形结构:图形结构的数据元素是多对多的关系
01-设计模式的原则
设计模式的目的1、代码重用性
2、可读性
3、可扩展性(增加功能时,对原来的功能没有影响)
4、可靠性(增加功能时,对原来的功能没有影响)
5、高内聚,低耦合
单一职责原则一个类应该只负责一项职责
如:类 A 负责两个不同职责:职责 1,职责 2。
当职责 1 需求变更而改变 A 时,可能造成职责 2 执行错误,所以需要将类 A 的粒度分解为 A1,A2
注意:
降低类的复杂度,一个类负责一个职责
提高类的可读性
降低变更的风险
只有类中方法数量足够少时,可以在方法级别保持单一职责原则
接口隔离的原则客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上
类A和类C只需要依赖接口1的一部分接口,而不需要实现全部,所以可以将接口 Interface1 拆分为独立的几个接口(这里我们拆分成 3 个接口),类 A 和类 C 分别与他们需要的接口建立依赖关系
依赖倒转原则1)高层模块不应该依赖底层模块,二者都应该依赖其抽象
2)抽象不应该依赖细节,细节应该依赖抽象
3)核心思想:面向接口编程
三种方式:接口 ...
06-本地方法栈和本地方法
本地方法实际上是一个java调用非java代码的一个接口 ( 使用native关键字进行修饰 )
本地方法的作用:
1、Java应用与Java外面的环境交互
2、与操作系统进行交互
3、Sun公司解释器由C实现
本地方法栈 (线程私有)Java虚拟机栈用于管理Java方法的调用,而本地方法栈用于管理本地方法的调用
本地方法栈中登记本地方法,然后执行引擎执行时,加载本地方法库
当某一个线程调用本地方法时
本地方法可通过本地方法接口来访问虚拟机内部的运行时数据区
可以使用本地处理器中的寄存器
……(和虚拟机拥有一样的权限)
05-虚拟机栈及相关问题
虚拟机栈 (线程私有)
不存在GC,存在OOM
每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个栈帧,对应着一次次的方法调用
虚拟机栈的生命周期和线程一致。作用是主管java程序的运行,保存方法的局部变量(8种基本数据类型,对象的引用地址,对象实际存储在堆空间中),部分结果,并参与方法的调用和返回
栈是一种快速有效的分配存储方式,访问速度仅次于程序计数器
JVM直接对栈的操作:1、每个方法执行,伴随着进栈(入栈,压栈)
2、执行结束后的出栈操作
设置栈内存的大小使用参数-Xss选项设置线程的最大栈空间,栈的大小直接决定了函数调用的最大可达深度
栈的存储单位1)栈中的数据都是以栈帧为基本单位存在
2)在这个线程上正在执行的每个方法都各自对应着一个栈帧
3)栈帧是一个内存区块,是一个数据集,****维系着方法执行过程中的各种数据信息
4)在一条活动线程中,一个时间点上,只会有一个活动的栈帧。即只有当前正在执行的方法的栈帧(栈顶栈帧)是有效的,这个栈帧被称为当前栈帧,与当前栈帧相对应的方法就是当前方法,定义这个方法的类就是当前类。
5)执行引擎运行的所有字节码指令只针对当前栈帧进行 ...
04-程序计数器
程序计数器(PC寄存器)概述既不存在GC也不存在OOM
PC寄存器用来存储指向下一条指令的地址,也是即将要执行的指令代码。由执行引擎读取下一条指令
它是一块很小的内存空间,几乎可以忽略不记。也是运行速度最快的存储区域。
在JVM规范中,每个线程都有它自己的程序计数器,是线程私有的,生命周期与线程的生命周期保持一致。
代码演示
通过PC寄存器,我们就可以知道当前程序执行到哪一步了
使用PC寄存器存储字节码地址有什么用?(为什么要使用PC寄存器记录当前线程的执行地址呢?)1、CPU需要不停的切换各个线程,这时候切换回来以后,就得知道接着从哪开始继续执行。
2、JVM的字节码解释器需要通过改变PC寄存器的值来明确下一条应该执行什么样的字节码指令。
PC寄存器为什么被设定为线程私有的?由于CPU时间片轮限制,众多线程在并发执行过程中,任何一个确定的时刻,一个处理器或者多核处理器中的一个内核,只会执行某个线程中的一条指令。
这样必然导致经常中断或恢复,为了保证分毫无差。每个线程在创建后,都会产生自己的程序计数器和栈帧,程序计数器在各个线程之间互不影响。
比如一个cp ...