数组排序之冒泡快排、OOP、类相关知识(Java学习笔记三)

数组算法之排序

衡量排序算法优劣的标准:

  • 时间复杂度。

  • 空间复杂度。

  • 稳定性。若两个记录A和B的关键字值相等,且排序后A、B的先后次序保持不变,则称这种排序算法是稳定的

分类:

  • 内部排序:所有排序操作都在内存中完成,不需要外部存储器。
  • 外部排序:参加排序的数据量非常大,需要接触外部存储器。常见的是多路归并排序。可认为外部排序是由多次内部排序组成。

十大内部排序算法:

  • 选择排序:直接选择排序、堆排序。
  • 交换排序:冒泡排序、快速排序。
  • 插入排序:直接插入排序、折半插入排序、希尔排序。
  • 归并排序。
  • 桶式排序。
  • 基数排序。

算法五大特征:

  • 输入:0个或多个输入,输入必须有清楚的描述和定义。
  • 输出:1个或多个输出。
  • 有穷性:有限步骤内结束,且每一步在可接受时间内完成。
  • 确定性:有明确的含义,无二义性。(此处指确定性算法,但目前诞生很多非确定性算法,比如深度学习相关算法等)
  • 可行性:所有步骤清晰可行,用户可人为计算得出。

各大排序算法复杂度、稳定性等对比:

(”希堆快选“——不稳定;其余稳定)

在这里插入图片描述


冒泡排序

算法课学习过,不再赘述。实现如下:

public static int[] bubbleSort(int[] nums) {

        for (int i = 0; i < nums.length - 1; i++) {
            for (int j = 0; j < nums.length - i - 1; j++) {
                if (nums[j] > nums[j + 1]) {
                    int temp = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = temp;

//                    nums[j] = nums[j] ^ nums[j + 1];
//                    nums[j + 1] = nums[j] ^ nums[j + 1];
//                    nums[j] = nums[j] ^ nums[j + 1];

//                    nums[j + 1] = (nums[j] ^ nums[j + 1]) ^ nums[j + 1];
//                    nums[j] = (nums[j] ^ nums[j + 1]) ^ nums[j + 1];
                }
            }
        }
        return nums;
    }

快速排序

思想算法课学习过,不再赘述。实现如下:

注意点:1.递归思想及递归出口;2.必须从基准数的对面(右边)开始;

 public static int[] fastSort(int[] nums, int left, int right) {
        if (left < right) {
            int base = nums[left];
            int i = left;
            int j = right;
            while (i < j) {
                while (i < j) {
                    if (nums[j] >= base) {
                        j--;
                    } else break;
                }
                while (i < j) {
                    if (nums[i] <= base) {
                        i++;
                    } else break;
                }
                int temp = nums[j];
                nums[j] = nums[i];
                nums[i] = temp;
            }
            nums[left] = nums[j];
            nums[j] = base;
            fastSort(nums, left, j - 1);
            fastSort(nums, j + 1, right);
        }

        return nums;
 }

Arrays工具类

java.utils.Arrays类提供操作数组的各种方法(比如排序和搜索等)。

  • 判断两个数组是否相等(值):equals(int[] a, int[] b);
  • 输出数组信息:toString(int[] a);
  • 将指定值填充到数组中(会替换掉所有元素):fill(int[] a, int val);
  • 对数组进行排序:sort(int[] a);
  • 二分查找指定值:binarySearch(int[] a, int key);

数组常见异常

  • 数组角标越界异常:ArrayIndexOutOfBoundsExcetion
  • 空指针异常:NullPointerException(这个异常见过无数次了)

面向过程(POP)与面向对象(OOP)

二者都属于编程思想,面向对象是相对于面向过程而言的,“万事万物皆对象”。

  • 面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。

  • 面向对象,将功能封装到对象中,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。

面向对象三大特征:继承、封装、多态。

类和对象
  • 类:对一类事物的描述,是抽象的、概念上的定义。
  • 对象:是存在的该类事物的每个个体,也称作实例(instance)。

常见的类成员:

  • Field = 属性 = 成员变量
  • Method = 方法 = 函数 = 成员方法 = 行为

通过“对象.属性”或“对象.方法”调用对象的结构。如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。

对象/对象数组内存解析
  • 栈:即虚拟机栈。存储局部变量,方法执行完自动释放。
  • 堆:存储对象实例(new出来的)。所有的对象实例以及数组都要在堆上分配。对象的属性及属性值也存储在堆。
  • 方法区:存储方法、常量、静态变量、类信息、以及可编译器编译后的代码等数据。
匿名对象

