入门-基础-算法第4版

1、前言

本书研究多种重要而实用的算法;和算法关系最紧密的是数据结构;本书使用java做为编程语言。

  • 基础编程模型:描述和实现算法所用到的语言特性、软件库和操作系统特性总称
  • 数据抽象并定义抽象数据类型:便于进行模块化编程
  • 三种基本抽象数据类型:背包、队列和栈
  • 性能:性能是算法研究的一个核心问题

算法第四版主要内容框架:

  1. 基础:包括Java编程模型、数据抽象、基本数据结构、集合类的抽象数据类型、算法性能分析的方法和一个案例分析
  2. 排序:有序的重新排列数组中的元素是非常重要的基础算法。我们会深入研究各种排序算法,包括插入排序、选择排序、希尔排序、快速排序、归并排序和堆排序。同时我们还会讨论另外一些算法,他们用于解决几个与排序相关的问题,例如优先队列、选举以及归并。
  3. 查找:从庞大的数据集中找到指定的条目也是非常重要的。我们将会讨论基本的和高级的查找算法,包括二叉查找树、平衡查找树和散列表。
  4. 图:图的主要内容是对象和他们的连接,连接可能有权重和方向。利用图可以为大量重要而困难的问题建模,因此图算法的设计也是本书的一个重要的研究领域。我们会研究深度优先搜索、广度优先搜索、连通性问题以及若干其他算法和应用,包括Kruskal和Prim的最小生成树算法、Dijkstra和Bellman-Ford的最短路径算法。
  5. 字符串:字符串是现代应用程序中的重要数据类型。我们将会研究一系列处理字符串的算法,首先是对字符串键的排序和查找的快速算法,然后是子字符串查找、正则表达式模式匹配和数据压缩算法。此外,在分析一些本身就十分重要的基础问题之后,这一章对相关领域的前沿话题也做了介绍。
  6. 背景:这一章将讨论与本书内容有关的若干其他前沿研究领域,包括科学计算、运筹学和计算理论。我们会介绍性地将一下基于事件的模拟、B树、后缀数组、最大流量问题以及其他高级主题。最后会讲一讲搜索问题、问题转化和NP完全性等算法研究的支柱理论,以及它们和本书的联系。

2、基础编程模型

我们学习选的方法是用Java编程语言编写的程序来实现算法。这样做的原因:

  • 程序是对算法精确、优雅和完全的描述
  • 可以通过运行程序来学习算法的各种性质
  • 可以在应用程序中直接使用这些算法

缺点:

  • 使分离算法的思想和实现细节变得困难

2.1、Java程序的基本结构

一段Java程序(类)或者是一个静态方法(函数)库,或者定义一个数据类型。要创建静态方法库和定义数据类型,会用到下面七种语法:

  • 原始数据类型:他们在计算机程序中精确地定义整数、浮点数和布尔值等。他们的定义包括取值范围和能够对相应的值进行的操作,它们能够被组合为类似于数学公式定义的表达式。
  • 语句:语句通过创建变量并对其赋值、控制运行流程或者引发副作用来进行计算。常用的一种语句
    • 声明
    • 赋值
    • 条件
    • 循环
    • 调用
    • 返回
  • 数组:数组是多个同种数据类型的集合。
  • 静态方法:静态方法可以封装并重用代码,使我们用独立的模块开发程序。
  • 字符串:字符串是一连串的字符,Java内置了对它们的一些操作。
  • 标准输入/输出:标准输入输出是程序与外界沟通的桥梁。
  • 数据抽象:数据抽象封装和重用代码,使我们可以定义非原始的数据类型,进而支持面向对象编程。

示例:二分查找

import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;

import java.util.Arrays;

// 导入一个Java库

public class BinarySearch {
    /**
     * 二分查找法:静态方法
     * @param key 参数变量,参数类型int
     * @param a    目标数组
     * @return     key在数组a中的位置;否则返回-1
     */
    public static int rank(int key, int[] a) {
        // 初始化声明语句
        int lo = 0;
        int hi = a.length - 1;
        // 循环
        while (lo <= hi) {
            int mid = (hi - lo) / 2 + lo;
            if (key < a[mid]) hi = mid - 1;
            else if (key > a[mid]) lo = mid + 1;
            else return mid;
        }
        // 返回语句
        return -1;
    }

