diff --git a/Algorithm/单源最短路问题.md b/Algorithm/单源最短路问题.md new file mode 100644 index 00000000..7ffcf5bb --- /dev/null +++ b/Algorithm/单源最短路问题.md @@ -0,0 +1,22 @@ +# 单元最短路问题 + +> 通过不同的方式解决单元最短路问题 + +> 图,不是树 +## 0 问题描述 + +单元最短路问题、有向无环图 + +## 1 暴力求解 + +### 深度优先搜索DFS + +### 广度优先搜索BFS + +## 2 回溯法 + +深度优先算法,每次回溯的时候进行剪枝操作。 +如果此分支没有希望比已经保存的最短路更优。 + +而且可以从不同的点到达同一个点。保留之前到达这个点的状态,如果最新到达这个点的距离小于之前的距离,则继续向下走,如果大于则放弃并回溯。 + diff --git a/README.md b/README.md index 05caa00e..e83a70fb 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ > 关于笔记记录的说明:我觉得笔记记录的内容过于细节。所有的知识应该以书上为准。整理笔记的目的应该是作为一种快速参考或者索引,而不是详细的记录所有的细节。说实话,我觉得你的笔记废话太多,自己都不一定会看。 > 我觉得是时间放弃你愚蠢的笔记策略了。 > 从今以后,必须跟上自己的笔记进度和作业进度。不能就学两科还跟不上进度,太傻逼了。 +> 殷康龙啊,上课时间才是最重要的,记得做笔记啊,啥时候,你成了一个上课不听,下课做作的人???没用的。以后自己去坐到前排学习吧,这种事,确实有利。能强迫自己认真听讲。 ## 1 分类标题(用来描述主题的各个方面或者分类) diff --git a/Scala/1 基本语法.md b/Scala/1 基本语法.md new file mode 100644 index 00000000..144f4f8d --- /dev/null +++ b/Scala/1 基本语法.md @@ -0,0 +1,127 @@ +# 基本语法 + +## 1 相关概念 + +对象:对象有属性和行为。例如:一只狗的状属性有:颜色,名字,行为有:叫、跑、吃等。对象是一个类的实例。 + +类:类是对象的抽象,而对象是类的具体实例。 + +方法:方法描述的基本的行为,一个类可以包含多个方法。 + +属性:每个对象都有它唯一的实例变量集合。对象的属性通过给字段赋值来创建。 + +## 2 基本语法 + +### 特点 + +区分大小写 - Scala是大小写敏感的,这意味着标识Hello 和 hello在Scala中会有不同的含义。 + +类名 - 对于所有的类名的第一个字母要大写。 +如果需要使用几个单词来构成一个类的名称,每个单词的第一个字母要大写。 + +示例:class MyFirstScalaClass + +方法名称 - 所有的方法名称的第一个字母用小写。 +如果若干单词被用于构成方法的名称,则每个单词的第一个字母应大写。 + +示例:def myMethodName() + +程序文件名 - 程序文件的名称应该与对象名称完全匹配(新版本不需要了,但建议保留这种习惯)。 +保存文件时,应该保存它使用的对象名称(记住Scala是区分大小写),并追加".scala"为文件扩展名。 (如果文件名和对象名称不匹配,程序将无法编译)。 + +示例: 假设"HelloWorld"是对象的名称。那么该文件应保存为'HelloWorld.scala" + +def main(args: Array[String]) - Scala程序从main()方法开始处理,这是每一个Scala程序的强制程序入口部分。 + +### 标识符 +Scala 可以使用两种形式的标志符,字符数字和符号。 + +字符数字使用字母或是下划线开头,后面可以接字母或是数字,符号"$"在 Scala 中也看作为字母。然而以"$"开头的标识符为保留的 Scala 编译器产生的标志符使用,应用程序应该避免使用"$"开始的标识符,以免造成冲突。 + +Scala 的命名规则采用和 Java 类似的 camel 命名规则,首字符小写,比如 toString。类名的首字符还是使用大写。此外也应该避免使用以下划线结尾的标志符以避免冲突。符号标志符包含一个或多个符号,如+,:,? 等,比如: + ++ ++ ::: < ?> :-> +Scala 内部实现时会使用转义的标志符,比如:-> 使用 $colon$minus$greater 来表示这个符号。因此如果你需要在 Java 代码中访问:->方法,你需要使用 Scala 的内部名称 $colon$minus$greater。 + +混合标志符由字符数字标志符后面跟着一个或多个符号组成,比如 unary_+ 为 Scala 对+方法的内部实现时的名称。字面量标志符为使用"定义的字符串,比如 `x` `yield`。 + +你可以在"之间使用任何有效的 Scala 标志符,Scala 将它们解释为一个 Scala 标志符,一个典型的使用为 Thread 的 yield 方法, 在 Scala 中你不能使用 Thread.yield()是因为 yield 为 Scala 中的关键字, 你必须使用 Thread.`yield`()来使用这个方法。 + +### Scala 关键字 +下表列出了 scala 保留关键字,我们不能使用以下关键字作为变量: + +abstract case catch class +def do else extends +false final finally for +forSome if implicit import +lazy match new null +object override package private +protected return sealed super +this throw trait try +true type val var +while with yield +- : = => +<- <: <% >: +# @ + +### Scala 注释 +Scala 类似 Java 支持单行和多行注释。多行注释可以嵌套,但必须正确嵌套,一个注释开始符号对应一个结束符号。注释在 Scala 编译中会被忽略,实例如下: + +object HelloWorld { + /* 这是一个 Scala 程序 + * 这是一行注释 + * 这里演示了多行注释 + */ + def main(args: Array[String]) { + // 输出 Hello World + // 这是一个单行注释 + println("Hello, world!") + } +} + +### 空行和空格换行符 + +一行中只有空格或者带有注释,Scala 会认为其是空行,会忽略它。标记可以被空格或者注释来分割。 + +Scala是面向行的语言,语句可以用分号(;)结束或换行符。Scala 程序里,语句末尾的分号通常是可选的。如果你愿意可以输入一个,但若一行里仅 有一个语句也可不写。另一方面,如果一行里写多个语句那么分号是需要的。例如 + +val s = "菜鸟教程"; println(s) + +## 3 包 + +### Scala 包 +定义包 +Scala 使用 package 关键字定义包,在Scala将代码定义到某个包中有两种方式: + +第一种方法和 Java 一样,在文件的头定义包名,这种方法就后续所有代码都放在该包中。 比如: + +package com.runoob +class HelloWorld +第二种方法有些类似 C#,如: + +package com.runoob { + class HelloWorld +} +第二种方法,可以在一个文件中定义多个包。 + +### 引用 +Scala 使用 import 关键字引用包。 + +import java.awt.Color // 引入Color + +import java.awt._ // 引入包内所有成员 + +def handler(evt: event.ActionEvent) { // java.awt.event.ActionEvent + ... // 因为引入了java.awt,所以可以省去前面的部分 +} +import语句可以出现在任何地方,而不是只能在文件顶部。import的效果从开始延伸到语句块的结束。这可以大幅减少名称冲突的可能性。 + +如果想要引入包中的几个成员,可以使用selector(选取器): + +import java.awt.{Color, Font} + +// 重命名成员 +import java.util.{HashMap => JavaHashMap} + +// 隐藏成员 +import java.util.{HashMap => _, _} // 引入了util包的所有成员,但是HashMap被隐藏了 \ No newline at end of file diff --git a/Scala/10 数组.md b/Scala/10 数组.md new file mode 100644 index 00000000..4759a436 --- /dev/null +++ b/Scala/10 数组.md @@ -0,0 +1,202 @@ +# Scala数组 + + +## 1 基本操作 +### 声明数组 +以下是 Scala 数组声明的语法格式: + +var z:Array[String] = new Array[String](3) + +或 + +var z = new Array[String](3) + +### 处理数组 +数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本的 for 循环。 + +以下实例演示了数组的创建,初始化等处理过程: + +object Test { + def main(args: Array[String]) { + var myList = Array(1.9, 2.9, 3.4, 3.5) + + // 输出所有数组元素 + for ( x <- myList ) { + println( x ) + } + + // 计算数组所有元素的总和 + var total = 0.0; + for ( i <- 0 to (myList.length - 1)) { + total += myList(i); + } + println("总和为 " + total); + + // 查找数组中的最大元素 + var max = myList(0); + for ( i <- 1 to (myList.length - 1) ) { + if (myList(i) > max) max = myList(i); + } + println("最大值为 " + max); + + } +} + +### 多维数组 +多维数组一个数组中的值可以是另一个数组,另一个数组的值也可以是一个数组。矩阵与表格是我们常见的二维数组。 + +以上是一个定义了二维数组的实例: + +var myMatrix = ofDim[Int](3,3) +实例中数组中包含三个数组元素,每个数组元素又含有三个值。 + +接下来我们来看一个二维数组处理的完整实例: + +import Array._ + +object Test { + def main(args: Array[String]) { + var myMatrix = ofDim[Int](3,3) + + // 创建矩阵 + for (i <- 0 to 2) { + for ( j <- 0 to 2) { + myMatrix(i)(j) = j; + } + } + + // 打印二维阵列 + for (i <- 0 to 2) { + for ( j <- 0 to 2) { + print(" " + myMatrix(i)(j)); + } + println(); + } + + } +} + +### 合并数组 +以下实例中,我们使用 concat() 方法来合并两个数组,concat() 方法中接受多个数组参数: + +import Array._ + +object Test { + def main(args: Array[String]) { + var myList1 = Array(1.9, 2.9, 3.4, 3.5) + var myList2 = Array(8.9, 7.9, 0.4, 1.5) + + var myList3 = concat( myList1, myList2) + + // 输出所有数组元素 + for ( x <- myList3 ) { + println( x ) + } + } +} + + +### 创建区间数组 +以下实例中,我们使用了 range() 方法来生成一个区间范围内的数组。range() 方法最后一个参数为步长,默认为 1: + +import Array._ + +object Test { + def main(args: Array[String]) { + var myList1 = range(10, 20, 2) + var myList2 = range(10,20) + + // 输出所有数组元素 + for ( x <- myList1 ) { + print( " " + x ) + } + println() + for ( x <- myList2 ) { + print( " " + x ) + } + } +} + +## 数组函数 + +Scala 数组方法 +下表中为 Scala 语言中处理数组的重要方法,使用它前我们需要使用 import Array._ 引入包。 + +序号 方法和描述 +1 +def apply( x: T, xs: T* ): Array[T] + +创建指定对象 T 的数组, T 的值可以是 Unit, Double, Float, Long, Int, Char, Short, Byte, Boolean。 + +2 +def concat[T]( xss: Array[T]* ): Array[T] + +合并数组 + +3 +def copy( src: AnyRef, srcPos: Int, dest: AnyRef, destPos: Int, length: Int ): Unit + +复制一个数组到另一个数组上。相等于 Java's System.arraycopy(src, srcPos, dest, destPos, length)。 + +4 +def empty[T]: Array[T] + +返回长度为 0 的数组 + +5 +def iterate[T]( start: T, len: Int )( f: (T) => T ): Array[T] + +返回指定长度数组,每个数组元素为指定函数的返回值。 + +以上实例数组初始值为 0,长度为 3,计算函数为a=>a+1: + +scala> Array.iterate(0,3)(a=>a+1) +res1: Array[Int] = Array(0, 1, 2) +6 +def fill[T]( n: Int )(elem: => T): Array[T] + +返回数组,长度为第一个参数指定,同时每个元素使用第二个参数进行填充。 + +7 +def fill[T]( n1: Int, n2: Int )( elem: => T ): Array[Array[T]] + +返回二数组,长度为第一个参数指定,同时每个元素使用第二个参数进行填充。 + +8 +def ofDim[T]( n1: Int ): Array[T] + +创建指定长度的数组 + +9 +def ofDim[T]( n1: Int, n2: Int ): Array[Array[T]] + +创建二维数组 + +10 +def ofDim[T]( n1: Int, n2: Int, n3: Int ): Array[Array[Array[T]]] + +创建三维数组 + +11 +def range( start: Int, end: Int, step: Int ): Array[Int] + +创建指定区间内的数组,step 为每个元素间的步长 + +12 +def range( start: Int, end: Int ): Array[Int] + +创建指定区间内的数组 + +13 +def tabulate[T]( n: Int )(f: (Int)=> T): Array[T] + +返回指定长度数组,每个数组元素为指定函数的返回值,默认从 0 开始。 + +以上实例返回 3 个元素: + +scala> Array.tabulate(3)(a => a + 5) +res0: Array[Int] = Array(5, 6, 7) +14 +def tabulate[T]( n1: Int, n2: Int )( f: (Int, Int ) => T): Array[Array[T]] + +返回指定长度的二维数组,每个数组元素为指定函数的返回值,默认从 0 开始。 \ No newline at end of file diff --git a/Scala/11 容器.md b/Scala/11 容器.md new file mode 100644 index 00000000..625e607d --- /dev/null +++ b/Scala/11 容器.md @@ -0,0 +1,1175 @@ +# Scala Collection + +## 1 容器概述 +Scala提供了一套很好的集合实现,提供了一些集合类型的抽象。 + +Scala 集合分为可变的和不可变的集合。 + +可变集合可以在适当的地方被更新或扩展。这意味着你可以修改,添加,移除一个集合的元素。 + +而不可变集合类,相比之下,永远不会改变。不过,你仍然可以模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变。 + +接下来我们将为大家介绍几种常用集合类型的应用: + +序号 集合及描述 +1 Scala List(列表) +List的特征是其元素以线性方式存储,集合中可以存放重复对象。 + +参考 API文档 + +2 Scala Set(集合) +Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。 + +参考 API文档 + +3 Scala Map(映射) +Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。 + +参考 API文档 + +4 Scala 元组 +元组是不同类型的值的集合 + +5 Scala Option +Option[T] 表示有可能包含值的容器,也可能不包含值。 + +6 Scala Iterator(迭代器) +迭代器不是一个容器,更确切的说是逐一访问容器内元素的方法。 + +实例 +以下代码判断,演示了所有以上集合类型的定义实例: + +// 定义整型 List +val x = List(1,2,3,4) + +// 定义 Set +val x = Set(1,3,5,7) + +// 定义 Map +val x = Map("one" -> 1, "two" -> 2, "three" -> 3) + +// 创建两个不同类型元素的元组 +val x = (10, "Runoob") + +// 定义 Option +val x:Option[Int] = Some(5) + + +## 1 列表 + + +### 列表定义 +Scala 列表类似于数组,它们所有元素的类型都相同,但是它们也有所不同:列表是不可变的,值一旦被定义了就不能改变,其次列表 具有递归的结构(也就是链接表结构)而数组不是。。 + +列表的元素类型 T 可以写成 List[T]。例如,以下列出了多种类型的列表: + +// 字符串列表 +val site: List[String] = List("Runoob", "Google", "Baidu") + +// 整型列表 +val nums: List[Int] = List(1, 2, 3, 4) + +// 空列表 +val empty: List[Nothing] = List() + +// 二维列表 +val dim: List[List[Int]] = + List( + List(1, 0, 0), + List(0, 1, 0), + List(0, 0, 1) + ) +构造列表的两个基本单位是 Nil 和 :: + +Nil 也可以表示为一个空列表。 + +以上实例我们可以写成如下所示: + +// 字符串列表 +val site = "Runoob" :: ("Google" :: ("Baidu" :: Nil)) + +// 整型列表 +val nums = 1 :: (2 :: (3 :: (4 :: Nil))) + +// 空列表 +val empty = Nil + +// 二维列表 +val dim = (1 :: (0 :: (0 :: Nil))) :: + (0 :: (1 :: (0 :: Nil))) :: + (0 :: (0 :: (1 :: Nil))) :: Nil + +### 列表操作 + +Scala列表有三个基本操作: + +head 返回列表第一个元素 +tail 返回一个列表,包含除了第一元素之外的其他元素 +isEmpty 在列表为空时返回true +对于Scala列表的任何操作都可以使用这三个基本操作来表达。实例如下: + +object Test { + def main(args: Array[String]) { + val site = "Runoob" :: ("Google" :: ("Baidu" :: Nil)) + val nums = Nil + + println( "第一网站是 : " + site.head ) + println( "最后一个网站是 : " + site.tail ) + println( "查看列表 site 是否为空 : " + site.isEmpty ) + println( "查看 nums 是否为空 : " + nums.isEmpty ) + } +} + +### 连接列表 + +连接列表 +你可以使用 ::: 运算符或 List.:::() 方法或 List.concat() 方法来连接两个或多个列表。实例如下: + +object Test { + def main(args: Array[String]) { + val site1 = "Runoob" :: ("Google" :: ("Baidu" :: Nil)) + val site2 = "Facebook" :: ("Taobao" :: Nil) + + // 使用 ::: 运算符 + var fruit = site1 ::: site2 + println( "site1 ::: site2 : " + fruit ) + + // 使用 List.:::() 方法 + fruit = site1.:::(site2) + println( "site1.:::(site2) : " + fruit ) + + // 使用 concat 方法 + fruit = List.concat(site1, site2) + println( "List.concat(site1, site2) : " + fruit ) + + + } +} + +### List.fill() +我们可以使用 List.fill() 方法来创建一个指定重复数量的元素列表: + +object Test { + def main(args: Array[String]) { + val site = List.fill(3)("Runoob") // 重复 Runoob 3次 + println( "site : " + site ) + + val num = List.fill(10)(2) // 重复元素 2, 10 次 + println( "num : " + num ) + } +} + +### List.tabulate() +List.tabulate() 方法是通过给定的函数来创建列表。 + +方法的第一个参数为元素的数量,可以是二维的,第二个参数为指定的函数,我们通过指定的函数计算结果并返回值插入到列表中,起始值为 0,实例如下: +object Test { + def main(args: Array[String]) { + // 通过给定的函数创建 5 个元素 + val squares = List.tabulate(6)(n => n * n) + println( "一维 : " + squares ) + + // 创建二维列表 + val mul = List.tabulate( 4,5 )( _ * _ ) + println( "多维 : " + mul ) + } +} + +###List.reverse +List.reverse 用于将列表的顺序反转,实例如下: + +object Test { + def main(args: Array[String]) { + val site = "Runoob" :: ("Google" :: ("Baidu" :: Nil)) + println( "site 反转前 : " + site ) + + println( "site 反转后 : " + site.reverse ) + } +} +下表列出了 Scala List 常用的方法: + +序号 方法及描述 +1 +def +:(elem: A): List[A] + +为列表预添加元素 + +scala> val x = List(1) +x: List[Int] = List(1) + +scala> val y = 2 +: x +y: List[Int] = List(2, 1) + +scala> println(x) +List(1) +2 +def ::(x: A): List[A] + +在列表开头添加元素 + +3 +def :::(prefix: List[A]): List[A] + +在列表开头添加指定列表的元素 + +4 +def :+(elem: A): List[A] + +复制添加元素后列表。 + +scala> val a = List(1) +a: List[Int] = List(1) + +scala> val b = a :+ 2 +b: List[Int] = List(1, 2) + +scala> println(a) +List(1) +5 +def addString(b: StringBuilder): StringBuilder + +将列表的所有元素添加到 StringBuilder + +6 +def addString(b: StringBuilder, sep: String): StringBuilder + +将列表的所有元素添加到 StringBuilder,并指定分隔符 + +7 +def apply(n: Int): A + +通过列表索引获取元素 + +8 +def contains(elem: Any): Boolean + +检测列表中是否包含指定的元素 + +9 +def copyToArray(xs: Array[A], start: Int, len: Int): Unit + +将列表的元素复制到数组中。 + +10 +def distinct: List[A] + +去除列表的重复元素,并返回新列表 + +11 +def drop(n: Int): List[A] + +丢弃前n个元素,并返回新列表 + +12 +def dropRight(n: Int): List[A] + +丢弃最后n个元素,并返回新列表 + +13 +def dropWhile(p: (A) => Boolean): List[A] + +从左向右丢弃元素,直到条件p不成立 + +14 +def endsWith[B](that: Seq[B]): Boolean + +检测列表是否以指定序列结尾 + +15 +def equals(that: Any): Boolean + +判断是否相等 + +16 +def exists(p: (A) => Boolean): Boolean + +判断列表中指定条件的元素是否存在。 + +判断l是否存在某个元素: + +scala> l.exists(s => s == "Hah") +res7: Boolean = true +17 +def filter(p: (A) => Boolean): List[A] + +输出符号指定条件的所有元素。 + +过滤出长度为3的元素: + +scala> l.filter(s => s.length == 3) +res8: List[String] = List(Hah, WOW) +18 +def forall(p: (A) => Boolean): Boolean + +检测所有元素。 + +例如:判断所有元素是否以"H"开头: + +scala> l.forall(s => s.startsWith("H")) res10: Boolean = false +19 +def foreach(f: (A) => Unit): Unit + +将函数应用到列表的所有元素 + +20 +def head: A + +获取列表的第一个元素 + +21 +def indexOf(elem: A, from: Int): Int + +从指定位置 from 开始查找元素第一次出现的位置 + +22 +def init: List[A] + +返回所有元素,除了最后一个 + +23 +def intersect(that: Seq[A]): List[A] + +计算多个集合的交集 + +24 +def isEmpty: Boolean + +检测列表是否为空 + +25 +def iterator: Iterator[A] + +创建一个新的迭代器来迭代元素 + +26 +def last: A + +返回最后一个元素 + +27 +def lastIndexOf(elem: A, end: Int): Int + +在指定的位置 end 开始查找元素最后出现的位置 + +28 +def length: Int + +返回列表长度 + +29 +def map[B](f: (A) => B): List[B] + +通过给定的方法将所有元素重新计算 + +30 +def max: A + +查找最大元素 + +31 +def min: A + +查找最小元素 + +32 +def mkString: String + +列表所有元素作为字符串显示 + +33 +def mkString(sep: String): String + +使用分隔符将列表所有元素作为字符串显示 + +34 +def reverse: List[A] + +列表反转 + +35 +def sorted[B >: A]: List[A] + +列表排序 + +36 +def startsWith[B](that: Seq[B], offset: Int): Boolean + +检测列表在指定位置是否包含指定序列 + +37 +def sum: A + +计算集合元素之和 + +38 +def tail: List[A] + +返回所有元素,除了第一个 + +39 +def take(n: Int): List[A] + +提取列表的前n个元素 + +40 +def takeRight(n: Int): List[A] + +提取列表的后n个元素 + +41 +def toArray: Array[A] + +列表转换为数组 + +42 +def toBuffer[B >: A]: Buffer[B] + +返回缓冲区,包含了列表的所有元素 + +43 +def toMap[T, U]: Map[T, U] + +List 转换为 Map + +44 +def toSeq: Seq[A] + +List 转换为 Seq + +45 +def toSet[B >: A]: Set[B] + +List 转换为 Set + +46 +def toString(): String + +列表转换为字符串 + + +## 2 Set集合 + +## 3 Map映射 + +### 基本概念 +Map(映射)是一种可迭代的键值对(key/value)结构。 + +所有的值都可以通过键来获取。 + +Map 中的键都是唯一的。 + +Map 也叫哈希表(Hash tables)。 + +Map 有两种类型,可变与不可变,区别在于可变对象可以修改它,而不可变对象不可以。 + +默认情况下 Scala 使用不可变 Map。如果你需要使用可变集合,你需要显式的引入 import scala.collection.mutable.Map 类 + +在 Scala 中 你可以同时使用可变与不可变 Map,不可变的直接使用 Map,可变的使用 mutable.Map。以下实例演示了不可变 Map 的应用: + +// 空哈希表,键为字符串,值为整型 +var A:Map[Char,Int] = Map() + +// Map 键值对演示 +val colors = Map("red" -> "#FF0000", "azure" -> "#F0FFFF") +定义 Map 时,需要为键值对定义类型。如果需要添加 key-value 对,可以使用 + 号,如下所示: + +A += ('I' -> 1) +A += ('J' -> 5) +A += ('K' -> 10) +A += ('L' -> 100) + +### Map 基本操作 +Scala Map 有三个基本操作: + +方法 描述 +keys 返回 Map 所有的键(key) +values 返回 Map 所有的值(value) +isEmpty 在 Map 为空时返回true +实例 +以下实例演示了以上三个方法的基本应用: + +object Test { + def main(args: Array[String]) { + val colors = Map("red" -> "#FF0000", + "azure" -> "#F0FFFF", + "peru" -> "#CD853F") + + val nums: Map[Int, Int] = Map() + + println( "colors 中的键为 : " + colors.keys ) + println( "colors 中的值为 : " + colors.values ) + println( "检测 colors 是否为空 : " + colors.isEmpty ) + println( "检测 nums 是否为空 : " + nums.isEmpty ) + } +} +### Map 合并 +你可以使用 ++ 运算符或 Map.++() 方法来连接两个 Map,Map 合并时会移除重复的 key。以下演示了两个 Map 合并的实例: + +object Test { + def main(args: Array[String]) { + val colors1 = Map("red" -> "#FF0000", + "azure" -> "#F0FFFF", + "peru" -> "#CD853F") + val colors2 = Map("blue" -> "#0033FF", + "yellow" -> "#FFFF00", + "red" -> "#FF0000") + + // ++ 作为运算符 + var colors = colors1 ++ colors2 + println( "colors1 ++ colors2 : " + colors ) + + // ++ 作为方法 + colors = colors1.++(colors2) + println( "colors1.++(colors2) : " + colors ) + + } +} + +### 输出 Map 的 keys 和 values +以下通过 foreach 循环输出 Map 中的 keys 和 values: + +object Test { + def main(args: Array[String]) { + val sites = Map("runoob" -> "http://www.runoob.com", + "baidu" -> "http://www.baidu.com", + "taobao" -> "http://www.taobao.com") + + sites.keys.foreach{ i => + print( "Key = " + i ) + println(" Value = " + sites(i) )} + } +} + +### 查看 Map 中是否存在指定的 Key +你可以使用 Map.contains 方法来查看 Map 中是否存在指定的 Key。实例如下: + +object Test { + def main(args: Array[String]) { + val sites = Map("runoob" -> "http://www.runoob.com", + "baidu" -> "http://www.baidu.com", + "taobao" -> "http://www.taobao.com") + + if( sites.contains( "runoob" )){ + println("runoob 键存在,对应的值为 :" + sites("runoob")) + }else{ + println("runoob 键不存在") + } + if( sites.contains( "baidu" )){ + println("baidu 键存在,对应的值为 :" + sites("baidu")) + }else{ + println("baidu 键不存在") + } + if( sites.contains( "google" )){ + println("google 键存在,对应的值为 :" + sites("google")) + }else{ + println("google 键不存在") + } + } +} + +### 常用方法 +Scala Map 方法 +下表列出了 Scala Map 常用的方法: + +序号 方法及描述 +1 +def ++(xs: Map[(A, B)]): Map[A, B] + +返回一个新的 Map,新的 Map xs 组成 + +2 +def -(elem1: A, elem2: A, elems: A*): Map[A, B] + +返回一个新的 Map, 移除 key 为 elem1, elem2 或其他 elems。 + +3 +def --(xs: GTO[A]): Map[A, B] + +返回一个新的 Map, 移除 xs 对象中对应的 key + +4 +def get(key: A): Option[B] + +返回指定 key 的值 + +5 +def iterator: Iterator[(A, B)] + +创建新的迭代器,并输出 key/value 对 + +6 +def addString(b: StringBuilder): StringBuilder + +将 Map 中的所有元素附加到StringBuilder,可加入分隔符 + +7 +def addString(b: StringBuilder, sep: String): StringBuilder + +将 Map 中的所有元素附加到StringBuilder,可加入分隔符 + +8 +def apply(key: A): B + +返回指定键的值,如果不存在返回 Map 的默认方法 + +9 +def clear(): Unit + +清空 Map + +10 +def clone(): Map[A, B] + +从一个 Map 复制到另一个 Map + +11 +def contains(key: A): Boolean + +如果 Map 中存在指定 key,返回 true,否则返回 false。 + +12 +def copyToArray(xs: Array[(A, B)]): Unit + +复制集合到数组 + +13 +def count(p: ((A, B)) => Boolean): Int + +计算满足指定条件的集合元素数量 + +14 +def default(key: A): B + +定义 Map 的默认值,在 key 不存在时返回。 + +15 +def drop(n: Int): Map[A, B] + +返回丢弃前n个元素新集合 + +16 +def dropRight(n: Int): Map[A, B] + +返回丢弃最后n个元素新集合 + +17 +def dropWhile(p: ((A, B)) => Boolean): Map[A, B] + +从左向右丢弃元素,直到条件p不成立 + +18 +def empty: Map[A, B] + +返回相同类型的空 Map + +19 +def equals(that: Any): Boolean + +如果两个 Map 相等(key/value 均相等),返回true,否则返回false + +20 +def exists(p: ((A, B)) => Boolean): Boolean + +判断集合中指定条件的元素是否存在 + +21 +def filter(p: ((A, B))=> Boolean): Map[A, B] + +返回满足指定条件的所有集合 + +22 +def filterKeys(p: (A) => Boolean): Map[A, B] + +返回符合指定条件的不可变 Map + +23 +def find(p: ((A, B)) => Boolean): Option[(A, B)] + +查找集合中满足指定条件的第一个元素 + +24 +def foreach(f: ((A, B)) => Unit): Unit + +将函数应用到集合的所有元素 + +25 +def init: Map[A, B] + +返回所有元素,除了最后一个 + +26 +def isEmpty: Boolean + +检测 Map 是否为空 + +27 +def keys: Iterable[A] + +返回所有的key/p> + +28 +def last: (A, B) + +返回最后一个元素 + +29 +def max: (A, B) + +查找最大元素 + +30 +def min: (A, B) + +查找最小元素 + +31 +def mkString: String + +集合所有元素作为字符串显示 + +32 +def product: (A, B) + +返回集合中数字元素的积。 + +33 +def remove(key: A): Option[B] + +移除指定 key + +34 +def retain(p: (A, B) => Boolean): Map.this.type + +如果符合满足条件的返回 true + +35 +def size: Int + +返回 Map 元素的个数 + +36 +def sum: (A, B) + +返回集合中所有数字元素之和 + +37 +def tail: Map[A, B] + +返回一个集合中除了第一元素之外的其他元素 + +38 +def take(n: Int): Map[A, B] + +返回前 n 个元素 + +39 +def takeRight(n: Int): Map[A, B] + +返回后 n 个元素 + +40 +def takeWhile(p: ((A, B)) => Boolean): Map[A, B] + +返回满足指定条件的元素 + +41 +def toArray: Array[(A, B)] + +集合转数组 + +42 +def toBuffer[B >: A]: Buffer[B] + +返回缓冲区,包含了 Map 的所有元素 + +43 +def toList: List[A] + +返回 List,包含了 Map 的所有元素 + +44 +def toSeq: Seq[A] + +返回 Seq,包含了 Map 的所有元素 + +45 +def toSet: Set[A] + +返回 Set,包含了 Map 的所有元素 + +46 +def toString(): String + +返回字符串对象 + +## 4 元组 + +### 基本概念 + +与列表一样,元组也是不可变的,但与列表不同的是元组可以包含不同类型的元素。 + +元组的值是通过将单个的值包含在圆括号中构成的。例如: + +val t = (1, 3.14, "Fred") +以上实例在元组中定义了三个元素,对应的类型分别为[Int, Double, java.lang.String]。 + +此外我们也可以使用以下方式来定义: + +val t = new Tuple3(1, 3.14, "Fred") +元组的实际类型取决于它的元素的类型,比如 (99, "runoob") 是 Tuple2[Int, String]。 ('u', 'r', "the", 1, 4, "me") 为 Tuple6[Char, Char, String, Int, Int, String]。 + +目前 Scala 支持的元组最大长度为 22。对于更大长度你可以使用集合,或者扩展元组。 + +访问元组的元素可以通过数字索引,如下一个元组: + +val t = (4,3,2,1) +我们可以使用 t._1 访问第一个元素, t._2 访问第二个元素,如下所示: + +object Test { + def main(args: Array[String]) { + val t = (4,3,2,1) + + val sum = t._1 + t._2 + t._3 + t._4 + + println( "元素之和为: " + sum ) + } +} + +### 迭代元组 +你可以使用 Tuple.productIterator() 方法来迭代输出元组的所有元素: + +object Test { + def main(args: Array[String]) { + val t = (4,3,2,1) + + t.productIterator.foreach{ i =>println("Value = " + i )} + } +} + +### 元组转为字符串 +你可以使用 Tuple.toString() 方法将元组的所有元素组合成一个字符串,实例如下: + +object Test { + def main(args: Array[String]) { + val t = new Tuple3(1, "hello", Console) + + println("连接后的字符串为: " + t.toString() ) + } +} + +### 元素交换 +你可以使用 Tuple.swap 方法来交换元组的元素。如下实例: + +object Test { + def main(args: Array[String]) { + val t = new Tuple2("www.google.com", "www.runoob.com") + + println("交换后的元组: " + t.swap ) + } +} + +## 6 迭代器 + +Scala Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法。 + +迭代器 it 的两个基本操作是 next 和 hasNext。 + +调用 it.next() 会返回迭代器的下一个元素,并且更新迭代器的状态。 + +调用 it.hasNext() 用于检测集合中是否还有元素。 + +让迭代器 it 逐个返回所有元素最简单的方法是使用 while 循环: + +object Test { + def main(args: Array[String]) { + val it = Iterator("Baidu", "Google", "Runoob", "Taobao") + + while (it.hasNext){ + println(it.next()) + } + } +} + +### 查找最大与最小元素 +你可以使用 it.min 和 it.max 方法从迭代器中查找最大与最小元素,实例如下: + +object Test { + def main(args: Array[String]) { + val ita = Iterator(20,40,2,50,69, 90) + val itb = Iterator(20,40,2,50,69, 90) + + println("最大元素是:" + ita.max ) + println("最小元素是:" + itb.min ) + + } +} + +### 获取迭代器的长度 +你可以使用 it.size 或 it.length 方法来查看迭代器中的元素个数。实例如下: + +object Test { + def main(args: Array[String]) { + val ita = Iterator(20,40,2,50,69, 90) + val itb = Iterator(20,40,2,50,69, 90) + + println("ita.size 的值: " + ita.size ) + println("itb.length 的值: " + itb.length ) + + } +} + +### 常用方法 + +Scala Iterator 常用方法 +下表列出了 Scala Iterator 常用的方法: + +序号 方法及描述 +1 +def hasNext: Boolean + +如果还有可返回的元素,返回true。 + +2 +def next(): A + +返回迭代器的下一个元素,并且更新迭代器的状态 + +3 +def ++(that: => Iterator[A]): Iterator[A] + +合并两个迭代器 + +4 +def ++[B >: A](that :=> GenTraversableOnce[B]): Iterator[B] + +合并两个迭代器 + +5 +def addString(b: StringBuilder): StringBuilder + +添加一个字符串到 StringBuilder b + +6 +def addString(b: StringBuilder, sep: String): StringBuilder + +添加一个字符串到 StringBuilder b,并指定分隔符 + +7 +def buffered: BufferedIterator[A] + +迭代器都转换成 BufferedIterator + +8 +def contains(elem: Any): Boolean + +检测迭代器中是否包含指定元素 + +9 +def copyToArray(xs: Array[A], start: Int, len: Int): Unit + +将迭代器中选定的值传给数组 + +10 +def count(p: (A) => Boolean): Int + +返回迭代器元素中满足条件p的元素总数。 + +11 +def drop(n: Int): Iterator[A] + +返回丢弃前n个元素新集合 + +12 +def dropWhile(p: (A) => Boolean): Iterator[A] + +从左向右丢弃元素,直到条件p不成立 + +13 +def duplicate: (Iterator[A], Iterator[A]) + +生成两个能分别返回迭代器所有元素的迭代器。 + +14 +def exists(p: (A) => Boolean): Boolean + +返回一个布尔值,指明迭代器元素中是否存在满足p的元素。 + +15 +def filter(p: (A) => Boolean): Iterator[A] + +返回一个新迭代器 ,指向迭代器元素中所有满足条件p的元素。 + +16 +def filterNot(p: (A) => Boolean): Iterator[A] + +返回一个迭代器,指向迭代器元素中不满足条件p的元素。 + +17 +def find(p: (A) => Boolean): Option[A] + +返回第一个满足p的元素或None。注意:如果找到满足条件的元素,迭代器会被置于该元素之后;如果没有找到,会被置于终点。 + +18 +def flatMap[B](f: (A) => GenTraversableOnce[B]): Iterator[B] + +针对迭代器的序列中的每个元素应用函数f,并返回指向结果序列的迭代器。 + +19 +def forall(p: (A) => Boolean): Boolean + +返回一个布尔值,指明 it 所指元素是否都满足p。 + +20 +def foreach(f: (A) => Unit): Unit + +在迭代器返回的每个元素上执行指定的程序 f + +21 +def hasDefiniteSize: Boolean + +如果迭代器的元素个数有限则返回 true(默认等同于 isEmpty) + +22 +def indexOf(elem: B): Int + +返回迭代器的元素中index等于x的第一个元素。注意:迭代器会越过这个元素。 + +23 +def indexWhere(p: (A) => Boolean): Int + +返回迭代器的元素中下标满足条件p的元素。注意:迭代器会越过这个元素。 + +24 +def isEmpty: Boolean + +检查it是否为空, 为空返回 true,否则返回false(与hasNext相反)。 + +25 +def isTraversableAgain: Boolean + +Tests whether this Iterator can be repeatedly traversed. + +26 +def length: Int + +返回迭代器元素的数量。 + +27 +def map[B](f: (A) => B): Iterator[B] + +将 it 中的每个元素传入函数 f 后的结果生成新的迭代器。 + +28 +def max: A + +返回迭代器迭代器元素中最大的元素。 + +29 +def min: A + +返回迭代器迭代器元素中最小的元素。 + +30 +def mkString: String + +将迭代器所有元素转换成字符串。 + +31 +def mkString(sep: String): String + +将迭代器所有元素转换成字符串,并指定分隔符。 + +32 +def nonEmpty: Boolean + +检查容器中是否包含元素(相当于 hasNext)。 + +33 +def padTo(len: Int, elem: A): Iterator[A] + +首先返回迭代器所有元素,追加拷贝 elem 直到长度达到 len。 + +34 +def patch(from: Int, patchElems: Iterator[B], replaced: Int): Iterator[B] + +返回一个新迭代器,其中自第 from 个元素开始的 replaced 个元素被迭代器所指元素替换。 + +35 +def product: A + +返回迭代器所指数值型元素的积。 + +36 +def sameElements(that: Iterator[_]): Boolean + +判断迭代器和指定的迭代器参数是否依次返回相同元素 + +37 +def seq: Iterator[A] + +返回集合的系列视图 + +38 +def size: Int + +返回迭代器的元素数量 + +39 +def slice(from: Int, until: Int): Iterator[A] + +返回一个新的迭代器,指向迭代器所指向的序列中从开始于第 from 个元素、结束于第 until 个元素的片段。 + +40 +def sum: A + +返回迭代器所指数值型元素的和 + +41 +def take(n: Int): Iterator[A] + +返回前 n 个元素的新迭代器。 + +42 +def toArray: Array[A] + +将迭代器指向的所有元素归入数组并返回。 + +43 +def toBuffer: Buffer[B] + +将迭代器指向的所有元素拷贝至缓冲区 Buffer。 + +44 +def toIterable: Iterable[A] + +Returns an Iterable containing all elements of this traversable or iterator. This will not terminate for infinite iterators. + +45 +def toIterator: Iterator[A] + +把迭代器的所有元素归入一个Iterator容器并返回。 + +46 +def toList: List[A] + +把迭代器的所有元素归入列表并返回 + +47 +def toMap[T, U]: Map[T, U] + +将迭代器的所有键值对归入一个Map并返回。 + +48 +def toSeq: Seq[A] + +将代器的所有元素归入一个Seq容器并返回。 + +49 +def toString(): String + +将迭代器转换为字符串 + +50 +def zip[B](that: Iterator[B]): Iterator[(A, B) + +返回一个新迭代器,指向分别由迭代器和指定的迭代器 that 元素一一对应而成的二元组序列 \ No newline at end of file diff --git a/Scala/12 类和对象.md b/Scala/12 类和对象.md new file mode 100644 index 00000000..0a99f81c --- /dev/null +++ b/Scala/12 类和对象.md @@ -0,0 +1,242 @@ +# Scala 类和对象 + +## 1 基本概念 +类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。 + +我们可以使用 new 关键字来创建类的对象,实例如下: + +class Point(xc: Int, yc: Int) { + var x: Int = xc + var y: Int = yc + + def move(dx: Int, dy: Int) { + x = x + dx + y = y + dy + println ("x 的坐标点: " + x); + println ("y 的坐标点: " + y); + } +} +Scala中的类不声明为public,一个Scala源文件中可以有多个类。 + +以上实例的类定义了两个变量 x 和 y ,一个方法:move,方法没有返回值。 + +Scala 的类定义可以有参数,称为类参数,如上面的 xc, yc,类参数在整个类中都可以访问。 + +接着我们可以使用 new 来实例化类,并访问类中的方法和变量: + +import java.io._ + +class Point(xc: Int, yc: Int) { + var x: Int = xc + var y: Int = yc + + def move(dx: Int, dy: Int) { + x = x + dx + y = y + dy + println ("x 的坐标点: " + x); + println ("y 的坐标点: " + y); + } +} + +object Test { + def main(args: Array[String]) { + val pt = new Point(10, 20); + + // 移到一个新的位置 + pt.move(10, 10); + } +} + + +## 2 Scala 继承 +Scala继承一个基类跟Java很相似, 但我们需要注意以下几点: + +1、重写一个非抽象方法必须使用override修饰符。 +2、只有主构造函数才可以往基类的构造函数里写参数。 +3、在子类中重写超类的抽象方法时,你不需要使用override关键字。 +接下来让我们来看个实例: + +class Point(xc: Int, yc: Int) { + var x: Int = xc + var y: Int = yc + + def move(dx: Int, dy: Int) { + x = x + dx + y = y + dy + println ("x 的坐标点: " + x); + println ("y 的坐标点: " + y); + } +} + +class Location(override val xc: Int, override val yc: Int, + val zc :Int) extends Point(xc, yc){ + var z: Int = zc + + def move(dx: Int, dy: Int, dz: Int) { + x = x + dx + y = y + dy + z = z + dz + println ("x 的坐标点 : " + x); + println ("y 的坐标点 : " + y); + println ("z 的坐标点 : " + z); + } +} +Scala 使用 extends 关键字来继承一个类。实例中 Location 类继承了 Point 类。Point 称为父类(基类),Location 称为子类。 + +override val xc 为重写了父类的字段。 + +继承会继承父类的所有属性和方法,Scala 只允许继承一个父类。 + +实例如下: + +import java.io._ + +class Point(val xc: Int, val yc: Int) { + var x: Int = xc + var y: Int = yc + def move(dx: Int, dy: Int) { + x = x + dx + y = y + dy + println ("x 的坐标点 : " + x); + println ("y 的坐标点 : " + y); + } +} + +class Location(override val xc: Int, override val yc: Int, + val zc :Int) extends Point(xc, yc){ + var z: Int = zc + + def move(dx: Int, dy: Int, dz: Int) { + x = x + dx + y = y + dy + z = z + dz + println ("x 的坐标点 : " + x); + println ("y 的坐标点 : " + y); + println ("z 的坐标点 : " + z); + } +} + +object Test { + def main(args: Array[String]) { + val loc = new Location(10, 20, 15); + + // 移到一个新的位置 + loc.move(10, 10, 5); + } +} +执行以上代码,输出结果为: + +$ scalac Test.scala +$ scala Test +x 的坐标点 : 20 +y 的坐标点 : 30 +z 的坐标点 : 20 +Scala重写一个非抽象方法,必须用override修饰符。 + +class Person { + var name = "" + override def toString = getClass.getName + "[name=" + name + "]" +} + +class Employee extends Person { + var salary = 0.0 + override def toString = super.toString + "[salary=" + salary + "]" +} + +object Test extends App { + val fred = new Employee + fred.name = "Fred" + fred.salary = 50000 + println(fred) +} +执行以上代码,输出结果为: + +$ scalac Test.scala +$ scala Test +Employee[name=Fred][salary=50000.0] + + +## 3 Scala 单例对象 +在 Scala 中,是没有 static 这个东西的,但是它也为我们提供了单例模式的实现方法,那就是使用关键字 object。 + +Scala 中使用单例模式时,除了定义的类之外,还要定义一个同名的 object 对象,它和类的区别是,object对象不能带参数。 + +当单例对象与某个类共享同一个名称时,他被称作是这个类的伴生对象:companion object。你必须在同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类:companion class。类和它的伴生对象可以互相访问其私有成员。 + +单例对象实例 +import java.io._ + +class Point(val xc: Int, val yc: Int) { + var x: Int = xc + var y: Int = yc + def move(dx: Int, dy: Int) { + x = x + dx + y = y + dy + } +} + +object Test { + def main(args: Array[String]) { + val point = new Point(10, 20) + printPoint + + def printPoint{ + println ("x 的坐标点 : " + point.x); + println ("y 的坐标点 : " + point.y); + } + } +} +执行以上代码,输出结果为: + +$ scalac Test.scala +$ scala Test +x 的坐标点 : 10 +y 的坐标点 : 20 + +## 4 伴生对象实例 +/* 文件名:Marker.scala + * author:菜鸟教程 + * url:www.runoob.com + */ + +// 私有构造方法 +class Marker private(val color:String) { + + println("创建" + this) + + override def toString(): String = "颜色标记:"+ color + +} + +// 伴生对象,与类名字相同,可以访问类的私有属性和方法 +object Marker{ + + private val markers: Map[String, Marker] = Map( + "red" -> new Marker("red"), + "blue" -> new Marker("blue"), + "green" -> new Marker("green") + ) + + def apply(color:String) = { + if(markers.contains(color)) markers(color) else null + } + + + def getMarker(color:String) = { + if(markers.contains(color)) markers(color) else null + } + def main(args: Array[String]) { + println(Marker("red")) + // 单例函数调用,省略了.(点)符号 + println(Marker getMarker "blue") + } +} +执行以上代码,输出结果为: + +$ scalac Marker.scala +$ scala Marker +创建颜色标记:red +创建颜色标记:blue +创建颜色标记:green +颜色标记:red +颜色标记:blue \ No newline at end of file diff --git a/Scala/13 Trait.md b/Scala/13 Trait.md new file mode 100644 index 00000000..5a71edf3 --- /dev/null +++ b/Scala/13 Trait.md @@ -0,0 +1,64 @@ +# Scala Trait(特征) +Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。 + +与接口不同的是,它还可以定义属性和方法的实现。 + +一般情况下Scala的类只能够继承单一父类,但是如果是 Trait(特征) 的话就可以继承多个,从结果来看就是实现了多重继承。 + +Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait,如下所示: + +trait Equal { + def isEqual(x: Any): Boolean + def isNotEqual(x: Any): Boolean = !isEqual(x) +} +以上Trait(特征)由两个方法组成:isEqual 和 isNotEqual。isEqual 方法没有定义方法的实现,isNotEqual定义了方法的实现。子类继承特征可以实现未被实现的方法。所以其实 Scala Trait(特征)更像 Java 的抽象类。 + +以下演示了特征的完整实例: + +/* 文件名:Test.scala + * author:菜鸟教程 + * url:www.runoob.com + */ +trait Equal { + def isEqual(x: Any): Boolean + def isNotEqual(x: Any): Boolean = !isEqual(x) +} + +class Point(xc: Int, yc: Int) extends Equal { + var x: Int = xc + var y: Int = yc + def isEqual(obj: Any) = + obj.isInstanceOf[Point] && + obj.asInstanceOf[Point].x == x +} + +object Test { + def main(args: Array[String]) { + val p1 = new Point(2, 3) + val p2 = new Point(2, 4) + val p3 = new Point(3, 3) + + println(p1.isNotEqual(p2)) + println(p1.isNotEqual(p3)) + println(p1.isNotEqual(2)) + } +} +执行以上代码,输出结果为: + +$ scalac Test.scala +$ scala Test +false +true +true +特征构造顺序 +特征也可以有构造器,由字段的初始化和其他特征体中的语句构成。这些语句在任何混入该特征的对象在构造时都会被执行。 + +构造器的执行顺序: + +调用超类的构造器; +特征构造器在超类构造器之后、类构造器之前执行; +特征由左到右被构造; +每个特征当中,父特征先被构造; +如果多个特征共有一个父特征,父特征不会被重复构造 +所有特征被构造完毕,子类被构造。 +构造器的顺序是类的线性化的反向。线性化是描述某个类型的所有超类型的一种技术规格。 \ No newline at end of file diff --git a/Scala/2 数据类型.md b/Scala/2 数据类型.md new file mode 100644 index 00000000..a0925cfe --- /dev/null +++ b/Scala/2 数据类型.md @@ -0,0 +1,34 @@ +# 数据类型 + +## 1 数据类型 + +### Scala 数据类型 +Scala 与 Java有着相同的数据类型,下表列出了 Scala 支持的数据类型: + +数据类型 描述 +Byte 8位有符号补码整数。数值区间为 -128 到 127 +Short 16位有符号补码整数。数值区间为 -32768 到 32767 +Int 32位有符号补码整数。数值区间为 -2147483648 到 2147483647 +Long 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807 +Float 32 位, IEEE 754 标准的单精度浮点数 +Double 64 位 IEEE 754 标准的双精度浮点数 +Char 16位无符号Unicode字符, 区间值为 U+0000 到 U+FFFF +String 字符序列 +Boolean true或false +Unit 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。 +Null null 或空引用 +Nothing Nothing类型在Scala的类层级的最底端;它是任何其他类型的子类型。 +Any Any是所有其他类的超类 +AnyRef AnyRef类是Scala里所有引用类(reference class)的基类 + +### 转义字符 + +转义字符 Unicode 描述 +\b \u0008 退格(BS) ,将当前位置移到前一列 +\t \u0009 水平制表(HT) (跳到下一个TAB位置) +\n \u000a 换行(LF) ,将当前位置移到下一行开头 +\f \u000c 换页(FF),将当前位置移到下页开头 +\r \u000d 回车(CR) ,将当前位置移到本行开头 +\" \u0022 代表一个双引号(")字符 +\' \u0027 代表一个单引号(')字符 +\\ \u005c 代表一个反斜线字符 '\' \ No newline at end of file diff --git a/Scala/3 变量常量.md b/Scala/3 变量常量.md new file mode 100644 index 00000000..d6653446 --- /dev/null +++ b/Scala/3 变量常量.md @@ -0,0 +1,51 @@ +# Scala 变量 +### 变量的作用 +变量是一种使用方便的占位符,用于引用计算机内存地址,变量创建后会占用一定的内存空间。 + +基于变量的数据类型,操作系统会进行内存分配并且决定什么将被储存在保留内存中。因此,通过给变量分配不同的数据类型,你可以在这些变量中存储整数,小数或者字母。 + +### 变量声明 +在学习如何声明变量与常量之前,我们先来了解一些变量与常量。 + +一、变量: 在程序运行过程中其值可能发生改变的量叫做变量。如:时间,年龄。 +二、常量 在程序运行过程中其值不会发生变化的量叫做常量。如:数值 3,字符'A'。 +在 Scala 中,使用关键词 "var" 声明变量,使用关键词 "val" 声明常量。 + +声明变量实例如下: + +var myVar : String = "Foo" +var myVar : String = "Too" +以上定义了变量 myVar,我们可以修改它。 + +声明常量实例如下: + +val myVal : String = "Foo" +以上定义了常量 myVal,它是不能修改的。如果程序尝试修改常量 myVal 的值,程序将会在编译时报错。 + +### 变量类型声明 +只声明类型不给值。 +变量的类型在变量名之后等号之前声明。定义变量的类型的语法格式如下: + +var VariableName : DataType [= Initial Value] + +或 + +val VariableName : DataType [= Initial Value] + +### 变量类型引用 +在 Scala 中声明变量和常量不一定要指明数据类型,在没有指明数据类型的情况下,其数据类型是通过变量或常量的初始值推断出来的。 + +所以,如果在没有指明数据类型的情况下声明变量或常量必须要给出其初始值,否则将会报错。 + +var myVar = 10; +val myVal = "Hello, Scala!"; + +### cala 多个变量声明 +Scala 支持多个变量的声明: + +val xmax, ymax = 100 // xmax, ymax都声明为100 +如果方法返回值是元组,我们可以使用 val 来声明一个元组: + +scala> val pa = (40,"Foo") +pa: (Int, String) = (40,Foo) + diff --git a/Scala/4 访问修饰符.md b/Scala/4 访问修饰符.md new file mode 100644 index 00000000..3adef5d4 --- /dev/null +++ b/Scala/4 访问修饰符.md @@ -0,0 +1,87 @@ +# Scala 访问修饰符 +Scala 访问修饰符基本和Java的一样,分别有:private,protected,public。 + +如果没有指定访问修饰符,默认情况下,Scala 对象的访问级别都是 public。 + +Scala 中的 private 限定符,比 Java 更严格,在嵌套类情况下,外层类甚至不能访问被嵌套类的私有成员。 + +## 1 私有(Private)成员 +用 private 关键字修饰,带有此标记的成员仅在包含了成员定义的类或对象内部可见,同样的规则还适用内部类。 + +class Outer{ + class Inner{ + private def f(){println("f")} + class InnerMost{ + f() // 正确 + } + } + (new Inner).f() //错误 +} +(new Inner).f( ) 访问不合法是因为 f 在 Inner 中被声明为 private,而访问不在类 Inner 之内。 + +但在 InnerMost 里访问 f 就没有问题的,因为这个访问包含在 Inner 类之内。 + +Java中允许这两种访问,因为它允许外部类访问内部类的私有成员。 + +## 2 保护(Protected)成员 +在 scala 中,对保护(Protected)成员的访问比 java 更严格一些。因为它只允许保护成员在定义了该成员的的类的子类中被访问。而在java中,用protected关键字修饰的成员,除了定义了该成员的类的子类可以访问,同一个包里的其他类也可以进行访问。 + +package p{ +class Super{ + protected def f() {println("f")} + } + class Sub extends Super{ + f() + } + class Other{ + (new Super).f() //错误 + } +} +上例中,Sub 类对 f 的访问没有问题,因为 f 在 Super 中被声明为 protected,而 Sub 是 Super 的子类。相反,Other 对 f 的访问不被允许,因为 other 没有继承自 Super。而后者在 java 里同样被认可,因为 Other 与 Sub 在同一包里。 + +## 3 公共(Public)成员 +Scala中,如果没有指定任何的修饰符,则默认为 public。这样的成员在任何地方都可以被访问。 + +class Outer { + class Inner { + def f() { println("f") } + class InnerMost { + f() // 正确 + } + } + (new Inner).f() // 正确因为 f() 是 public +} + +## 4 作用域保护 +Scala中,访问修饰符可以通过使用限定词强调。格式为: + +private[x] + +或 + +protected[x] +这里的x指代某个所属的包、类或单例对象。如果写成private[x],读作"这个成员除了对[…]中的类或[…]中的包中的类及它们的伴生对像可见外,对其它所有类都是private。 + +这种技巧在横跨了若干包的大型项目中非常有用,它允许你定义一些在你项目的若干子包中可见但对于项目外部的客户却始终不可见的东西。 + +package bobsrockets{ + package navigation{ + private[bobsrockets] class Navigator{ + protected[navigation] def useStarChart(){} + class LegOfJourney{ + private[Navigator] val distance = 100 + } + private[this] var speed = 200 + } + } + package launch{ + import navigation._ + object Vehicle{ + private[launch] val guide = new Navigator + } + } +} +上述例子中,类Navigator被标记为private[bobsrockets]就是说这个类对包含在bobsrockets包里的所有的类和对象可见。 + +比如说,从Vehicle对象里对Navigator的访问是被允许的,因为对象Vehicle包含在包launch中,而launch包在bobsrockets中,相反,所有在包bobsrockets之外的代码都不能访问类Navigator。 + diff --git a/Scala/5 运算符.md b/Scala/5 运算符.md new file mode 100644 index 00000000..fb58b677 --- /dev/null +++ b/Scala/5 运算符.md @@ -0,0 +1,109 @@ +# Scala 运算符 +一个运算符是一个符号,用于告诉编译器来执行指定的数学运算和逻辑运算。 + +Scala 含有丰富的内置运算符,包括以下几种类型: + +算术运算符 + +关系运算符 + +逻辑运算符 + +位运算符 + +赋值运算符 + +## 1 算术运算符 +下表列出了 Scala 支持的算术运算符。 + +假定变量 A 为 10,B 为 20: + +运算符 描述 实例 ++ 加号 A + B 运算结果为 30 +- 减号 A - B 运算结果为 -10 +* 乘号 A * B 运算结果为 200 +/ 除号 B / A 运算结果为 2 +% 取余 B % A 运算结果为 0 + +## 2 关系运算符 +下表列出了 Scala 支持的关系运算符。 + +假定变量 A 为 10,B 为 20: + +运算符 描述 实例 +== 等于 (A == B) 运算结果为 false +!= 不等于 (A != B) 运算结果为 true +> 大于 (A > B) 运算结果为 false +< 小于 (A < B) 运算结果为 true +>= 大于等于 (A >= B) 运算结果为 false +<= 小于等于 (A <= B) 运算结果为 true + +## 3 逻辑运算符 +下表列出了 Scala 支持的逻辑运算符。 + +假定变量 A 为 1,B 为 0: + +运算符 描述 实例 +&& 逻辑与 (A && B) 运算结果为 false +|| 逻辑或 (A || B) 运算结果为 true +! 逻辑非 !(A && B) 运算结果为 true + +## 4 位运算符 +位运算符用来对二进制位进行操作,~,&,|,^分别为取反,按位与与,按位与或,按位与异或运算,如下表实例: + +p q p & q p | q p ^ q +0 0 0 0 0 +0 1 0 1 1 +1 1 1 1 0 +1 0 0 1 1 + +Scala 中的按位运算法则如下: + +运算符 描述 实例 +& 按位与运算符 (a & b) 输出结果 12 ,二进制解释: 0000 1100 +| 按位或运算符 (a | b) 输出结果 61 ,二进制解释: 0011 1101 +^ 按位异或运算符 (a ^ b) 输出结果 49 ,二进制解释: 0011 0001 +~ 按位取反运算符 (~a ) 输出结果 -61 ,二进制解释: 1100 0011, 在一个有符号二进制数的补码形式。 +<< 左移动运算符 a << 2 输出结果 240 ,二进制解释: 1111 0000 +>> 右移动运算符 a >> 2 输出结果 15 ,二进制解释: 0000 1111 +>>> 无符号右移 A >>>2 输出结果 15, 二进制解释: 0000 1111 + +## 5 赋值运算符 +以下列出了 Scala 语言支持的赋值运算符: + +运算符 描述 实例 += 简单的赋值运算,指定右边操作数赋值给左边的操作数。 C = A + B 将 A + B 的运算结果赋值给 C ++= 相加后再赋值,将左右两边的操作数相加后再赋值给左边的操作数。 C += A 相当于 C = C + A +-= 相减后再赋值,将左右两边的操作数相减后再赋值给左边的操作数。 C -= A 相当于 C = C - A +*= 相乘后再赋值,将左右两边的操作数相乘后再赋值给左边的操作数。 C *= A 相当于 C = C * A +/= 相除后再赋值,将左右两边的操作数相除后再赋值给左边的操作数。 C /= A 相当于 C = C / A +%= 求余后再赋值,将左右两边的操作数求余后再赋值给左边的操作数。 C %= A is equivalent to C = C % A +<<= 按位左移后再赋值 C <<= 2 相当于 C = C << 2 +>>= 按位右移后再赋值 C >>= 2 相当于 C = C >> 2 +&= 按位与运算后赋值 C &= 2 相当于 C = C & 2 +^= 按位异或运算符后再赋值 C ^= 2 相当于 C = C ^ 2 +|= 按位或运算后再赋值 C |= 2 相当于 C = C | 2 + +## 6 运算符优先级 + +取决于所属的运算符组,它会影响算式的的计算。 + +实例: x = 7 + 3 * 2; 这里, x 计算结果为 13, 而不是 20,因为乘法(*) 高于加法(+), 所以它先计算 3*2 再加上 7。 + +查看以下表格,优先级从上到下依次递减,最上面具有最高的优先级,逗号操作符具有最低的优先级。 + +类别 运算符 关联性 +1 () [] 左到右 +2 ! ~ 右到左 +3 * / % 左到右 +4 + - 左到右 +5 >> >>> << 左到右 +6 > >= < <= 左到右 +7 == != 左到右 +8 & 左到右 +9 ^ 左到右 +10 | 左到右 +11 && 左到右 +12 || 左到右 +13 = += -= *= /= %= >>= <<= &= ^= |= 右到左 +14 , 左到右 diff --git a/Scala/6 控制结构.md b/Scala/6 控制结构.md new file mode 100644 index 00000000..19a7a7f0 --- /dev/null +++ b/Scala/6 控制结构.md @@ -0,0 +1,56 @@ +# 控制结构 + +## 1 IF选择 +Scala IF...ELSE 语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。 + +* if 语句。if 语句有布尔表达式及之后的语句块组成。 +* if...else 语句。if 语句后可以紧跟 else 语句,else 内的语句块可以在布尔表达式为 false 的时候执行。 +* if...else if...else 语句。if 语句后可以紧跟 else if...else 语句,在多个条件判断语句的情况下很有用。 +* if...{if...else...}...else... 嵌套语句。if...else 嵌套语句可以实现在 if 语句内嵌入一个或多个 if 语句。 + + +## 2 循环 + +### 循环类型 +Scala 语言提供了以下几种循环类型。点击链接查看每个类型的细节。 + +循环类型 描述 +while 循环 运行一系列语句,如果条件为true,会重复运行,直到条件变为false。 +do...while 循环 类似 while 语句区别在于判断循环条件之前,先执行一次循环的代码块。 +for 循环 用来重复执行一系列语句直到达成特定条件达成,一般通过在每次循环完成后增加计数器的值来实现。 + +### while 循环 + +Scala 语言中 while 循环的语法: + +while(condition) +{ + statement(s); +} +在这里,statement(s) 可以是一个单独的语句,也可以是几个语句组成的代码块。 + +condition 可以是任意的表达式,当为任意非零值时都为 true。当条件为 true 时执行循环。 当条件为 false 时,退出循环,程序流将继续执行紧接着循环的下一条语句。 + + +### for循环 + +语法 +Scala 语言中 for 循环的语法: + +for( var x <- Range ){ + statement(s); +} + +### do while循环 +Scala 语言中 while 循环的语法: + +do { + statement(s); +} while( condition ); +### 循环控制语句 +循环控制语句改变你代码的执行顺序,通过它你可以实现代码的跳转。Scala 以下几种循环控制语句: + +Scala 不支持 break 或 continue 语句,但从 2.8 版本后提供了一种中断循环的方式,点击以下链接查看详情。 + +控制语句 描述 +break 语句 中断循环 diff --git a/Scala/7 函数.md b/Scala/7 函数.md new file mode 100644 index 00000000..491d96ae --- /dev/null +++ b/Scala/7 函数.md @@ -0,0 +1,63 @@ +# 方法函数 + +## 1 方法与函数关系 + +Scala 有方法与函数,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话来说在类中定义的函数即是方法。 + +Scala 中的方法跟 Java 的类似,方法是组成类的一部分。 + +Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象。 + +Scala 中使用 val 语句可以定义函数,def 语句定义方法。 + +class Test{ + def m(x: Int) = x + 3 + val f = (x: Int) => x + 3 +} +## 2 函数 + +### 类型变量混合式 + +val f1 = (x:Int,y:Int)=>x*y + +### 类型变量分离式 +val f2:(Int,Int)=>Int = (x,y)=>x*y + + +## 3 方法 +### 方法声明 +Scala 方法声明格式如下: + +def functionName ([参数列表]) : [return type] +如果你不写等于号和方法主体,那么方法会被隐式声明为抽象(abstract),包含它的类型于是也是一个抽象类型。 + +### 方法定义 +方法定义由一个 def 关键字开始,紧接着是可选的参数列表,一个冒号 : 和方法的返回类型,一个等于号 = ,最后是方法的主体。 + +Scala 方法定义格式如下: + +def functionName ([参数列表]) : [return type] = { + function body + return [expr] +} + +object add{ + def addInt( a:Int, b:Int ) : Int = { + var sum:Int = 0 + sum = a + b + + return sum + } +} + + + +### 方法调用 +Scala 提供了多种不同的方法调用方式: + +以下是调用方法的标准格式: + +functionName( 参数列表 ) +如果方法使用了实例的对象来调用,我们可以使用类似java的格式 (使用 . 号): + +[instance.]functionName( 参数列表 ) diff --git a/Scala/8 闭包.md b/Scala/8 闭包.md new file mode 100644 index 00000000..9a359c38 --- /dev/null +++ b/Scala/8 闭包.md @@ -0,0 +1,29 @@ +# Scala 闭包 +闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。 + +闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数。 + +如下面这段匿名的函数: + +val multiplier = (i:Int) => i * 10 +函数体内有一个变量 i,它作为函数的一个参数。如下面的另一段代码: + +val multiplier = (i:Int) => i * factor +在 multiplier 中有两个变量:i 和 factor。其中的一个 i 是函数的形式参数,在 multiplier 函数被调用时,i 被赋予一个新的值。然而,factor不是形式参数,而是自由变量,考虑下面代码: + +var factor = 3 +val multiplier = (i:Int) => i * factor +这里我们引入一个自由变量 factor,这个变量定义在函数外面。 + +这样定义的函数变量 multiplier 成为一个"闭包",因为它引用到函数外面定义的变量,定义这个函数的过程是将这个自由变量捕获而构成一个封闭的函数。 + +完整实例 + +object Test { + def main(args: Array[String]) { + println( "muliplier(1) value = " + multiplier(1) ) + println( "muliplier(2) value = " + multiplier(2) ) + } + var factor = 3 + val multiplier = (i:Int) => i * factor +} \ No newline at end of file diff --git a/Scala/9 字符串.md b/Scala/9 字符串.md new file mode 100644 index 00000000..0e61e3a7 --- /dev/null +++ b/Scala/9 字符串.md @@ -0,0 +1,289 @@ +# 字符串 + +## 1 简介 +在 Scala 中,字符串的类型实际上是 Java String,它本身没有 String 类。 + +在 Scala 中,String 是一个不可变的对象,所以该对象不可被修改。这就意味着你如果修改字符串就会产生一个新的字符串对象。 + +但其他对象,如数组就是可变的对象。接下来我们会为大家介绍常用的 java.lang.String 方法。 + + +## 2 常用方法 + +### 创建字符串 +创建字符串实例如下: + +var greeting = "Hello World!"; + +或 + +var greeting:String = "Hello World!"; + +### 字符串长度 +我们可以使用 length() 方法来获取字符串长度: + +object Test { + def main(args: Array[String]) { + var palindrome = "www.runoob.com"; + var len = palindrome.length(); + println( "String Length is : " + len ); + } +} + +### 字符串连接 +String 类中使用 concat() 方法来连接两个字符串: + +string1.concat(string2); + + +### 创建格式化字符串 +String 类中你可以使用 printf() 方法来格式化字符串并输出,String format() 方法可以返回 String 对象而不是 PrintStream 对象。以下实例演示了 printf() 方法的使用: + +object Test { + def main(args: Array[String]) { + var floatVar = 12.456 + var intVar = 2000 + var stringVar = "菜鸟教程!" + var fs = printf("浮点型变量为 " + + "%f, 整型变量为 %d, 字符串为 " + + " %s", floatVar, intVar, stringVar) + println(fs) + } +} + + +### 常用方法 + +String 方法 +下表列出了 java.lang.String 中常用的方法,你可以在 Scala 中使用: + +序号 方法及描述 +1 +char charAt(int index) + +返回指定位置的字符 + +2 +int compareTo(Object o) + +比较字符串与对象 + +3 +int compareTo(String anotherString) + +按字典顺序比较两个字符串 + +4 +int compareToIgnoreCase(String str) + +按字典顺序比较两个字符串,不考虑大小写 + +5 +String concat(String str) + +将指定字符串连接到此字符串的结尾 + +6 +boolean contentEquals(StringBuffer sb) + +将此字符串与指定的 StringBuffer 比较。 + +7 +static String copyValueOf(char[] data) + +返回指定数组中表示该字符序列的 String + +8 +static String copyValueOf(char[] data, int offset, int count) + +返回指定数组中表示该字符序列的 String + +9 +boolean endsWith(String suffix) + +测试此字符串是否以指定的后缀结束 + +10 +boolean equals(Object anObject) + +将此字符串与指定的对象比较 + +11 +boolean equalsIgnoreCase(String anotherString) + +将此 String 与另一个 String 比较,不考虑大小写 + +12 +byte getBytes() + +使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中 + +13 +byte[] getBytes(String charsetName + +使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中 + +14 +void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) + +将字符从此字符串复制到目标字符数组 + +15 +int hashCode() + +返回此字符串的哈希码 + +16 +int indexOf(int ch) + +返回指定字符在此字符串中第一次出现处的索引 + +17 +int indexOf(int ch, int fromIndex) + +返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索 + +18 +int indexOf(String str) + +返回指定子字符串在此字符串中第一次出现处的索引 + +19 +int indexOf(String str, int fromIndex) + +返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始 + +20 +String intern() + +返回字符串对象的规范化表示形式 + +21 +int lastIndexOf(int ch) + +返回指定字符在此字符串中最后一次出现处的索引 + +22 +int lastIndexOf(int ch, int fromIndex) + +返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索 + +23 +int lastIndexOf(String str) + +返回指定子字符串在此字符串中最右边出现处的索引 + +24 +int lastIndexOf(String str, int fromIndex) + +返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索 + +25 +int length() + +返回此字符串的长度 + +26 +boolean matches(String regex) + +告知此字符串是否匹配给定的正则表达式 + +27 +boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) + +测试两个字符串区域是否相等 + +28 +boolean regionMatches(int toffset, String other, int ooffset, int len) + +测试两个字符串区域是否相等 + +29 +String replace(char oldChar, char newChar) + +返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的 + +30 +String replaceAll(String regex, String replacement + +使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串 + +31 +String replaceFirst(String regex, String replacement) + +使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串 + +32 +String[] split(String regex) + +根据给定正则表达式的匹配拆分此字符串 + +33 +String[] split(String regex, int limit) + +根据匹配给定的正则表达式来拆分此字符串 + +34 +boolean startsWith(String prefix) + +测试此字符串是否以指定的前缀开始 + +35 +boolean startsWith(String prefix, int toffset) + +测试此字符串从指定索引开始的子字符串是否以指定前缀开始。 + +36 +CharSequence subSequence(int beginIndex, int endIndex) + +返回一个新的字符序列,它是此序列的一个子序列 + +37 +String substring(int beginIndex) + +返回一个新的字符串,它是此字符串的一个子字符串 + +38 +String substring(int beginIndex, int endIndex) + +返回一个新字符串,它是此字符串的一个子字符串 + +39 +char[] toCharArray() + +将此字符串转换为一个新的字符数组 + +40 +String toLowerCase() + +使用默认语言环境的规则将此 String 中的所有字符都转换为小写 + +41 +String toLowerCase(Locale locale) + +使用给定 Locale 的规则将此 String 中的所有字符都转换为小写 + +42 +String toString() + +返回此对象本身(它已经是一个字符串!) + +43 +String toUpperCase() + +使用默认语言环境的规则将此 String 中的所有字符都转换为大写 + +44 +String toUpperCase(Locale locale) + +使用给定 Locale 的规则将此 String 中的所有字符都转换为大写 + +45 +String trim() + +删除指定字符串的首尾空白符 + +46 +static String valueOf(primitive data type x) + +返回指定类型参数的字符串表示形式 \ No newline at end of file diff --git a/Scala/参考文献.md b/Scala/参考文献.md new file mode 100644 index 00000000..87c75a56 --- /dev/null +++ b/Scala/参考文献.md @@ -0,0 +1,4 @@ +* [菜鸟教程](https://www.runoob.com/scala/scala-tutorial.html) +* [scala详细教程](https://blog.csdn.net/wangshun_410/article/details/90759688#2.3%20IDEAScala%20%E6%8F%92%E4%BB%B6%E7%9A%84%E7%A6%BB%E7%BA%BF%E5%AE%89%E8%A3%85) +* [W3c教程](https://www.w3cschool.cn/scaladevelopmentguide/) +* [另外一个教程](https://www.cnblogs.com/lq0310/p/9840317.html) \ No newline at end of file diff --git a/Spark/Spark原理.md b/Spark/Spark原理.md new file mode 100644 index 00000000..f7c9cfec --- /dev/null +++ b/Spark/Spark原理.md @@ -0,0 +1,97 @@ +# Spark +> 参考文献 +> * [原理介绍](https://www.cnblogs.com/cxxjohnson/p/8909578.html) + +## 1 简介 + +Apache Spark是一个围绕速度、易用性和复杂分析构建的大数据处理框架,Spark提供了一个全面、统一的框架用于管理各种有着不同性质(文本数据、图表数据等)的数据集和数据源(批量数据或实时的流数据)的大数据处理的需求 + +Spark是一个计算引擎、计算框架,与TensorFlow很像。但是不提供数据存储功能。大数据存储功能由Hadoop等专门的解决方案提供。 + +## 2 架构生态 + +通常当需要处理的数据量超过了单机尺度(比如我们的计算机有4GB的内存,而我们需要处理100GB以上的数据)这时我们可以选择spark集群进行计算,有时我们可能需要处理的数据量并不大,但是计算很复杂,需要大量的时间,这时我们也可以选择利用spark集群强大的计算资源,并行化地计算,其架构示意图如下: + +![](image/Spark架构.png.png) + +* Spark Core:包含Spark的基本功能;尤其是定义RDD的API、操作以及这两者上的动作。其他Spark的库都是构建在RDD和Spark Core之上的 +* Spark SQL:提供通过Apache Hive的SQL变体Hive查询语言(HiveQL)与Spark进行交互的API。每个数据库表被当做一个RDD,Spark SQL查询被转换为Spark操作。 +* Spark Streaming:对实时数据流进行处理和控制。Spark Streaming允许程序能够像普通RDD一样处理实时数据 +* MLlib:一个常用机器学习算法库,算法被实现为对RDD的Spark操作。这个库包含可扩展的学习算法,比如分类、回归等需要对大量数据集进行迭代的操作。 +* GraphX:控制图、并行图操作和计算的一组算法和工具的集合。GraphX扩展了RDD API,包含控制图、创建子图、访问路径上所有顶点的操作 + + +## 3 Spark&Hadoop + +* Hadoop有两个核心模块,分布式存储模块HDFS和分布式计算模块Mapreduce +* spark本身并没有提供分布式文件系统,因此spark的分析大多依赖于Hadoop的分布式文件系统HDFS +* Hadoop的Mapreduce与spark都可以进行数据计算,而相比于Mapreduce,spark的速度更快并且提供的功能更加丰富 + +## 4 运行流程及特点 + +![](image/Spark运行流程.png) + +1. 构建Spark Application的运行环境,启动SparkContext +2. SparkContext向资源管理器(可以是Standalone,Mesos,Yarn)申请运行Executor资源,并启动StandaloneExecutorbackend, +3. Executor向SparkContext申请Task +4. SparkContext将应用程序分发给Executor +5. SparkContext构建成DAG图,将DAG图分解成Stage、将Taskset发送给Task Scheduler,最后由Task Scheduler将Task发送给Executor运行 +6. Task在Executor上运行,运行完释放所有资源 + + +Spark运行特点: + +* 每个Application获取专属的executor进程,该进程在Application期间一直驻留,并以多线程方式运行Task。这种Application隔离机制是有优势的,无论是从调度角度看(每个Driver调度他自己的任务),还是从运行角度看(来自不同Application的Task运行在不同JVM中),当然这样意味着Spark Application不能跨应用程序共享数据,除非将数据写入外部存储系统 +* Spark与资源管理器无关,只要能够获取executor进程,并能保持相互通信就可以了 +* 提交SparkContext的Client应该靠近Worker节点(运行Executor的节点),最好是在同一个Rack里,因为Spark Application运行过程中SparkContext和Executor之间有大量的信息交换 +* Task采用了数据本地性和推测执行的优化机制 + +## 5 常用术语 + +* Application: Appliction都是指用户编写的Spark应用程序,其中包括一个Driver功能的代码和分布在集群中多个节点上运行的Executor代码 +* Driver: Spark中的Driver即运行上述Application的main函数并创建SparkContext,创建SparkContext的目的是为了准备Spark应用程序的运行环境,在Spark中有SparkContext负责与ClusterManager通信,进行资源申请、任务的分配和监控等,当Executor部分运行完毕后,Driver同时负责将SparkContext关闭,通常用SparkContext代表Driver +* Executor: 某个Application运行在worker节点上的一个进程, 该进程负责运行某些Task, 并且负责将数据存到内存或磁盘上,每个Application都有各自独立的一批Executor, 在Spark on Yarn模式下,其进程名称为CoarseGrainedExecutor Backend。一个CoarseGrainedExecutor Backend有且仅有一个Executor对象, 负责将Task包装成taskRunner,并从线程池中抽取一个空闲线程运行Task, 这个每一个oarseGrainedExecutor Backend能并行运行Task的数量取决与分配给它的cpu个数 +* Cluter Manager:指的是在集群上获取资源的外部服务。目前有三种类型 + * Standalon : spark原生的资源管理,由Master负责资源的分配 + * Apache Mesos:与hadoop MR兼容性良好的一种资源调度框架 + * Hadoop Yarn: 主要是指Yarn中的ResourceManager +* Worker: 集群中任何可以运行Application代码的节点,在Standalone模式中指的是通过slave文件配置的Worker节点,在Spark on Yarn模式下就是NoteManager节点 +* Task: 被送到某个Executor上的工作单元,但hadoopMR中的MapTask和ReduceTask概念一样,是运行Application的基本单位,多个Task组成一个Stage,而Task的调度和管理等是由TaskScheduler负责 +* Job: 包含多个Task组成的并行计算,往往由Spark Action触发生成, 一个Application中往往会产生多个Job +* Stage: 每个Job会被拆分成多组Task, 作为一个TaskSet, 其名称为Stage,Stage的划分和调度是有DAGScheduler来负责的,Stage有非最终的Stage(Shuffle Map Stage)和最终的Stage(Result Stage)两种,Stage的边界就是发生shuffle的地方 + +![](image/Spark执行逻辑.png) + +* DAGScheduler: 根据Job构建基于Stage的DAG(Directed Acyclic Graph有向无环图),并提交Stage给TASkScheduler。 其划分Stage的依据是RDD之间的依赖的关系找出开销最小的调度方法,如下图 +* TASKSedulter: 将TaskSET提交给worker运行,每个Executor运行什么Task就是在此处分配的. TaskScheduler维护所有TaskSet,当Executor向Driver发生心跳时,TaskScheduler会根据资源剩余情况分配相应的Task。另外TaskScheduler还维护着所有Task的运行标签,重试失败的Task。下图展示了TaskScheduler的作用 + +在不同运行模式中任务调度器具体为: +* Spark on Standalone模式为TaskScheduler +* YARN-Client模式为YarnClientClusterScheduler +* YARN-Cluster模式为YarnClusterScheduler +将这些术语串起来的运行层次图如下: + +![](image/Spark执行层次.png) + +Job=多个stage,Stage=多个同种task, Task分为ShuffleMapTask和ResultTask,Dependency分为ShuffleDependency和NarrowDependency + + +## 7 RDD 执行流程 + +RDD运行流程: + +RDD在Spark中运行大概分为以下三步: +1. 创建RDD对象 +2. DAGScheduler模块介入运算,计算RDD之间的依赖关系,RDD之间的依赖关系就形成了DAG +3. 每一个Job被分为多个Stage。划分Stage的一个主要依据是当前计算因子的输入是否是确定的,如果是则将其分在同一个Stage,避免多个Stage之间的消息传递开销 + +示例图如下: + +![](image/SparkRDD执行流程.png) + +以下面一个按 A-Z 首字母分类,查找相同首字母下不同姓名总个数的例子来看一下 RDD 是如何运行起来的 +![](image/Spark程序实例.png) +创建 RDD 上面的例子除去最后一个 collect 是个动作,不会创建 RDD 之外,前面四个转换都会创建出新的 RDD 。因此第一步就是创建好所有 RDD( 内部的五项信息 )? +创建执行计划 Spark 会尽可能地管道化,并基于是否要重新组织数据来划分 阶段 (stage) ,例如本例中的 groupBy() 转换就会将整个执行计划划分成两阶段执行。最终会产生一个 DAG(directed acyclic graph ,有向无环图 ) 作为逻辑执行计划 + +调度任务 将各阶段划分成不同的 任务 (task) ,每个任务都是数据和计算的合体。在进行下一阶段前,当前阶段的所有任务都要执行完成。因为下一阶段的第一个转换一定是重新组织数据的,所以必须等当前阶段所有结果数据都计算出来了才能继续 \ No newline at end of file diff --git a/Spark/image/SparkRDD执行流程.png b/Spark/image/SparkRDD执行流程.png new file mode 100644 index 00000000..07c7da82 Binary files /dev/null and b/Spark/image/SparkRDD执行流程.png differ diff --git a/Spark/image/Spark执行层次.png b/Spark/image/Spark执行层次.png new file mode 100644 index 00000000..92926828 Binary files /dev/null and b/Spark/image/Spark执行层次.png differ diff --git a/Spark/image/Spark执行逻辑.png b/Spark/image/Spark执行逻辑.png new file mode 100644 index 00000000..830075a2 Binary files /dev/null and b/Spark/image/Spark执行逻辑.png differ diff --git a/Spark/image/Spark架构.png.png b/Spark/image/Spark架构.png.png new file mode 100644 index 00000000..e29e6af3 Binary files /dev/null and b/Spark/image/Spark架构.png.png differ diff --git a/Spark/image/Spark程序实例.png b/Spark/image/Spark程序实例.png new file mode 100644 index 00000000..367b4d8a Binary files /dev/null and b/Spark/image/Spark程序实例.png differ diff --git a/Spark/image/Spark运行流程.png b/Spark/image/Spark运行流程.png new file mode 100644 index 00000000..5b36400a Binary files /dev/null and b/Spark/image/Spark运行流程.png differ diff --git a/概率论与数理统计/第11节 假设检验.md b/概率论与数理统计/第11节 假设检验.md index eac5a518..5f092094 100644 --- a/概率论与数理统计/第11节 假设检验.md +++ b/概率论与数理统计/第11节 假设检验.md @@ -25,7 +25,7 @@ $$ * 检验法则:若$(x_1,\dotsm,x_n)\in W$,则拒绝$H_0$,否则由$(x_1,\dotsm,x_n)\in W^c$,就接受$H_0$。称$W$为拒绝域,$W^c$称为接受域。 > 拒绝度$\alpha$与拒绝域$W$一一对应。置信度$1-\alpha$与接受域(置信区间)$1-\alpha$一一对应。 -* 检验统计量:能够由统计量确定拒绝域W,则统计量为检验统计量。检验统计量的检验临界值,能够区分两个检验区间。 +* 检验统计量:能够由统计量确定拒绝域W,则统计量为检验统计量。检验统计量的检验临界值,能够区分两个检验区间。样本空间可以分为拒绝域和接受域,但是无法用数学关系式定量表达。需要使用样本的统计量的不等式,定量表示拒绝域和接受域的范围,而区分这个范围的量称为检验临界值。 * 示性函数或者检验函数 $$ \varphi(x)=\begin{cases} @@ -65,15 +65,21 @@ $\alpha$越大,第一类错误发生的错误越小,第二类错误发生的 > 这里的势不依赖于假设,而是一种本质的基于总体真正的属性的计算值。(假设是一种猜测,验证后才可以使准确地)$\varphi(x)$是显示总体本身真实属性的函数,不依赖于假设,与是否犯错无关。 -$H_0$不成立时,拒绝$H_0$的概率,称为势和功效。 +* $H_0$不成立时,成功拒绝$H_0$的概率,称为势和功效。 $$ \gamma(\theta)=P_\theta\{x\in W\} $$ -势函数,当$H_0$不成立时拒绝$H_0$的概率,称为势和功效。相当于拒绝度的衡量。 + +* 势函数,相当于拒绝度的衡量。 $$ g(\theta)=P_\theta\{x\in W\}=E_\theta(\varphi(x)),\theta\in\Theta\\ +$$ +* 势函数的计算 +> 关键点在于,\theta的范围。 +$$ 当\theta\in\Theta_0,g(\theta)=\alpha(\theta)\\ +当\theta\in\Theta_1,\beta(\theta)=p_\theta\{x\not\in W\}=1-g(\theta)\\ 当\theta\in\Theta_1,g(\theta)=\gamma(\theta) $$ @@ -87,6 +93,8 @@ $$ * 这里在逻辑上没有说接受概率和拒绝概率。接受概率和拒绝概率是区间估计那里的置信度和拒绝度。而这里用犯错概率来引入概率的影响,因为这里的接受和拒绝依赖于实际的样本,而区间估计并不依赖于实际的样本,是一种理论计算。所以犯错依赖于概率。 ### 定义:检验水平 + +> 分析:这里的检验水平就是拒绝水平。如果能在一个水平下拒绝,那么肯定也能在更大范围内拒绝,即包含真实拒绝域的拒绝域,肯定是拒绝域。因为,**如果能在一个范围内接收,肯定能在更小的范围下接受。**,即属于真实接受域的子集一定是接受域。 * 条件 $$ \alpha\in(0,1),\forall \theta\in\Theta\\ @@ -99,6 +107,14 @@ $$ $$ * 条件 $$ +\alpha<\alpha'<1 +$$ +* 结论 +$$ +\varphi(x)也是一个显著性水平为\alpha'的检验函数 +$$ +* 条件 +$$ \alpha=sup\{E_\theta(\varphi(x)),\theta\in\Theta\} $$ * 结论 @@ -113,3 +129,9 @@ $$ > 本质上都是区间积分与值的关系。在概率分布函数图像中即面积和面积临界值的关系。 +### 对应关系说明 +> 将$\theta,W$分开理解,会比较好。但是一个题中如何分开看,如何将二者都计算出来。应该是$\theta$是个条件,$g(\theta)$势函数用来计算拒绝域与接受域的概率。 +* 假设检验:$H_0,H_1$(命题的划分,不一定包含所有的情况,并集不为全集) +* 接受域拒绝域:$W^c,W$(样本空间的划分,反向定义,包含所有的情况,互补) +* 检验统计量-检验临界值区分$c$(检验统计量的划分,与样本空间的接受域和拒绝域意义对应) +* 置信度拒绝度:$1-\alpha,\alpha$(包含所有的情况,是一个琳结婚之,与检验临界值一一对应,在假设检验部分对应真实水平) \ No newline at end of file diff --git a/概率论与数理统计/第12节 正太总体参数的假设检验.md b/概率论与数理统计/第12节 正太总体参数的假设检验.md index 2668c753..6da7ddf4 100644 --- a/概率论与数理统计/第12节 正太总体参数的假设检验.md +++ b/概率论与数理统计/第12节 正太总体参数的假设检验.md @@ -12,9 +12,27 @@ H_0:\mu\geq\mu_0,&H_1:\mu<\mu_0 \end{aligned} $$ +### 假设检验-z检验步骤 +> 关于假设检验,需要使用样本统计量和临界值对应样本空间的接受域和拒绝域。 + +1. 命题假设$H_0:\mu\in\Theta_0,H_1:\mu\in\Theta_1$ +2. 检验统计量$z=\frac{\overline{x}-\mu_0}{\sigma/\sqrt{n}}$ +3. 根据检验水平计算拒绝域的临界值$\\双侧检验W=\{(x_1,\dotsm,x_n:|z|\geq z_{1-\frac{\alpha}{2}}\}\\单侧检验W=\{(x_1,\dotsm,x_n:|z|\geq z_{1-\alpha}\}\\$ +这里也可以根据样本的值,计算此时的$\alpha$的真实水平。 +4. 计算样本的检验统计量的值,与拒绝域的临界值对比。 + +> 单侧检验和双侧检验的区分在于,检验统计量不等式的构建或者说拒绝域不同。 + ## 2 单个总体-方差未知-均值检验 +> 方差未知的时候,无法通过查表获得z检验的值,此时一半会这接给出样本的均值。 +### 假设检验-z检验步骤 +1. 命题假设$H_0:\mu\in\Theta_0,H_1:\mu\in\Theta_1$ +2. 检验统计量$z=\frac{\overline{x}-\mu_0}{\sigma/\sqrt{n}}$ +3. 根据检验水平计算拒绝域的临界值$\\双侧检验W=\{(x_1,\dotsm,x_n:|z|\geq z_{1-\frac{\alpha}{2}}\}\\单侧检验W=\{(x_1,\dotsm,x_n:|z|\geq z_{1-\alpha}\}\\$ +这里也可以根据样本的值,计算此时的$\alpha$的真实水平。 +4. 计算样本的检验统计量的值,与拒绝域的临界值对比。 ## 3 单个总体-方差检验 不同的单侧假设问题 @@ -26,6 +44,14 @@ H_0:\sigma^2=\sigma^2_0,&H_1:\sigma^2<\sigma^2_0\\ H_0:\sigma^2\geq\sigma^2_0,&H_1:\sigma^2<\sigma^2_0 \end{aligned} $$ +> 一半会直接鬼畜样本的方差,这样不需要通过检验统计量+样本的值计算各个方差。 +### 假设检验$\chi^2$检验 + +1. 命题假设$H_0:\sigma^2\in\Theta_0,H_1:\sigma^2\in\Theta_1$ +2. 检验统计量$\chi^2=\frac{(n-1)S^2}{\sigma_0^2}$ +3. 根据检验水平计算拒绝域的临界值$\\双侧检验W=\{(x_1,\dotsm,x_n:\chi^2\leq\chi^2_{\frac{\alpha}{2}}\cup\chi^2\geq \chi^2_{1-\frac{\alpha}{2}}\}\\$ +4. 计算样本的检验统计量的值,与拒绝域的临界值对比。 + ## 4 两个总体-均值相等 diff --git a/概率论与数理统计/第25节 距离判别.md b/概率论与数理统计/第25节 距离判别.md new file mode 100644 index 00000000..36a2056d --- /dev/null +++ b/概率论与数理统计/第25节 距离判别.md @@ -0,0 +1,37 @@ +# 距离判别 + +> 分类:数据集带标签 +> 聚类:无标签数据集 + +## 1 欧氏距离与马氏距离 + +### 定义 +* 判别分析:根据样品的观察值判定归属。 +* 距离判别原理:对距离进行规定,就近原则判定样品的归属。 +### 定义:欧氏距离 +$$ +d(x,y)=\sqrt{\sum_{i=1}^n(x_i-y_i)^2} +$$ +> 缺点:指标的量纲不同,意义不同。距离会因各个指标单位的变化而改变 + +### 定义:马氏距离 +* 声明 +$$ +p元总体G的均值\mu和协方差矩阵\Sigma(\Sigma>0) +$$ + +### 性质 + + +### 判别的优劣-回报法 +使用训练集检验判别的优劣 +### 判别的优劣-交叉验证法 +将带标签的数据分为两部分,训练集和测试集。 + +分成多份。分别计算f + +### 判别的优劣-刀切法 +轮流剔除,得到多个模型,用被剔除的数据进行检验。统计误判率。 +## 2 两个总体的距离 + +## 3 多个总体的距离 \ No newline at end of file diff --git a/概率论与数理统计/第26节 Bayes判别.md b/概率论与数理统计/第26节 Bayes判别.md new file mode 100644 index 00000000..b5982c54 --- /dev/null +++ b/概率论与数理统计/第26节 Bayes判别.md @@ -0,0 +1,15 @@ +# Bayes判别 + +## 1 错判风险ECM最小准则 + + +## 2 两个总体的bayes判别 + +### 定理:损失最小判别 + +* 声明 +$$ +总体G_1,G_2 +$$ +* 结论 +## 3 多个总体的bayes判别 \ No newline at end of file diff --git a/线性代数/0 线性代数概述.md b/线性代数/0 线性代数概述.md new file mode 100644 index 00000000..0d157742 --- /dev/null +++ b/线性代数/0 线性代数概述.md @@ -0,0 +1,106 @@ +# 线性代数 +线性代数究竟讲了个什么事情?线性方程组、向量、线性空间之间有什么关系?他们与矩阵有什么关系?为什么要在线性代数中讲到矩阵? +### 1. 映射=函数=变换=算子(在不同领域的不同称呼) + +通常我们说 变换(transformation)时,实际上指的是函数(function)f ,也成为一个算子或者映射,给它一定的输入,它会产生相应的输出。 + +在线性代数的场景中,变换(transformation)可以想象为输入某个向量,然后输出另一个向量的过程。 +### 线性方程、向量空间、线性空间关系 + +是同一个东西的不同表述。 + +线性方程的系数表示的输入向量,多组$[x_1,\cdots,x_n]$表示多组算子。$[y_1,y_2,\cdots,y_n]$表示变换后的结果。 + +向量空间。由多个线性无关的向量组成的向量组,称为向量空间。每一个向量表示一个算子。 + +线性空间。有多个线性无关的基底组成的线性空间。每一个基底表示一个算子。 + +### 线性变换的表示 + +一般来说,方阵能描述任意线性变换。线性变换,在一个线性空间中,将一个向量依次乘一组基底,则完成线性变换,得到另外一个向量。把一个平面想象为彼此间均匀且平行的网格,线性变换会让网格中的线条依然保持平行且均匀。 +$$ +[y_1,y_2,\cdots,y_n]^T=[a_1^T,a_2^T,\cdots,a_n^T]^T*[x_1,x_2,\cdots,x_n]^T\\ +其中a_i=[t_1,t_2,\cdots,t_n]是一个基底。 +$$ + + +### 线性变换的特点 + +线性变换保留了直线和平行线,但原点没有移动。线性变换保留直线的同时,其他的几何性质如长度、角度、面积和体积可能被变换改变了。从非技术意义上说,线性变换可能“拉伸”坐标系,但不会“弯曲”或“卷折”坐标系。 +1. 向量在变换后仍然是直线,不会被扭曲; +2. 原点不会发生移动。 + +### 线性变换和线性映射的区别 + +线性映射( linear mapping)是从一个向量空间V到另一个向量空间W的映射且保持加法运算和数量乘法运算,而线性变换(linear transformation)是线性空间V到其自身的线性映射。 + +### 线性代数 + +每一组线性方程的值,每一组线性无关的向量,每一组基底,都可以构成一个矩阵,统一为一个算子。所以线性代数主要讲了两件事。什么是线性变换。如何用矩阵工具解决线性变换问题。 + + + +## 1 常见矩阵 +* 单位矩阵 +* 对角矩阵 +* (上下)三角矩阵 +* 伴随矩阵 +* 逆矩阵 +* 正交矩阵 +* 对称矩阵 + +## 2 矩阵计算 +* 加减 +* 数乘 +* 矩阵乘积 +* 行列式 +* 逆 +* 秩 + +## 3 矩阵变换 +> 明白矩阵变换的实际意义和矩阵变换前后保留的性质。 +### 初等变换 +* 对调 +* 数乘 +* 对调数乘 + +$$ +B=A +$$ + + +### 相似变换 +$$ +P^{-1}AP=B +$$ + +> 线性无关/自由度/独立性的描述 +> $$ +det A \not = 0\\ +矩阵的秩\\ +线性无关方程\\ +线性无关向量(正交是比线性无关更强的条件)\\ +线性无关空间\\ +> $$ + + + +> 矩阵表示 +> $$ +A=\left[\begin{array}{cccc}{a_{11}} & {a_{12}} & {\cdots} & {a_{1 n}} \\ {a_{21}} & {a_{22}} & {\cdots} & {a_{2 n}} \\ {\vdots} & {\vdots} & {\ddots} & {\vdots} \\ {a_{m 1}} & {a_{m 2}} & {\cdots} & {a_{m n}}\end{array}\right] +> $$ +> $$ +A \cdot \vec{x}= +\left(\begin{array}{c} +{a_{11} x_{1}+a_{12} x_{2}+\cdots+a_{1 n} x_{n}}\\ +{a_{21} x_{1}+a_{22} x_{2}+\cdots+a_{2 n} x_{n}}\\ +{\vdots} \\ +{a_{m 1} x_{1}+a_{m 2} x_{2}+\cdots+a_{m n} x_{n}} +\end{array}\right) +> $$ +> $$ +A x=\lambda x +> $$ +> $$ +A=P^{-1} B P +> $$ \ No newline at end of file diff --git a/线性代数/1 矩阵行列式.md b/线性代数/1 矩阵行列式.md new file mode 100644 index 00000000..f55714fd --- /dev/null +++ b/线性代数/1 矩阵行列式.md @@ -0,0 +1,177 @@ +# 行列式 + +## 1 行列式与线性方程组 + +### 线性方程程组 +$$ +\begin{cases} + a_{11}x_1+a_{12}x_2=b_1\\ + a_{21}x_1+a_{22}x_2=b_2 +\end{cases}\\ +$$ + +### 行列式含义 + +$$ +\begin{vmatrix} + a_{11} & a_{12}\\ + a_{21} & a_{22} +\end{vmatrix} += a_{11}a_{22}-a_{12}a_{21} +\\ +\begin{vmatrix} + a_{11} & a_{12} & a_{13}\\ + a_{21} & a_{22} & a_{23}\\ + a_{31} & a_{32} & a_{33} +\end{vmatrix}\\ += a_{11}a_{22}a_{33}+a_{12}a_{23}a_{31}+a_{13}a_{21}a_{32}\\ +-a_{12}a_{21}a_{33}-a_{11}a_{23}a_{32}-a_{13}a_{21}a_{32} +$$ + +### 行列式表示线性方程组的解 +$$ +D = \begin{vmatrix} + a_{11} & a_{12}\\ + a_{21} & a_{22} +\end{vmatrix} + +D_1=\begin{vmatrix} + b_1 & a_{12}\\ + b_2 & a_{21} +\end{vmatrix} + +D_2=\begin{vmatrix} + a_{11} & b_1\\ + a_{21} & b_2 +\end{vmatrix}\\ + +x_1=\frac{D_1}{D},x_2=\frac{D_2}{D} +$$ + +## 2 全排类和逆序数 +### 全排列 +把n个不同的元素排成一列,成为全排列 + +### 逆序 +* 当两个元素的先后次序与标准次序不同时,则存在一个逆序。 +* 一个排列中所有逆序的总数,成为逆序数。 +* 逆序数为奇数的排列称为奇排列,逆序数为偶数的排列称为偶排列。 + +## 3 n阶行列式定义 + +### n阶行列式定义 +$$ +\begin{vmatrix} +{a_{11}} & {a_{12}} & {\cdots} & {a_{1 n}} \\ +{a_{21}} & {a_{22}} & {\cdots} & {a_{2 n}} \\ +{\vdots} & {\vdots} & {\ddots} & {\vdots} \\ +{a_{m 1}} & {a_{m 2}} & {\cdots} & {a_{m n}} +\end{vmatrix} +=(-1)^ta_{1p_1}\cdots a_{np_n} +$$ +t为逆序数。记作det(A) + +### n阶行列式性质 + +* 对角行列式 +* 上(下)三角行列式与对角行列式的值相同。 + +## 4 对换 +### 定义:对换 +* 在排列中将任意两个元素对调,其余元素不变,称为对换。 +* 将相邻的两个元素对换,称为相邻对换。 + +### 定理:元素对换 + +一个排列中任意两个元素对换,奇偶性改变。奇排列变换为标准排列的对换次数为奇数,偶排列变为标准排列的对换次数是偶数。 + +## 5 行列式的性质 + +* 性质1:行列式与转置行列式相等。 +$$ +D=D^T +$$ +* 性质2:互换行列式的两行(列),行列式变号。如果有两行或者两列完全相同,则行列式等于零。 +* 性质3:行列式乘一个数,等于行列式的某一行(列)乘这个数。行列式某一行(列)元素的公因子可以提取到行列式外。 +* 性质4:行列式中如果有两行成比例,则行列式等于零。 +* 性质5:如果第i行(列)元素都是两数之和,则行列式能够拆成第i行(列)不同的两个行列式之和。 +* 性质6:行列式的某一列,各个元素乘以同一个数,然后加到另一列上,行列式不变。 +$$ +\begin{vmatrix} +{a_{11}} & {a_{12}} & {\cdots} & {a_{1 n}} \\ +{a_{21}} & {a_{22}} & {\cdots} & {a_{2 n}} \\ +{\vdots} & {\vdots} & {\ddots} & {\vdots} \\ +{a_{m 1}} & {a_{m 2}} & {\cdots} & {a_{m n}} +\end{vmatrix} += +\begin{vmatrix} +{a_{11}} & {a_{12}} & {\cdots} & {a_{1 n}} \\ +{a_{21}} & {a_{22}} & {\cdots} & {a_{2 n}} \\ +{\vdots} & {\vdots} & {\vdots} & {\vdots} \\ +{a_{k1}}+ka_{i1} & {a_{k2}+ka_{i2}} & {\cdots} & {a_{kn}+ka_{in}} \\ +{\vdots} & {\vdots} & {\ddots} & {\vdots} \\ +{a_{m 1}} & {a_{m 2}} & {\cdots} & {a_{m n}} +\end{vmatrix} +$$ +## 6 行列式按行列展开 +### 定义:余子式 +在n阶行列式中,把(i,j)元素a(i,j)所在的第i行第j列划去 ,留下的n-1阶行列式,叫做(i,j)元素a(i,j)的代数余子式,记作$M_{ij}$。 + +代数余子式$A_{ij}=(-1)^{i+j}M_{ij}$ + +### 定理:余子式计算 + +一个n阶行列式,如果其中第i行所有元素除$a_{ij}$外都为零,那么行列式等于$a_{ij}$与它的代数余子式的成绩。 +$$ +D = a_{ij}A_{ij} +$$ + +### 定理:行列式的余子式表示,行列式按行(列)展开法则 + +行列式等于它的任一行的各元素与对应的代数余子式乘积之和。即: +$$ +D = a_{i1}A_{i1}+\cdots+a_{in}A_{in} +$$ + +### 范德蒙行列式 + +$$ +D_n= +\begin{vmatrix} +{a_{11}} & {a_{12}} & {\cdots} & {a_{1 n}} \\ +{a_{21}} & {a_{22}} & {\cdots} & {a_{2 n}} \\ +{\vdots} & {\vdots} & {\ddots} & {\vdots} \\ +{a_{m 1}} & {a_{m 2}} & {\cdots} & {a_{m n}} +\end{vmatrix} += +\prod_{n\geq i>j\geq l}(x_i - x_j) +$$ + +### 定理:行列式的其他展开 + +行列式某一行的元素与玲一行的对应元素的代数余子式乘积之和等于零。 + +## 7 克拉默法则 +### 定理:克拉默法则 +如果线性方程组的系数行列式不等于零,则方程组有唯一解。 + +### 定义:齐次方程组 + +线性方程组常数项不全为零时,称为非齐次线性方程组。常数项全为零时,叫做其次线性方程组。 + +### 定理:齐次方程组 +* 如果齐次方程组的系数行列式不等于零,则齐次线性方程组没有非零解。 +* 如果其次线性方程组有非零解,则它的系数行列式必为零。 + + +## 8 常见题型及解法 + +### 求行列式 + +* 暴力解 +* 利用点数余子式解 + + +### 解线性方程组 + +* 克拉默法则 diff --git a/线性代数/2 矩阵基本运算.md b/线性代数/2 矩阵基本运算.md new file mode 100644 index 00000000..f9d0ca0d --- /dev/null +++ b/线性代数/2 矩阵基本运算.md @@ -0,0 +1,270 @@ +# 矩阵及其运算 + +## 1 矩阵概念 + +### 定义:矩阵 + +$$ +A=\begin{bmatrix} + {a_{11}} & {a_{12}} & {\cdots} & {a_{1 n}} \\ + {a_{21}} & {a_{22}} & {\cdots} & {a_{2 n}} \\ + {\vdots} & {\vdots} & {\ddots} & {\vdots} \\ + {a_{m 1}} & {a_{m 2}} & {\cdots} & {a_{m n}} +\end{bmatrix} +$$ + +* m行n列矩阵,$m \times n$矩阵,记作$A_{m\times n}$ +* 矩阵中的第i行第j列称为A的元素,记作$a_{ij}$ + +### 矩阵分类 +* 实矩阵、复矩阵:元素都是实数的矩阵称为实矩阵,元素是复数的矩阵称为复矩阵。 +* 方阵:m=n的矩阵称为n阶方阵。 +* 行列向量:只有一行的矩阵称为行向量,只有一列的矩阵称为列向量。记作 +$$ +A=(a_1,\cdots,a_n)\\ +B= \left( +\begin{array}{c} + b_1 \\ + \vdots\\ + b_n\\ +\end{array} +\right) +$$ +* 同型矩阵:行数、列数都相等。 +* 矩阵相等:同型矩阵,对应元素相等。 +* 零矩阵:元素都是零的矩阵称为零矩阵。 +* 对角矩阵:不在主对角线上的元素都是0。 +* 单位矩阵:主对角线上的元素都是1,不再主对角线上的元素都为零。 +> 矩阵与行列式说明:矩阵是一个数据,行列式是方阵的一个运算。 + + +### 线性变换与矩阵运算 + +* 线性变换 +$$ +y_1={a_{11} x_{1}+a_{12} x_{2}+\cdots+a_{1 n} x_{n}}\\ +y_2={a_{21} x_{1}+a_{22} x_{2}+\cdots+a_{2 n} x_{n}}\\ +{\vdots} \\ +y_n={a_{m 1} x_{1}+a_{m 2} x_{2}+\cdots+a_{m n} x_{n}} +$$ +* 矩阵表示 +$$ +A=\begin{bmatrix} + {a_{11}} & {a_{12}} & {\cdots} & {a_{1 n}} \\ + {a_{21}} & {a_{22}} & {\cdots} & {a_{2 n}} \\ + {\vdots} & {\vdots} & {\ddots} & {\vdots} \\ + {a_{m 1}} & {a_{m 2}} & {\cdots} & {a_{m n}} +\end{bmatrix} +$$ +$$ +X=(x_1,\cdots,x_n)^T\\ +Y=(y_1,\cdots,y_n)^T\\ +$$ +* 线性变换的矩阵表示 +$$ +Y=AX +$$ +## 2 矩阵运算 +> 矩阵的加法与数乘是线性运算。阶数不会发生变化。 +> 矩阵是线性变换的一种表示形式。每一种矩阵运算都对应线性变换的一种变化。 +### 矩阵加法 + +同型矩阵A与B相加,对应位置的每个元素相加,记作$A+B$ + +$$ +A+B=\begin{bmatrix} + {a_{11}+b_{11}} & {a_{12}+b_{12}} & {\cdots} & {a_{1n}+b_{1n}} \\ + {a_{21}+b_{21}} & {a_{22}+b_{22}} & {\cdots} & {a_{2 n}+b_{2 n}} \\ + {\vdots} & {\vdots} & {\ddots} & {\vdots} \\ + {a_{m 1}+b_{m 1}} & {a_{m 2}+b_{m 2}} & {\cdots} & {a_{m n}+b_{m n}} +\end{bmatrix} +$$ + +* $A+B=B+A$ +* (A+B)+C=A+(B+C) +* 负矩阵$-A=(-a_{ij}$ + +### 矩阵数乘 + +实数$\lambda$与矩阵A的成绩记作$\lambda A 或 A\lambda$ + +$$ +\lambda A=\begin{bmatrix} + \lambda {a_{11}} & \lambda {a_{12}} & {\cdots} & \lambda {a_{1n}} \\ + \lambda {a_{21}} & \lambda {a_{22}} & {\cdots} & \lambda {a_{2n}} \\ + {\vdots} & {\vdots} & {\ddots} & {\vdots} \\ + \lambda {a_{m1}} & \lambda {a_{m2}} & {\cdots} & \lambda {a_{mn}} +\end{bmatrix} +$$ + +* $(\lambda\mu)A=\lambda(\mu A)$ +* $(\lambda+\mu)A=\lambda A + \mu A$ +* $\lambda(A+B)=\lambda A+\lambda B$ + +### 矩阵乘法 + +矩阵$A_{m\times s},B_{s\times n}$。矩阵A,B的乘积是一个$m\times n$的矩阵$C_{m\times n}$ +$$ +C = AB +$$ +> 关于维度的理解:一维是列向量,因为一维是向下在行的数量上拓展,列上不拓展。二维是在列的方向上拓展,列数增加。 + +* 不满足交换律$AB\neq BA$ +* $(AB)C=A(BC)$ +* $\lambda(AB)=(\lambda A)B=A(\lambda B)$ +* $A(B+C)=AB+AC$ +* $AI=IA=A$ +* 矩阵的幂:$A^{k+l}=A^{k}A^l$ + + +### 矩阵转置 + +将矩阵的行列互换,得到转置矩阵。 +$$ +A^T +$$ + +* $(A^T)^T=A$ +* $(A+B)^T=A^T+B^T$ +* $(\lambda A)^T=\lambda(A)^T$ +* $(AB)^T=B^TA^T$ + +### 矩阵行列式 + +n阶方阵A所有的元素构成的行列式。称为方阵A的行列式。记作$|A|或\det A$ + +* $|A^T|\|A|$ +* $|\lambda A|=\lambda^nA$ +* $|AB|=|A||B|$ +* $det A = 0$奇异矩阵。$det A \not = 0$非奇异矩阵 + +行列式A的各个元素的代数余子式构成矩阵称为伴随矩阵。 +$$ +A^* = \begin{bmatrix} + {A_{11}} & {A_{12}} & {\cdots} & {A_{1 n}} \\ + {A_{21}} & {A_{22}} & {\cdots} & {A_{2 n}} \\ + {\vdots} & {\vdots} & {\ddots} & {\vdots} \\ + {A_{m 1}} & {A_{m 2}} & {\cdots} & {A_{m n}} +\end{bmatrix} +$$ + +$$ +A^*A=AA^*=|A|E +$$ +### 矩阵共轭 +当 $A=(a_{ij})$是复矩阵时,用$\overline{a_{ij}}$表示$a$的共轭复数 + +$$ +\overline{A}=(\overline{a}_{ij}) +$$ +* $\overline{A+B}=\overline{A}+\overline{B}$ +* $\overline{\lambda A}=\overline{\lambda}\cdot\overline{A}$ +* $\overline{AB}=\overline{A}\cdots\overline{B}$ + +### 转角公式 + +$$ +A=\begin{bmatrix} + \cos \varphi & -\sin \varphi \\ + \sin \varphi & \cos \varphi +\end{bmatrix}\\ +\overrightarrow{OP}=(x,y)^T\\ + +A\cdot\overrightarrow{OP}表示转过\varphi角度 +$$ + +其中转角公式具有如下性质 + +$$ +A^n = \begin{bmatrix} + \cos n\varphi & -\sin n\varphi \\ + \sin n\varphi & \cos n\varphi +\end{bmatrix}\\ +$$ + +## 2 矩阵的逆 +### 线性变换的逆变换与矩阵关系 + +### 定义:矩阵的逆 +n阶矩阵A,B如果: +$$ +AB=BA=E +$$ +A是可逆的,B是A的逆矩阵。 + +### 定理:行列式不为0 +若矩阵A可逆,则$|A|\not = 0$。若$|A|\not = 0$则矩阵A可逆。 + +$$ +A^{-1}=\frac{1}{|A|}A^*\\ +A^* 为伴随矩阵。 +$$ + +### 性质:矩阵的逆 +* $(A^{-1})^{-1}=A$ +* $(\lambda A)^{-1}=\frac{1}{\lambda}A^{-1}$ +* $(AB)^{-1}=B^{-1}A^{-1}$ +* $(A^T)^{-1}=(A^{-1})^T$ + +### 矩阵的相似变换 + +$$ +A^n = P B^n P^{-1} +$$ +用来解决一下问题 + +$$ +\varphi(A)=a_0E + a_1 A^1+\dots+a_nA^n\\ +=P a_0E P^-1 + \dots + P a_n B^n P^{-1}\\ +=P(\varphi(B))P^{-1} +$$ + +如果 B是对角阵,则 +$$ +B=diag(\lambda_1,\cdots,\lambda_n)\\ +B^k=diag(\lambda_1^k,\cdots,\lambda_n^k) +$$ + +## 3 矩阵分块 + +$$ +A = \begin{bmatrix} + {A_{11}} & {A_{12}} & {\cdots} & {A_{1 n}} \\ + {A_{21}} & {A_{22}} & {\cdots} & {A_{2 n}} \\ + {\vdots} & {\vdots} & {\ddots} & {\vdots} \\ + {A_{m 1}} & {A_{m 2}} & {\cdots} & {A_{m n}} +\end{bmatrix}\\ + +B = \begin{bmatrix} + {B_{11}} & {B_{12}} & {\cdots} & {B_{1 n}} \\ + {B_{21}} & {B_{22}} & {\cdots} & {B_{2 n}} \\ + {\vdots} & {\vdots} & {\ddots} & {\vdots} \\ + {B_{m 1}} & {B_{m 2}} & {\cdots} & {B_{m n}} +\end{bmatrix} +$$ +其中$A_{ij},B_{ij}$行列数相同,划分相同 + +### 性质:加法 + +$$ +A+B= (A_{ij}+B_{ij}) +$$ +### 性质:数乘 +$$ +\lambda A = (\lambda A_{ij}) +$$ +### 性质:乘积 +$$ +AB=(C_{ij})\\ +C_{ij}=\sum_{k=1}^sA_{ik}B_{kj} +$$ +### 性质:转置 +$$ +A^T=((A_{ji})^T) +$$ + +## 4 常见题型 + +### 求矩阵的逆 +* 定义法,通过伴随矩阵与矩阵的乘积 +* 初等变换法,通过初等变换,对角单位阵,得到矩阵的逆。 diff --git a/线性代数/3 矩阵初等变换.md b/线性代数/3 矩阵初等变换.md new file mode 100644 index 00000000..b68b7f32 --- /dev/null +++ b/线性代数/3 矩阵初等变换.md @@ -0,0 +1,48 @@ +# 矩阵的初等变换 + +## 1 矩阵的初等变换 + +### 初等变换的定义 + +矩阵的初等行变换$A\sim^r B$、初等列变换$A\sim^c B$ +1. 对调两行 +2. 数乘某一行 +3. 某一行元素的k倍加到另外一行 + +初等行变换与初等列变换统称初等变换。记作$A\sim B$ + +### 初等变换的性质 + +1. 反身性$A \sim A$ +2. 对称性$A\sim B,B\sim A$ +3. 传递性$A\sim B,B\sim C,A\sim C$ + +### 初等变换的形式 + +* 行阶梯形式:阶梯型。 +* 行最简形式:每一行第一个非零元素为1,且该列其他元素为零。 +* 标准形式:行变换后,进行列变换,到达行最简形式,列最简形式。左上角单位阵 +$$ +F=\begin{bmatrix} + E_r & 0\\ + 0 & 0 +\end{bmatrix}_{m\times n} +$$ + +### 初等变换的乘积表示 + +* $A\sim^r B$的充要条件存在m阶可逆矩阵P,使$PA = B$ +* $A\sim^c B$的充要条件存在n阶可逆矩阵Q,使$AQ = B$ +* $A\sim B$的充要条件存在m阶可逆矩阵P,存在n阶可逆矩阵Q,使$PAQ =B$ + +### 初等矩阵 + +由单位阵E经过一次初等变换得到的矩阵称为初等矩阵。 + +性质: +* 对矩阵进行一次初等行变换,等价于左乘一个初等矩阵。对矩阵进行一次列变换,等价于右乘一个初等矩阵。 +* 矩阵可逆的充要条件,存在有限个初等矩阵$P_1,\cdots,P_n$使得$A=P_1\cdots P_n$ +* 方阵A可逆的充要条件是$A\sim^r E$ + +## 2 矩阵的秩 + diff --git a/线性代数/4 向量空间.md b/线性代数/4 向量空间.md new file mode 100644 index 00000000..81834f8b --- /dev/null +++ b/线性代数/4 向量空间.md @@ -0,0 +1,102 @@ +# 向量 + + +## 7 向量运算 + +### 定义:向量内积 +$$ +x=(x_1,\cdots,x_n)^T\\ +y=(y_1,\cdots,y_n)^T\\ +[x,y]=x^Ty=x_1y_1+\cdots+x_ny_n +$$ +[x,y]称为向量的内积。 + +### 性质:向量内积 + +1. $[x,y]=[y,x]$ +2. $\lambda[x,y]=[\lambda x,y]$ +3. $[x+y,z]=[x,z]+[y,z]$ +4. $x=\overrightarrow{0},=>[x,x]=0\\x \not =\overrightarrow{0},=>[x,x]\not =0$ +5. 施瓦茨不等式:$[x,y]^2\geq [x,x]+[y,y]$ + +### 定义:向量长度(范数) + +$$ +||x||=\sqrt{[x,x]}=\sqrt{x_1^2+\cdots+x_n^2} +$$ + +### 性质:向量长度 + +1. 非负性:$x=\overrightarrow{0},=>||x||=0\\x \not =\overrightarrow{0},=>||x||\not =0$ +2. 齐次性:$||\lambda x||=\lambda ||x||$ +3. 三角不等式:$||x+y||\leq ||x||+||y||$ + +### 性质:向量内积的几何意义 +* 向量内积表示一个向量在另一个向量上投影的积$[x,y]=||x||\cdot||y|| \cos \theta$ +* n维向量x,y的夹角:$\cos\theta = \frac{[x,y]}{||x||\cdot||y||}$ + +### 定义:正交向量 + +当n维向量x,y的夹角为90,即[x,y]=0时,称向量x,y正交 + +### 定理:线性无关向量与向量正交 + +若n为向量$a_1,a_2,\cdots,a_r$是一组两两正交的向量,则这组向量线性无关。 + + +### 定义:规范正交基 + +* 条件 +$$ +n维向量e_1,\cdots,e_r是向量空间V的一个基(线性无关)\\ +e_1,\cdots,e_r两两正交\\ +e_1,\cdots,e_r都是单位向量 +$$ +* 结论 +$$ +e_1,\cdots,e_r是向量空间V的一个规范正交基\\ +由一组基得到一组规范正交基的过程称为规范正交化。 +$$ + +### 定理:施密特正交化 + +1. 正交化 +$$ +每次减去与前一项交叉的部分。\\ +b_1 = a_1 \\ +b_2 = a_2 - \frac{[a_2,b_1]}{[b_1,b_1]}b_1\\ +\cdots\\ +b_n = a_n - \frac{[a_n,b_{n-1}]}{[b_{n-1},b_{n-1}]}b_{n-1} +$$ +2. 规范化 +$$ +e_1 = \frac{b_1}{||b_1||}\\ +\cdots\\ +e_n = \frac{b_n}{||b_n||} +$$ + +### 定义:正交矩阵 + +$$ +A^T\cdot A=E\\ +A\cdot A^T=E\\ +A^T=A^{-1}\\ +$$ +则称A为正交矩阵。 + + +### 性质:正交矩阵 + +1. A的列向量与行向量都是单位向量,且两两正交。 +2. 若A为正交矩阵,则$A^{-1},A^T$都是正交矩阵,且$det A = |A|=1$ +3. 若A与B为正交阵,则AB也为正交阵。 + +### 定义:正交变换 + +若P为正交矩阵,则$y=Px$称为正交变换。 + +### 性质:正交变换 +* ||y||=||x|| + + + diff --git a/线性代数/5 矩阵相似变换.md b/线性代数/5 矩阵相似变换.md new file mode 100644 index 00000000..58330cb7 --- /dev/null +++ b/线性代数/5 矩阵相似变换.md @@ -0,0 +1,145 @@ +# 矩阵相似变换 + +## 1 特征值和特征向量 +> 应用,方阵的对角化,解微分方程 + +### 定义:特征值和特征向量 + +* 声明 + +$$ +A是n阶矩阵\\ +\lambda 数\\ +x是n维向量 +$$ +* 条件 +**特征表达式** +$$ +Ax=\lambda x +$$ +* 结论 +$$ +\lambda 是矩阵A的特征值\\ +x是矩阵A的特征向量。 +$$ +### 性质:特征值特征向量 +* 同一个特征值的所有特征向量的非零线性组合,仍是特征向量。 +* 特征值的性质: +$$ +\lambda_1+\cdots+\lambda_n=a_1+\cdots+a_n\\ +\lambda_1\cdots\lambda_n=|A|=det A +$$ + +### 定理:特征值、特征向量、矩阵的线性变换 + +$$ +\lambda 是矩阵A的特征值,p是属于lambda的特征向量 +$$ + +* $k\lambda 是kA的特征值,p是kA属于k\lambda的特征向量$ +* $\lambda^k是A^k的特征值,p是A^k属于\lambda^k的特征向量$ +* $\frac{1}{\lambda}是A^{-1}的特征值$ +* $\varphi(A)是A的m次多项式,\varphi(\lambda)是\varphi(A)的特征值,p是\varphi(A)属于\varphi(\lambda)的特征向量$ + +### 计算:特征值和特征向量 +特征表达式的另一种表示方法 +$$ +(A-\lambda E)\overrightarrow{x}=\overrightarrow{0} +$$ + +因为是有n个未知数的n个线性方程的齐次线性方程组,有零解的充要条件是系数行列式等于零。**特征方程**成立 +$$ +|A-\lambda E|=0 +$$ +含有一个未知数的高阶方程,解得有多个重根。每个重根对应一个特征向量。特征向量不唯一,需要转化为模长为1的向量。 + +### 定理:特征向量线性无关 +* 声明 +$$ +\lambda_1,\cdots,\lambda_m是m个特征值\\ +p_1,\cdots,p_m是m个特征向量\\ +$$ +* 条件 +$$ +\lambda_1,\cdots,\lambda_m各不相等 +$$ +* 结论 +$$ +p_1,\cdots,p_m线性无关 +$$ + +## 3 相似矩阵 + +### 定义:相似变换 +* 声明 +$$ +A,B是n阶矩阵\\ +P是可逆矩阵 +$$ +* 条件 +$$ +P^{-1}AP=B +$$ +* 结论 +$$ +P^{-1}AP是对A的相似变换。\\ +B是A的\textbf{相似矩阵}\\ +P是\textbf{变换矩阵} +$$ + +### 定理:相似变换特征不变性 + +若n阶矩阵A与B相似。则A,B的特征值和特征向量相同。 + +### 定理:相似对角化 + +若n阶矩阵A与对角阵$\Lambda$相似,则A的n个特征值就是对角阵的元素值。**特征值对角阵$\Lambda$** +$$ +\Lambda=\begin{bmatrix} + \lambda_1 &&&\\ + & \lambda_2&&\\ + &&\cdots&\\ + &&&\lambda_n +\end{bmatrix} +$$ +并且相似变换P是那个特征向量组成的特征矩阵。 +$$ +P=(p_1,p_2,\cdots,p_n) +$$ +### 定理:相似对角化的充要条件 + +n阶矩阵A与特征值对角阵相似的充分必要条件,A有n个线性无关的特征向量。 + +若n阶矩阵A的n个特征值不相等,则A通过变换矩阵(特征向量矩阵)与特征值对角阵相似。 + +## 4 对称矩阵的对角化 +> 使用对称矩阵强化了相似对角化存在定理。简化相似对角的充分条件。 +### 定理:对称阵 + +对称阵的特征值为实数。 + +### 定理:对称阵特征向量正交 + +* 条件 + +$$ +\lambda_1,\lambda_2是对称阵A不相等的两个特征值。\\ +p_1,p_2是其对应的特征向量。 +$$ +* 结论 + +$$ +p_1,p_2正交 +$$ + +### 定理:对称阵特征对角矩阵存在 + +* 条件 +$$ +A 为对称阵,必有正交阵P,\\ +使得P^{-1}AP=P^TAP=\Lambda\\ +其中\Lambda是A中以n个特征值为对角元素的特征值对角阵。 +$$ +* 结论 + + diff --git a/线性代数/6 线性空间.md b/线性代数/6 线性空间.md new file mode 100644 index 00000000..e69de29b diff --git a/计算机网络实验/16 综合组网原理.md b/计算机网络实验/16 综合组网原理.md new file mode 100644 index 00000000..65fe5d3b --- /dev/null +++ b/计算机网络实验/16 综合组网原理.md @@ -0,0 +1,125 @@ +# 综合组网实验 + + +## 1 网络需求分析 + +### 任务 +* 网络建设目标分析 +* 网络应用约束分析 +* 网络技术分析 +* 网络规格参数分析等 + +### 手段 +* 了解应用背景 +* 查询技术文档 +* 与客户交流 + +## 2 网络规划设计 + +## 指标的分析和评估 +* 网络的规模 +* 网络的结构 +* 网络管理 +* 网络的扩展 +* 网络安全 +* 外部网络的互联 + +### 分许报告 +* 网络的规模 +* 该方案的优点 +* 现有网络状况 +* 网络的运行方式 +* 安全性要求 +* 网络可提供的应用 +* 响应时间 +* 可靠性 +* 节点的分布 +* 扩展性 + + +## 3 网络系统设计 + +### 内容 + +* 网络系统需求:对网络需求进行分类 +* 网络体系结构的设计:传输方式、客户接口、服务器、网络划分、互联设备。使用体系结构图表示结果。 +* 网络拓扑结构设计:综合性、高可靠性、高性能、层次性、支持qos、安全性、扩展性、开放性、标准化、实用性。 +* 网络安全性设计;网络层安全、系统安全、客户安全、应用程序安全、数据安全。 + + +## 4 网络设备选型 + +### 主要设备 + +工作站、服务器、路由器、交换机/集线器、共享设备、网络适配器、加密设备、 UPS电源 + +### 选取原则 +* 采用的网络技术 +* 支持的网络应用 +* 设备在网络中的功能和所处位置 + +## 5 系统集成 + +* 系统逻辑结构图的设计 +* 项目及分包商的管理 +* 硬件和软件产品的采购 +* 开发环境的建立 +* 应用软件的开发 +* 应用系统的安装、测试、实施和培训 + +## 6 综合布线 + +### 作用 +* 网络的性能 +* 网络的投资 +* 网络的使用 +* 网络的维护 + +## 7 接入技术 + +### 主要技术 +* 基于双绞线的以太网接入技术 +* 基于双绞线的ADSL技术 +* 基于HFC网的CableModem技术 +* 光纤接入技术 + + +## 8 IP地址规划和子网划分 + +### 划分方式 +* 顺序分配 +* 按行政分配 +* 按地域分配 +* 按拓扑方式分配 + +### 分配原则 +* 管理便捷原则 +* 地域原则 +* 业务原则 +* 地址节省原则 + +## 9 路由设计 + +### 静态路由 + +### 动态路由 +包括:RIP协议,OSPF协议,BGP协议 +* 路由能在选取的各种IGP之间进行快速而简捷的切换 +* 尽量少的流量占用 +* 优先考虑适应能力和强壮性 +* 充分利用地址资源 +* 考虑选取能用于不同AS之间的协议 +* 使用路由策略控制路由的发布。 + +## 10 网络可靠性设计 + +### 设备本身可靠性 +冗余设计,双处理板、双交换网板、多个电源备份。 +### 链路备份 +* WAN链路备份 +* LAN链路备份:STP实现局域网链路备份,链路聚合实现备份 +* 路由协议备份 +### 路由备份 + +### 设备备份 +* VRRP,将一组多态路由器组成的虚拟路由器,称为备份组。 diff --git a/计算机网络实验/17 综合组网实验.md b/计算机网络实验/17 综合组网实验.md new file mode 100644 index 00000000..360611a9 --- /dev/null +++ b/计算机网络实验/17 综合组网实验.md @@ -0,0 +1,271 @@ +# 综合组网试验 + +## 1 总体规划设计 + +### 系统需求和设计目标 +6层楼约30个机房约1600多台计算机,为一般网络应用、监控、服务器、存储、信息发布、电子教室、中控和投影等多个系统提供网络平台 + +1. 将整个实验中心机房连成一个相对独立的局域网,保证互联互通、学生自由上机、正常上网、刷卡系统、网络服务器、考试系统的正常运行。 +2. 满足多媒体教学、流媒体教学的需要,保证音、视频的流畅播放,确保良好的服务质量。 +3. 网络的连通性完全可控,要求满足某些机房考试时禁止该机房访问互联网,而其他机房正常上课不受影响。 +4. 网络支持组播应用,能够满足机房管理软件等教学相关应用的需求。 +5. 网络设备支持抗ARP病毒攻击、广播风暴抑制、DHCP协议、IPv6协议等功能。 +6. 所有网络设备都要能够被实时监控和管理。 + + +### 总体规划 + +1. 信息平台网络采用TCP/IP体系结构,以满足与其他网络系统的互联互通。 +2. 分层次的方法划分网络 +3. 不同层次使用不同级别的千兆交换机,出口路由器采用中高端路由器 +4. 采用地址转换技术(NAT)规划网络。IP地址的划分采用每个机房一个网段。NAT采用基于端口的NAT-PT技术。申请至少128个公网地址的地址池。 +5. 采用ACL控制机房的访问 +6. 采用支持IPv6协议、DHCP协议、路由协议、组播协议及安全性高的设备。 + +![](image/综合组网分层图.png) +### 网络拓扑规划 + + +![dd](image/综合组网拓扑图.png) + +## 2 网络详细设计 + +### 2.1 网络拓扑设计 +![](image/综合组网网络详细拓扑.png) +### 2.2 网络可靠性设计 + +* WAN链路备份 + * 用于为路由器的广域网接口提供备份(也可以用于局域网接口备份) + * 主接口:路由器上的任意一个物理接口或子接口,以及逻辑通道(Dialer口除外) + * 备份接口:当主接口出现故障时,多个备份接口可以根据配置的优先级来决定接替顺序;而且,备份接口具有分担负载功能 +* LAN链路备份 + * 使用二层交换机支持的STP协议、端口聚合技术等实现 + ![](image/综合组网链路备份.png) +* 路由备份 + * 动态路由协议能够自动发现路由,并生成路由表 + * 网络中有冗余路径,动态路由收敛需要时间、路由更新报文消耗网络资源等 + ![](image/综合组网动态路由备份.jpg) + +* 设备备份 + * VRRP(Virtual Router Redundancy Protocol,虚拟路由器冗余协议),一种LAN接入设备备份协议 + * 将局域网的一组多台路由器组织成一个虚拟路由器,称为备份组,优先级最高者为主用路由器,其余为备用 + ![dd](image/综合组网VRRP设备备份.png) + +### 2.3 设备选型 + +* 设备厂商选择 +* 接入层设备选型 +* 汇聚层设备选型 +* 核心层设备选型 + + +### 2.4 VLAN划分、网络地址、设备编号规划 +* VLAN划分 +* IP地址规划 + * 公网地址段: 115.25.141.129∽115.25.141.255/25 + * 私网地址段: 10.0.0.0/8网段 + * 对私网地址划分子网,每个实验室一个网段 + * 地址分配:地址中第二个字节代表楼层,第三个字节代表房间号,第四个字节表示其在房间中的位置编号 + + +* 网络设备采用统一编号: + * 核心路由器以SR6602-n方式编号 + * 核心交换机编号为S7503E-core + * 汇聚交换机以Fn-5800方式编号 + * 接入交换机以“F楼层号-房间号-设备型号-n”方式编号 + +### 2.5 路由设计 + +* 动态路由 + * 在拓扑图中的红色虚线标注区域,即各实验室内的接入交换机、各楼层的汇聚交换机F3-S5800、F4-S5800、F5-S5800、F6-S5800、F7-S5800、F8-S5800、核心交换机S7503E-core、核心路由器SR6602-1和SR6602-2的G0/0接口上配置OSPF动态路由协议 + +* 静态路由 + * 在出口路由器(即核心路由器)SR6602-1和SR6602-2上分别配置一条指向外部网络的默认路由 + +### 2.6 NAT地址转换与访问控制 + +* NAT地址转换 + * 115.25.141.128/25地址段中115.25.141.193-115.25.141.254/26用于公网地址,另外一段地址为其他服务器等设备使用 + * 保留私有地址段10.0.0.0/8作为内部IP地址 + * 在出口路由器SR6602-1和SR6602-2上配置NAT地址转换 + * 配置命令(包括5大条) + ``` + //配置地址池 + nat address-group 1 115.25.141.193 115.25.141.254 + //配置访问控制列表 + acl number 2001 + rule 0 permit source 10.0.0.0 0.255.255.255 + rule 1 deny + //在路由器出接口上绑定地址池和ACL + [interface e0/1]nat outbound 2001 address-group 1 + ``` +* 访问控制 + * 通过ACL设置访问控制考试实验室访问Internet,参考命令如下: + ``` + acl number 2001//禁止403机房上网 + rule 0 deny source 10.4.3.0 0.0.0.255 + rule 1 permit source 10.0.0.0 0.255.255.255 + rule 2 deny + ``` + +### 2.7 网络管理设计 +* 在平台内值班室501房间的一台PC机上安装H3C Quidview网管软件,作为网管服务器 +* 所有接入交换机、汇聚交换机、核心交换机和核心路由器是被管设备,配置SNMP协议,并指定Trap报文发送到上面管理服务器的IP地址 +``` +这里以核心交换机S7503E-core为例: +[S7503E-core]snmp-agent +[S7503E-core]snmp sys version v1 +[S7503E-core]snmp com write private +[S7503E-core]snmp com read public +[S7503E-core]snmp trap enable +[S7503E-core]snmp target-host trap address udp-domain 10.5.1.100 params securityname public +``` +### 2.8 组播设计 + +* 根据需求分析可知,组播应用对网络的要求是:同一实验室内、同一楼层不同实验室机器之间、不同楼层的机器之间都能进行组播传输 +* 在各接入交换机、汇聚交换机、核心交换机的各接口上都配置了PIM DM组播路由协议 +* 以汇聚交换机F3-S5800为例的配置请见教程 +``` +[F3-S5800]multicast routing-enable +[F3-S5800-]int vlan 30 +[F3-S5800-vlan-interface30]igmp enable +[F3-S5800-vlan-interface30]pim dm +[F3-S5800-]int vlan 301 +[F3-S5800-vlan-interface301]igmp enable +[F3-S5800-vlan-interface301]pim dm +[F3-S5800-]int vlan 302 +[F3-S5800-vlan-interface302]igmp enable +[F3-S5800-vlan-interface302]pim dm +[F3-S5800-]int vlan 303 +[F3-S5800-vlan-interface303]igmp enable +[F3-S5800-vlan-interface303]pim dm +[F3-S5800-]int vlan 304 +[F3-S5800-vlan-interface304]igmp enable +[F3-S5800-vlan-interface304]pim dm + +``` +### 2.9 网络布线与电源布线 + +* 网络布线 +* 电源布线及电源改造 + + +## 3 综合组网实验 +![](image/综合组网组网图.png) +### IP配置 +> 参考图 + +### VLAN划分 +> 参考图 + +### 路由实现 +* 在汇聚交换机、核心交换机、核心路由器上配置OSPF协议 +``` +# S2 S1所有端口启动OSPF,R1,R2内网端口启动OSPF +router id 1.1.1.1 +ospf +area 0 +netwrok 10.3.1.1 0.0.0.255 +network 10.3.2.1 0.0.0.255 +network 192.168.3.2 0.0.0.255 +``` +* 在路由器上配置到达外网的静态路由,并引入到OSPF协议当中 +``` +R1,R2配置前往外网的静态路由,并将静态路由引入到ospf协议当中。 +R1 +ip route-static 0.0.0.0 0.0.0.0 192.168.5.1 +[ospf]default-route-advertise cost 100 +R2 +ip route-static 0.0.0.0 0.0.0.0 192.168.5.1 +[ospf]default-route-advertise cost 200 +R1,R2引入默认路由S1,S2不需要配置默认路由 +``` + +### 可靠性实现 + +* 链路聚合+STP协议实现 +``` +stp enable + +interface bridge-aggregation 1 +link-aggregation mode dynamic + +interface Ethernet1/0/1 +port link-aggregation group 1 + +interface Ethernet1/0/2 +port link-aggregation group 1 + +inter bridge-aggregation 1 +port link-type trunk +port trunk permit vlan all +``` +* 设备备份VRRP实现 +``` +R1 +interface ethernet 0/0 +ip address 192.168.100.3 255.255.255.0 +vrrp vrid 11 virtual-ip 192.168.100.2 + +R2 +interface ethernet 0/0 +ip address 192.168.100.4 255.255.255.0 +vrrp vrid 11 virtual-ip 192.168.100.2 +vrrp vrid 11 priority 80 +``` +* 路由备份实现 +``` +[R1-OSPF-1]default-route-advertise cost 100 +# 将R1上的默认路由ip route-static 0.0.0.0 0.0.0.0 192.168.5.1引入OSPF +[R2-OSPF-1]default-route-advertise cost 200 + +``` +### NAT实现 +``` +//配置访问控制列表 +acl number 2001 +rule 0 permit source 10.0.0.0 0.255.255.255 +rule 1 deny source any +//配置地址池 + nat address-group 1 +address 192.168.5.140 + 192.168.5.144 +//在路由器出接口上绑定地址池和ACL +[interface e0/1]nat outbound 2001 address-group 1 +``` +### 访问控制列表 +``` +//禁止403机房上网 +acl number 2001 +rule 0 deny source 10.4.3.0 0.0.0.255 +rule 1 permit source 10.0.0.0 0.255.255.255 +rule 2 deny +``` +### 网络管理应用 +``` +[S7503E-core]snmp-agent +[S7503E-core]snmp sys version v1 +[S7503E-core]snmp com write private +[S7503E-core]snmp com read public +[S7503E-core]snmp trap enable +[S7503E-core]snmp target-host trap address udp-domain 10.5.1.100 params securityname public +``` +### 组播实现 +``` +[F3-S5800]multicast routing-enable +[F3-S5800-]int vlan 30 +[F3-S5800-vlan-interface30]igmp enable +[F3-S5800-vlan-interface30]pim dm +[F3-S5800-]int vlan 301 +[F3-S5800-vlan-interface301]igmp enable +[F3-S5800-vlan-interface301]pim dm +[F3-S5800-]int vlan 302 +[F3-S5800-vlan-interface302]igmp enable +[F3-S5800-vlan-interface302]pim dm +[F3-S5800-]int vlan 303 +[F3-S5800-vlan-interface303]igmp enable +[F3-S5800-vlan-interface303]pim dm +[F3-S5800-]int vlan 304 +[F3-S5800-vlan-interface304]igmp enable +[F3-S5800-vlan-interface304]pim dm +``` \ No newline at end of file diff --git a/计算机网络实验/image/综合组网VRRP设备备份.png b/计算机网络实验/image/综合组网VRRP设备备份.png new file mode 100644 index 00000000..28e34704 Binary files /dev/null and b/计算机网络实验/image/综合组网VRRP设备备份.png differ diff --git a/计算机网络实验/image/综合组网分层图.png b/计算机网络实验/image/综合组网分层图.png new file mode 100644 index 00000000..b7ffeae8 Binary files /dev/null and b/计算机网络实验/image/综合组网分层图.png differ diff --git a/计算机网络实验/image/综合组网动态路由备份.jpg b/计算机网络实验/image/综合组网动态路由备份.jpg new file mode 100644 index 00000000..3a6f57e3 Binary files /dev/null and b/计算机网络实验/image/综合组网动态路由备份.jpg differ diff --git a/计算机网络实验/image/综合组网动态路由备份.png b/计算机网络实验/image/综合组网动态路由备份.png new file mode 100644 index 00000000..c7b556cc Binary files /dev/null and b/计算机网络实验/image/综合组网动态路由备份.png differ diff --git a/计算机网络实验/image/综合组网动态路由备份.png.jpg b/计算机网络实验/image/综合组网动态路由备份.png.jpg new file mode 100644 index 00000000..132a2f15 Binary files /dev/null and b/计算机网络实验/image/综合组网动态路由备份.png.jpg differ diff --git a/计算机网络实验/image/综合组网拓扑图.png b/计算机网络实验/image/综合组网拓扑图.png new file mode 100644 index 00000000..8c2aea32 Binary files /dev/null and b/计算机网络实验/image/综合组网拓扑图.png differ diff --git a/计算机网络实验/image/综合组网组网图.png b/计算机网络实验/image/综合组网组网图.png new file mode 100644 index 00000000..500c9e53 Binary files /dev/null and b/计算机网络实验/image/综合组网组网图.png differ diff --git a/计算机网络实验/image/综合组网网络详细拓扑.png b/计算机网络实验/image/综合组网网络详细拓扑.png new file mode 100644 index 00000000..5a0e42bc Binary files /dev/null and b/计算机网络实验/image/综合组网网络详细拓扑.png differ diff --git a/计算机网络实验/image/综合组网链路备份.png b/计算机网络实验/image/综合组网链路备份.png new file mode 100644 index 00000000..cec4eb09 Binary files /dev/null and b/计算机网络实验/image/综合组网链路备份.png differ