《数据结构与算法分析_java》系列(一)——引论

系列文章目录

(一)引论——为后续章节搭建一个学习平台


(二)算法分析——时间复杂度的分析法则及3个经典算法案例分析


(三)链表——ArrayList与LinkedList源码解析和应用场景以及手写实现LRU缓存淘汰算法


(四)队列——线程池中有限资源请求队列排队功能的实现原理及队列的手写实现


(五)栈——用户界面的前进跳转及回退机制如何实现及栈的手写实现


(六)Hash表——HashMap 的实现原理精讲及Hash思想在ThreadLocal与数据库索引中的应用


(七)Java容器结构总结


(八) 树——基本概念,以及huffman编码、二叉排序树、二叉平衡树的原理及手写实现


(九)散列和优先队列(堆)以及不相交集类


(十)图论(1)——拓扑排序、最短路径算法、网络流问题


(十 一)图论(2)——最小生成树、深度优先搜索的应用、NP-完全性介绍


(十二)算法设计技巧——贪婪算法、分治算法、动态规划算法、随机化算法和回溯算法


(十三)摊还分析——二项队列、斜堆、斐波那契堆、伸展树


(十四)高级数据结构及实现——自顶向下伸展树、红黑树、treap树、后缀数组与后缀树、k-d树、配对树


(十五)【面试】常用算法实战——排序算法、二分查找算法、kmp匹配算法、递归算法、大数据判存算法


(十六)【面试】B+树——MySql数据库索引是如何实现的


前言

在这一章,我们阐述本书的目的和目标并简要复习离散数学以及程序设计的一些概念。我们将要:

  • 看到程序对于合理的大量输入的运行性能与其在适量输入下运行性能的同等重要性。
  • 概括为本书其余部分所需要的基本的数学基础。
  • 简要复习递归。
  • 概括用于本书的Java语言的某些重要特点。

一、本书讨论的内容

在许多问题当中,一个重要的观念是:写岀一个工作程序并不够。如果这个程序在巨大的 数据集上运行,那么运行时间就变成了重要的问题。我们将在本书看到对于大量的输入如何估计程序的运行时间,尤其是如何在尚未具体编码的情况下比较两个程序的运行时间。我们还将看到彻底改进程序速度以及确定程序瓶颈的方法。这些方法将使我们能够发现需要我们集中精力努力优化的那些代码段。

二、数学知识复习

1、指数

在这里插入图片描述

2、对数

PS:在计算机科学中,除非有特别的声明,否则所有的对数都是以2为底的。

定义 1.1 X A = B , 当 且 仅 当 l o g x B = A { \quad X^A=B ,当且仅当log_xB=A} XA=BlogxB=A

由该定义可以得到几个方便的等式。

定理 1.1
l o g A B = l o g c B l o g c A ;A,B,C>0; A ≠ 1 log_AB={\frac{log_cB}{log_cA} \text {;A,B,C>0;}A \neq 1} logAB=logcAlogcBABC>0A=1
证明:
\quad\quad x = l o g c B x =log_cB x=logcB y = l o g c A y =log_cA y=logcA z = l o g A B z = log_AB z=logAB,则 B = c x B=c^x B=cx A = c y A= c^y A=cy B = A z B= A^z B=Az
   ⟹    B = c x = ( c y ) z = c y z \quad\quad \implies \quad B={c^x}={(c^y)^z}={c^{yz}} B=cx=(cy)z=cyz
   ⟹    x = y z \quad\quad \implies \quad x=yz x=yz
\quad\quad 即, l o g A B = l o g c B l o g c A log_AB=\frac{log_cB}{log_cA} logAB=logcAlogcB


定理 1.2
l o g A B = l o g A + l o g B ;A,B>0 logAB={logA+logB} \text {;A,B>0} logAB=logA+logBAB>0


定理 1.3
l o g A B = l o g A − l o g B ;A,B>0 log\frac{A}{B}={logA-logB} \text {;A,B>0} logBA=logAlogBAB>0


定理 1.4
l o g A B = B l o g A ;A,B>0 logA^B=BlogA \text {;A,B>0} logAB=BlogAAB>0


定理 1.5
l o g X < X  对所有X>0成立 logX<X \text { 对所有X>0成立} logX<X 对所有X>0成立


3、级数

最容易记忆的公式
∑ i = 0 N 2 i = 2 N + 1 − 1 (1) \bf \sum_{i=0}^N 2^i=2^{N+1}-1 \tag{1} i=0N2i=2N+11(1)


∑ i = 0 N A i = A N + 1 − 1 A − 1 (2) \bf \sum_{i=0}^N A^i=\frac{A^{N+1}-1}{A-1} \tag{2} i=0NAi=A1AN+11(2)

下面通过错位相减法来证明 (1) 式

证明:
\qquad S = ∑ i = 0 N 2 i = 1 + 2 + 2 2 + 2 3 + ⋯ + 2 N (a) S =\sum_{i=0}^N 2^i=1+2+2^2+2^3+\cdots+2^N \tag{a} S=i=0N2i=1+2+22+23++2N(a)
\qquad
2 S = 2 ∑ i = 0 N 2 i = 2 + 2 2 + 2 3 + ⋯ + 2 N + 2 N + 1 (b) 2S =2\sum_{i=0}^N 2^i=2+2^2+2^3+\cdots+2^N+2^{N+1} \tag{b} 2S=2i=0N2i=2+22+23++2N+2N+1(b)
\qquad 由(b)-(a)得
S = ∑ i = 0 N 2 i = 2 N + 1 − 1 S =\sum_{i=0}^N 2^i=2^{N+1}-1 S=i=0N2i=2N+11