    public static void main(String[] args) {
        // 初始化数组
        int[] whiteList = {23423, 123, 23 , 324234, 5234, 123, 2424, 2322, 9942, 2323, 2323};
        Arrays.sort(whiteList);
        // 输入
        int i = StdIn.readInt();
        // 输出
        StdOut.println(rank(i, whiteList));
    }
}

2.2、原始数据类型和表达式

数据类型就是一组数据和对其所能进行的操作的集合。以为为4种Java语言最基本的原始数据类型:

  • 整形及其算术运算符(int)
  • 双精度实数类型及其算术运算符(double)
  • 布尔型,它的值{true,false}及其逻辑操作(boolean)
  • 字符型,它的值是你能够输入的英文字母数字字符和符号(char)

Java程序控制的是用标识符命名的变量。每个变量都有自己的类型并存储了一个合法的值。在Java代码中我们用类似数学表达式的表达式来实现对各种类型的操作。对于原始数据类型来说,我们用标识符来引用变量,用+、-、*、/ 等运算符来指定操作,用字面量,例如1或者3.14来表示值,用形如(x+2.55)/2的表达式来表示对值的操作。

Java程序的基本组成:

术语例子定义
原始数据类型int double boolean char一组数据和对所能进行的操作的集合
标识符a Ab_b ab123由字母、数字、下划线和$组成的字符串,首字符不能是数字
变量[任意标识符]表示某种数据类型的值
运算符+ - * / %表示某种数据类型的运算
字面量int 1 double: 2.0 boolean: true char: ‘a’值在源代码中的表示
表达式字面量、变量或是能够计算出结果的一串字面量、变量和运算符的组合

只要能够指定值域和在此值域上的操作,就能定义一个数据类型。

类型值域运算符典型表达式
int − 2 31 -2^{31} 231 + 2 31 − 1 +2^{31}-1 +2311的整数(32位,二进制补码)+ - * / %5+38
double双精度实数(64位,IEEE754标准)+ - * /3.14+0.033.17
booleantrue 或者 false&& || ! ^true && falsefalse
char字符(16位)(算术运算符,但很少使用)
2.2.1、表达式

如上表所示,Java使用的是中缀表达式:一个字面量(或是一个表达式),紧接着一个运算符,再接着另外一个字面量(或者表达式)。Java中运算符有优先级和方向。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jkO0S3EB-1638710540104)(I:\study\java\note\algorithm\algorithms4\fundametal\operator-priority.png)]

2.2.2、类型转换

类型转换包括隐式类型换行和强制类型转换。

  • 隐式类型转换:一般就是数值类型的转换,整数->浮点型。如果表达式中既有浮点型,又有整数,运算时,会把整形自动转换为浮点型进行运算。

  • 强制类型转换:格式-(数据类型)数值。例如(int)3.7 值是3.

2.2.3、其他原始数据类型
  • 64位整数及其算术运算符(long)
  • 16位整数及其算法运算符(short)
  • 16位字符及其算术运算符(char)
  • 8为整数及其算法运算符(byte)
  • 32位单精度实数及其算术运算符(float)

2.3、语句

Java程序是由语句组成的。语句能够通过创建和操作变量、对变量赋值并控制这些操作的执行流程来描述运算。语句通常被组织成代码段,即花括号中的一系列语句。

  • 声明语句:创建某种类型的变量并用标识符为其命名。
  • 赋值语句:将某种类型的数值赋予一个变量。
  • 条件语句:能够简单的改变执行流程-根据指定的条件执行符合条件的代码段。
  • 循环语句:更彻底地改变执行流程-只要条件为真就不断反复的执行代码段中的语句。
  • 调用和返回语句:和方法相关。

2.4、数组

数组能够顺序存储相同类型的多个数据。除了存储数据,我们也希望能够访问数据。访问数组中的某个元素是方式是将其编号然后索引。

2.4.1、创建并初始化数组

创建数组步骤:

  1. 声明数组的类型和名称
  2. 创建数组
  3. 初始化数组元素

示例:

// 完整模式
double[a];
a = new double[N];
for(int i = 0; i < N; i++)
	a[i] = 1.0;
// 简化写法
double[] a = new double[N];
// 声明初始化
int[] b = {1, 5, 32, 22};
2.4.2、二维数组

Java中二维数组就是元素都是一维数组的一维数组。二维数组可以是参差不齐(元素数组的长度可以不一致),但大多数情况下我们都会使用MxN,级M行N列。二维数组的创建:

double[][] a = new double[M][N]

示例:

double[][] a = new double[M][N];
for(int i = 0; i < M; i++) 
	for(int j = 0; j < N; j++)
		a[i][j] = 1.0;