创建的对象没有显式地赋给一个变量名,即为匿名对象。

特征:匿名对象只能调用一次。

使用:

new PhoneFactory().show(new Phone());

class PhoneFactory{
    public void show(Phone phone){
        phone.sendMail();
        phone.playGame();
    }
}
class Phone {
    double price;
    public void sendMail() {
        System.out.println("发送邮件");
    }
    public void playGame() {
        System.out.println("玩游戏");
    }
}

属性(成员变量)和局部变量

相同点:

  • 定义变量的方法相同: 数据类型 变量名 = 变量值;
  • 先声明,后使用。
  • 都有其对应的作用域。

不同点:

  • 在类中声明的位置不同。
  • 权限修饰符不同。属性可以使用private、protected、public等,但局部变量不可以使用权限修饰符。
  • 默认初始值不同。属性根据其类型有默认初始值。局部变量没有初始化值,所以在调用局部变量之前,一定要显式赋值。特别地,形参在调用时,我们复制即可。
  • 在内存中加载的位置不同。属性在堆(非static),局部变量在栈。

属性的赋值顺序:

  1. 默认初始值;
  2. 显式赋值;
  3. 构造器中赋值;
  4. 通过“对象.方法”或者”对象.属性“赋值。

方法

权限修饰符 返回类型 方法名(形参类型 形参,…){方法体}

注意:

  • return关键字后面不可以声明执行语句。
  • 方法的使用中,可以调用当前类的属性或方法。
  • 方法中不可以定义方法。

重载

一个类中,允许存在一个以上的名方法,只要他们的参数个数或者参数类型不同即可。(两同一不同)

特点:与返回值类型、形参变量名、方法体、权限修饰符无关,只看参数列表,且参数列表必须不同。调用时根据方法参数列表的不同来区别。


可变个数形参(Varargs)

允许直接定义能和多个实参相匹配的形参。从而可以用一种更简单的方式来传递个数可变的实参。

可与同类中同名不同形参的方法之间构成重载,但是不能与同类中同名相同参数类型的数组构成重载。

可变形参在方法的形参中必须声明在末尾,且最多只能声明一个可变形参。

传入参数个数可以是0、1、2…个。

public static void show(String ... strs){
     ...   
     //传入参数个数:strs.length(当作数组处理)
     //取值:strs[i]    
}
调用:
//show("hello");
//show("hello","world");
//show();
public static void show(int i, String ... strs){
     ...   
     //传入参数个数:strs.length(当作数组处理)
     //取值:strs[i]
}
调用:
//show(1,"hello");
//show(1,"hello","world");
//show(1);

值传递

Java中方法的参数传递方式只有一种:值传递。即,传入的是实参值的副本,实参本身不受影响。

基本数据类型传递:传递其“数值”;引用数据类型传递:传递其“地址”。


递归

一个方法体内调用方法它自身。

递归一定要指定正确的递归出口,防止出现无穷递归,类似死循环。


封装与隐藏

隐藏对象内部的复杂性,之对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性,一定程度上满足如下“追求”。

程序设计追求——“高内聚,低耦合

  • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉。
  • 低耦合:进对外暴露少量的方法用于使用。

封装性的体现:

1.类属性的封装;

  • private修饰符修饰属性,使其私有化。

  • 类的set方法:即类属性的赋值操作,对类属性的数据类型和存储范围等进行制约。

  • 类的get方法:即类属性的获取操作。

2.不对外暴露的私有方法;

3.单例模型;


权限修饰符

封装性的体现需要权限修饰符进行配合。Java规定4种权限修饰符:public、缺省、protected、private。

可以用来修饰属性、方法、构造器、内部类。

修饰符类内部同一个包不同包的子类同一个工程
publicYesYesYesYes
protectedYesYesYes
缺省YesYes
privateYes

其中,对于class的权限修饰符只能是public或者缺省。


构造器

作用:1.创建对象;2.初始化对象的属性;

如果类中未定义构造器,则系统默认提供一个空参的构造器。但是要注意,一旦显示定义了类的构造器后,系统就不再提供默认的空参构造器,如仍需空参构造器,则必须自己编写。

一个类的构造器支持重载。

一个类中至少有一个构造器。


JavaBean

JavaBean是一种Java语言写成的可重用组件,对组装环境具有较强的适应能力。

所谓JavaBean,是指符合如下标准的Java类:

  • 类是公共的。
  • 有一个无参的公共构造器。
  • 有属性,且有对应的get、set方法。

用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。


UML类图

“#”->protected类型、"+"->public类型、"-"->private类型。

有下划线的方法是构造器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值