在这里插入图片描述

4、模运算

在这里插入图片描述

5、证明的方法

5.1 归纳法证明

Created with Raphaël 2.2.0 开始 证明基准情况 成立? 假设任意k项成立 证明k+1项成立 成立? 得证 结束 不得证 yes no yes no

5.2 反证法证明

\qquad 举个反例就OK


三、递归简论

编写递归程序的4个基本法则:

  1. 基准情形——无需递归就能求解
  2. 不断推进——每次递归调用都要朝向基准情形推进
  3. 设计法则——假设所有递归调用都能运行,无需关注簿记管理的细节
  4. 合成效益法则——切勿在不同的递归调用中做重复性的工作

第四条法则(连同它的名称一起)将在后面的章节证明是合理的。使用递归计算诸如斐波 那契数之类简单数学函数的值的想法一般来说不是一个好主意,其道理正是根据第四条法则。只要在头脑中记住这些法则,递归程序设计就应该是简单明了的


四、利用Java 5泛型特性实现泛型构件

1、泛型类和接口

/**
 * @author java6b
 * @date 2020-8-28
 * @deprecated  泛型在接口中的使用
 */
public interface Comparable<AnyType> {//声明一个泛型接口
    /**
     * 声明一个泛型方法——使用泛型类型作为方法参数
     * @param other
     * @return int
     */
    public  int compareTo( AnyType other );

    /**
     * 泛型方法——使用泛型类型作为返回类型
     * @return AnyType
     */
    public AnyType wuzl6b();
}
/**
 * 泛型在类中的使用
 */
public class GenericMemoryCell<AnyType>//声明一个泛型类
{ 
    private AnyType storedValue;//指定泛型类型的作用域——私有
    public AnyType read() {//泛型方法——使用泛型类型作为返回类型
        return storedValue;
    }
    public void write( AnyType x ) {//泛型方法——使用泛型类型作为方法参数
        storedValue = x;
    }
    
    //泛型方法——通配符
    public static double total_Area( Collection<? extends Shape> arr ) {
        double total = 0;
        for( Shape s : arr ){
            if( s != null ){
                total += s.area();
            }
        }
        return total;
    }
    
    //泛型static方法
    public static <AnyType> boolean contains( AnyType [ ] arr, AnyType x ){
        for( AnyType val : arr ) {
            if (x.equals(val)) {
                return true;
            }
        }
        return false;
    }

    //泛型方法的类型限界
    public static <AnyType extends Comparable<? super AnyType>>
        AnyType findMax( AnyType [ ] arr )
    {
        int maxindex = 0;
        for( int i = 1; i < arr.length; i++ ) {
            if (arr[i].compareTo(arr[maxindex]) > 0 ){
                maxindex = i;
            }
        }
        return arr[ maxindex ];
    }

    //自动装箱/拆箱
    public void boxing(){
        GenericMemoryCell<Integer> m1 = new GenericMemoryCell<Integer>();
        GenericMemoryCell<Integer> m2 = new GenericMemoryCell<>();//使用Java7中的菱形运算符
        m1.write(37);//自动装箱
        int val1 = m1.read(); //自动拆箱
    }
}

\qquad
2、类型擦除
\qquad
在这里插入图片描述

\qquad
3、对于泛型的限制
\qquad

  • 基本类型不能用做泛型的类型参数

  • instanceof检测和类型转换工作只对原始类型进行

  • static的语境
    \quad 1、在一个泛型类中,static方法和static域均不可引用类的类型变量,因为在类型擦除后类型变量就不存在了。
    \quad 2、由于实际上只存在一个原始的类,因此static域在该类的诸泛型实例之间是共享的。

  • 不能创建一个泛型类型的实例,也不能创建一个泛型的数组

  • 参数化类型的数组的实例化是非法的
    \qquad 在这里插入图片描述
    \qquad 正常情况下,我们认为第4行的赋值会生成一个ArrayStoreException,因为赋值的类型有错 误。可是,在类型擦除之后,数组的类型为GenericMemoryCell[],而加到数组中的对象也是 GenericMemoryCell,因此不存在ArrayStoreException异常。于是,该段代码没有类型转换,它最终将在第5行产生一个ClassCastException异常,这正是泛型应该避免的情况。


五、函数对象

\qquad 一个函数通过将其 放在一个对象内部而被传递。这样的对象通常叫作函数对象(funtion object) 。


总结

本章为该系列的其余部分创建一个平台。面对大量的输入,一种算法所花费的时间将是评判决策好坏的重要标准(当然,正确性是最重要的)。速度是相对的。对于一个问题在一台机器上速度是快的,有可能对另外一个问题或在一台不同的机器上就变成速度是慢的。我们将从下一 章开始处理这些问题,并且要用到本章讨论过的数学来建立一个正式的模型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值