2.5、方法

对方法的所有性质的完整性描述,有兴趣的自行查阅相关文档,以下展示几点:

  • 方法的参数按值传递
  • 方法名可以被重载
  • 方法只能返回一个值,但可以包含多个返回语句。
  • 方法可以产生副作用
2.5.1、递归

我们会经常使用递归,因为递归代码比相应的非递归代码更加简洁优雅、易懂。,但是需要注意一下三点:

  • 递归总有一个最简单的情况-结束条件,方法的第一条语句总是一个包含return的条件语句
  • 递归调用总是去尝试解决一个规模更小的子问题,这样递归才能收敛到最简单的情况
  • 递归调用的父问题和尝试解决的子问题之间不应该有交集

2.6、API

模块化编程的一个重要组成部分就是记录库方法的用法并供其他人参考的文档。我们会统一使用应用程序编程接口(API)的方式列出本书中使用的每个库方法名称、签名和简短的描述。库包括Java库,本书实现的标准库以及自定义编写的库。

2.7、输入输出

2.7.1、标准会图库

标准绘图库中还包含一些方法来改变画布的大小和比例、直线的颜色和宽度、文本字体、绘图时间(用于动画)等。StdDraw中常用静态方法的API如下:

API描述
void setXscale(double x0, double x1)将x的范围设为(x0, x1)
void setYscale(double y0, double y1)将y的范围设为(y0, y1)
void setPenRadius(double r)将画笔的粗细半径设为r
void setPenColor(Color c)将画笔的颜色设为c
void setFont(Font f)将文本字体设为f
void setCanvasSize(int w, int h)将画布窗口的宽和高设为w和h
void clear(Color c)清空画布并用颜色c将其填充
void show(int dt)显示所有图像并暂停dt毫秒

示例1:已排序的随机数组

import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdRandom;

import java.util.Arrays;

public class TestStdDraw01 {
    public static void main(String[] args) {
        int N = 50;
        double[] a = new double[N];
        for (int i = 0; i < N; i++) {
            a[i] = StdRandom.uniform();
        }
        Arrays.sort(a);
        for (int i = 0; i < N; i++) {
            double x = 1.0 * i / N;
            double y = a[i] / 2.0;
            double rw = 0.5 / N;
            double rh = a[i] / 2.0;
            StdDraw.filledRectangle(x, y, rw, rh);
        }
    }
}

结果图示:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B36j1ZWe-1638710540105)(I:\study\java\note\algorithm\algorithms4\fundametal\2021-12-05_ordered-random-array.png)]

源代码仓库:https://gitee.com/gaogzhen/algorithm

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
本书带完整书签 第1章 基础 1 1.1 基础编程模型 4 1.1.1 Java程序的基本结构 4 1.1.2 原始数据类塑与表达式 6 1.1.3 语句 8 1.1.4 简便记法 9 1.1.5 数组 10 1.1.6 静态方法 12 1.1.7 API 16 1.1.8 字符串 20 1.1.9 输入输出 21 1.1.10 二分査找 28 1.1.11 展望 30 1.2 数据抽象 38 1.2.1 使用抽象数据类型 38 1.2.2 抽象数据类型举例 45 1.2.3 抽象教据类型的实现 52 1.2.4 更多抽象数据类型的实现 55 1.2.5 数据类型的设计 60 1.3 背包、队列和栈 74 1.3.1 API 74 1.3.2 集合类數据类型的实现 81 1.3.3 链表 89 1.3.4 综述 98 1.4 算法分析 108 1.4.1 科学方法 108 1.4.2 观察 108 1.4.3 数学模型 112 1.4.4 增长数量级的分类 117 1.4.5 设计更快的算法 118 1.4.6 倍率实验 121 1.4.7 注意事项 123 1.4.8 处理对于输入的依赖 124 1.4.9 内存 126 1.4.10 展望 129 1.5 案例研究:union-find算法 136 1.5.1 动态连通性 136 1.5.2 实现 140 1.5.3 展望 148 第2章 排序 152 2.1 初级排序算法 153 2.1.1 游戏规则 153 2.1.2 选择排序 155 2.1.3 插入排序 157 2.1.4 排序算法的可视化 159 2.1.5 比较两种排序算法 159 2.1.6 希尔排序 162 2.2 归并排序 170 2.2.1 原地归并的抽象方法 170 2.2.2 自顶向下的归并排序 171 2.2.3 自底向上的归并排序 175 2.2.4 排序算法的复杂度 177 2.3 快速排序 182 2.3.1 基本算法 182 2.3.2 性能特点 185 2.3.3 算法改进 187 2.4 优先队列 195 2.4.1 API 195 2.4.2 初级实现 197 2.4.3 堆的定义 198 2.4.4 堆的算法 199 2.4.5 堆排序 205 2.5 应用 214 2.5.1 将各种數据排序 214 2.5.2 我应该使用啷种排序算法 218 2.5.3 问题的归约 219 2.5.4 排序应用一览 221 第3章查找 227 3.1 符号表 228 3.1.1 API 228 3.1.2 有序符号表 230 3.1.3 用例举例 233 3.1.4 无序链表中的顺序查找 235 3.1.5 有序數组中的二分查找 238 3.1.6 对二分査找的分析 242 3.1.7 预览 244 3.2 二叉查找树 250 3.2.1 基本实现 250 3.2.2 分析 255 3.2.3 有序性相关的方法与删除操作 257 3.3 平衡査找树 269 3.3.1 2-3査找树 269 3.3.2 红黑二叉查找树 275 3.3.3 实现 280 3.3.4 删除操作 282 3.3.5 红黑树的性质 284 3.4 散列表 293 3.4.1 散列函数 293 3.4.2 基于拉链法的散列表 297 3.4.3 基于线性探测法的散列表 300 3.4.4 调整教组大小 304 3.4.5 内存使用 306 3.5 应用 312 3.5.1 我应该使用符号表的哪种实现 312 3.5.2 集合的API 313 3.5.3 字典类用例 315 3.5.4 索引类用例 318 3.5.5 稀疏向量 322 第4章 图 329 4.1 无向图 331 4.1.1 术语表 331 4.1.2 表示无向图的数据类型 333 4.1.3 深度优先搜索 338 4.1.4 寻找路径 342 4.1.5 广度优先搜索 344 4.1.6 连通分量 349 4.1.7 符号图 352 4.1.8 总结 358 4.2 有向图 364 4.2.1 术语 364 4.2.2 有向图的数据类型 365 4.2.3 有向图中的可达性 367 4.2.4 环和有向无环图 369 4.2.5 有向图中的强连通性 378 4.2.6 总结 385 4.3 最小生成树 390 4.3.1 原理- 391 4.3.2 加权无向图的数据类型 393 4.3.3 最小生成树的API和测试用例 396 4.3.4 Prim算法 398 4.3.5 Prim算法的即时实现 401 4.3.6 Kruskal算法 404 4.3.7 展望 407 4.4 最短路径 412 4.4.1 最短路径的性质 413 4.4.2 加权有向图的数据结构 414 4.4.3 最短路径算法的理论基础 420 4.4.4 Dijkstra算法 421 4.4.5 无环加权有向图中的最短路径算法 425 4.4.6 一般加权有向图中的最短路径问题 433 4.4.7 展望 445 第5章 字符串 451 5.1 字符串排序 455 5.1.1 键索引计数法 455 5.1.2 低位优先的字符串排序 458 5.1.3 高位优先的字符串排序 461 5.1.4 三向字符串快速排序 467 5.1.5 字符串排序算法的选择 470 5.2 单词查找树 474 5.2.1 单词查找树 475 5.2.2 单词查找树的性质 483 5.2.3 三向单词查找树 485 5.2.4 三向单词查找树的性质 487 5.2.5 应该使用字符串符号表的哪种实现 489 5.3 子字符串查找 493 5.3.1 历史简介 493 5.3.2 暴力子字符串査找算法 494 5.3.3 Knuth-Morris-Pratt子字符串查找算法 496 5.3.4 Boyer-Moore字符串查找算法 502 5.3.5 Rabin-Karp指纹字符串查找算法 505 5.3.6 总结 509 5.4 正则表达式 514 5.4.1 使用正则表达式描述模式 514 5.4.2 缩略写法 516 5.4.3 正则表达式的实际应用 517 5.4.4 非确定有限状态自动机 518 5.4.5 模拟NFA的运行 520 5.4.6 构造与正则表达式对应的NFA 522 5.5 数据压缩 529 5.5.1 游戏规则 529 5.5.2 读写二进制数据 530 5.5.3 局限 533 5.5.4 热身运动:基因组 534 5.5.5 游程编码 537 5.5.6 霍夫曼压缩 540 第6章背景 558 索引 611
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gaog2zh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值