学习

算法红皮书 1.1.6-1.1.11

基础编程模型 #

静态方法 #

  • 本书中所有的Java程序要么是数据类型的定义,要么是一个静态方法库
  • 当讨论静态方法和实体方法共有的属性时,我们会使用不加定语的方法一词
  • 方法需要参数(某种数据类型的值)并根据参数计算出某种数据类型的返回值(例如数学函数的结果)或者产生某种副作用(例如打印一个值)
  • 静态方法由签名(public static 以及函数的返回值,方法名及一串参数)和函数体组成
  • 调用静态方法(写出方法名并在后面的括号中列出数值)
  • 方法的性质
    • 方法的参数按值传递,方法中使用的参数变量能够引用调用者的参数并改变其内容(只是不能改变原数组变量本身)
    • 方法名可以被重载
    • 方法只能返回一个值,但能包含多个返回语句
    • 方法可以产生副作用
  • 递归:方法可以调用自己 可以使用数学归纳法证明所解释算法的正确性,编写递归重要的三点
    • 递归总有一个最简单的情况(方法第一条总包含return的条件语句)
    • 递归调用总是去尝试解决一个规模更小的子问题
    • 递归调用的父问题和尝试解决的子问题之间不应该由交集 如下图中,两个子问题各自操作的数组部分是不同的
  • 基础编程模型
    • 静态方法库是定义在一个Java类中的一组静态方法
    • Java开发的基本模式是编写一个静态方法库(包含一个main()方法)类完成一个任务
    • 在本书中,当我们提到用于执行一项人物的Java程序时,我们指的就是用这种模式开发的代码(还包括对数据类型的定义)
  • 模块化编程
    • 通过静态方法库实现了模块化编程
    • 一个库中的静态方法也能够调用另一个库中定义的静态方法
  • 单元测试
    • Java编程最佳实践之一就是每个静态方法库中都包含一个main()函数来测试库中所有的方法
    • 本书中使用main()来说明模块的功能并将测试用例留作练习
  • 外部库
    • 系统标准库 java.lang.*:包括Math库;String和StringBuilder库
    • 导入的系统库 java.util.Arrays
    • 本书中其他库
    • 本书使用了作者开发的标准库Std*

API #

  • 模块化编程重要组成部分,记录库方法的用法并供其他人参考的文档
  • 会统一使用应用程序编程接口API的方法列出每个库方法、签名及简述
  • 用例(调用另一个库中的方法的程序),实现(实现了某个API方法的Java代码)
  • 作者自己的两个库,一个扩展Math.random(),一个支持各种统计
    • 随机静态方法库(StdRandom)的API
    • 数据分析方法库(StdStats)的API
    • StdRandom库中的静态方法的实现
  • 编写自己的库
    • 编写用例,实现中将计算过程分解
    • 明确静态方法库和与之对应的API
    • 实现API和一个能够对方法进行独立测试的main()函数
    • API的目的是将调用和实现分离

字符串 #

  • 字符串拼接,使用 +
  • 类型转换(将用户从键盘输入的内容转换成相应数据类型的值以及将各种数据类型的值转换成能够在屏幕上显示的值)
  • 如果数字跟在+后面,那么会将数据类型的值自动转换为字符串
  • 命令行参数
    • Java中字符串的存在,使程序能够接收到从命令行传递来的信息
    • 当输入命令java和一个库名及一系列字符串后,Java系统会调用库的main()方法并将后面的一系列字符串变成一个数组作为参数传递给它

输入输出 #

  • Java程序可以从命令行参数或者一个名为标准输入流的抽象字符流中获得输入,并将输出写入另一个名为标准输出流的字符流中
  • 默认情况下,命令行参数、标准输入和标准输出是和应用程序绑定的,而应用程序是由能够接受命令输入的操作系统或是开发环境所支持
  • 使用终端来指代这个应用程序提供的供输入和显示的窗口,如图
  • 命令和参数
    • 终端窗口包含一个提示符,通过它我们能够向操作系统输入命令和参数
    • 操作系统常用命令
  • 标准输出
    • StdOut库的作用是支持标准输出
    • 标准输出库的静态方法的API
    • 格式化输出 字符%并紧跟一个字符表示的转换代码(包括d,f和s)。%和转换代码之间可以插入证书表示值的宽度,且转换后会在字符串左边添加空格以达到需要的宽度。负数表示空格从右边加
    • 宽度后用小数点及数值可以指定精度(或String字符串所截取的长度)
    • 格式中转换代码和对应参数的数据类型必须匹配
  • 标准输入
    • StdIn库从标准输入流中获取数据,然后将标准输出定向到终端窗口
    • 标准输入流最重要的特点,这些值会在程序读取后消失
    • 例子
    • 标准输入库中的静态方法API
  • 重定向和管道
    • 将标准输出重定向到一个文件
      java RandomSeq 1000 100.0 200.0 > data.txt
      
    • 从文件而不是终端应用程序中读取数据
      java Average < data.txt
      
    • 将一个程序的输出重定向为另一个程序的输入,叫做管道
      java RandomSeq 1000 100.0 200.0 | java Average
      
      • 突破了我们能够处理的输入输出流的长度限制
      • 即使计算机没有足够的空间来存储十亿个数,
      • 我们仍然可以将例子中的1000 换成1 000 000 000 (当然我们还是需要一些时间来处理它们)。当RandomSeq 调用StdOut.println() 时,它就向输出流的末尾添加了一个字符串;当Average 调用StdIn.readInt() 时,它就从输入流的开头删除了一个字符串。这些动作发生的实际顺序取决于操作系统
    • 命令行的重定向及管道
  • 基于文件的输入输出
  • In和Out库提供了一些静态方法,来实现向文件中写入或从文件中读取一个原始数据类型的数组的抽象
  • 用于读取和写入数组的静态方法的API
  • 标准绘图库(基本方法和控制方法)–这里跳过

二分查找 #

  • 如图,在终端接收需要判断的数字,如果不存在于白名单(文件中的int数组)中则输出
  • 开发用例以及使用测试文件(数组长度很大的白名单)
  • 模拟实际情况来展示当前算法的必要性,比如
    • 将客户的账号保存在一个文件中,我们称它为白名单;
    • 从标准输入中得到每笔交易的账号;
    • 使用这个测试用例在标准输出中打印所有与任何客户无关的账号,公司很可能拒绝此类交易。
  • 使用顺序查找
    public static int rank(int key, int[] a)
    {
      for (int i = 0; i < a.length; i++)
        if (a[i] == key) return i;
      return -1;
    }
    
  • 当处理大量输入的时候,顺序查找的效率极其低

展望 #

  • 下一节,鼓励使用数据抽象,或称面向对象编程,而不是操作预定义的数据类型的静态方法
  • 使用数据抽象的好处
    • 复用性
    • 链式数据结构比数组更灵活
    • 可以准确地定义锁面对的算法问题

1.1 End #

算法红皮书 1.1.1-1.1.5

基础编程模型 #

Java程序的基本结构 #

  • 本书学习算法的方法:用Java编程语言编写的程序来实现算法(相比用自然语言有很多优势)
  • 劣势:编程语言特定,使算法的思想和实现细节变得困难(所以本书尽量使用大部分语言都必须的语法)
  • 把描述和实现算法所用到的语言特性、软件库和操作系统特定总称为基础编程模型
  • Java程序的基本结构
    • 一段Java程序或者是一个静态方法库,或者定义了一个数据类型,需要用到的语法

      • 原始数据类型(在计算机中精确地定义整数浮点数布尔值等)
      • 语句(创建变量并赋值,控制运行流程或引发副作用来进行计算,包括声明、赋值、条件、循环、调用和返回)
      • 数组(多个同种数据类型值的集合)
      • 静态方法(封装并重用代码)
      • 字符串(一连串的字符,内置一些对他们的操作)
      • 标准输入/输出(是程序与外界联系的桥梁)
      • 数据抽象(数据抽象封装和重用代码,可以定义非原始数据类型,进而面向对象编程)
    • 把这种输入命令执行程序的环境称为 虚拟终端

    • 要执行一条Java程序,需要先用javac命令编译,然后用java命令运行,比如下面的文件,需要使用命令

      javac BinarySearch.java
      java BinarySearch 
      


原始数据类型与表达式 #

  • 数据类型就是一组数据和其所能进行的操作的集合
  • Java中最基础的数据类型(整型int,双精度实数类型double,布尔值boolean,字符型char)
  • Java程序控制用标识符命名的变量
  • 对于原始类型,用标识符引用变量,+-*/指定操作,用字面量来表示值(如1或3.14),用表达式表示对值的操作( 表达式:(x+2.334)/2 )
  • 只要能够指定值域和在此值域上的操作,就能定义一个数据类型(很像数学上函数的定义)
  • +-*/是被重载过的
  • 运算产生的数据的数据类型和参与运算的数据的数据类型是相同的(5/3=1,5.0/3.0=1.6667等)
  • 如下图(图歪了亿点点..)
  • 表达式
  • 表达式具有优先级,Java使用的是中缀表达式(一个字面量紧接运算符,然后是另一个字面量)。逻辑运算中优先级 ! && || ,运算符中 * / % 高于+ - 。括号能改变这些规则。代码中尽量使用括号消除对优先级的依赖
  • 类型转换
    • 数值会自动提升为高级数据类型,如1+2.5 1会被先转为double 1.0,值也为double的3.5
    • 强转(把类型名放在括号里讲其转换为括号中的类型) 讲高级数据类型转为低级可能会导致精度的缺失,尽量少使用
  • 比较
    • ==、!=、<、<=、>、>=,这些运算符称为 混合类型运算符,因为结果是布尔型而不是参与比较的数据类型
    • 结果是布尔型的表达式称为布尔表达式
  • 其他原始类型(int为32位,double为64位)
    • long,64位整数
    • short,16位整数
    • char,16位字符
    • byte,8位整数
    • 32位单精度实数,float

语句 #

  • 语句用来创建和操作变量、对变量赋值并控制操作的执行流程
  • 包括声明语句、赋值语句、条件语句、循环语句、调用和返回语句
  • 声明:让一个变量名和一个类型在编译时关联起来
  • 赋值:将(由一个表达式定义的)某个数据类型额值和一个变量关联起来
  • 条件语句:
    if (<boolean expression>) { <block statement> }
    
  • 循环语句
    while(<boolean expression>) { <block statement> }
    
    其中循环语句中的代码段称为循环体
  • break与continue语句
    • break,立即退出循环
    • continue,立即开始下一轮循环

简便记法 #

  • 声明并初始化
  • 隐式赋值
    • ++i;–i
    • i/=2;i+=1
  • 单语句代码段(省略if/while代码段的花括号)
  • for语句
    for(<initialize>;<boolean expression>;<increment>)
    {
        <block statements>
    }
    
    这段代码等价于后面的
    <initialize>;
    while(<boolean expression>)
    {
      <block statments>
      <increment>;
    }
    
  • java语句总结

数组 #

  • 数组能够存储相同类型的多个数据
  • N个数组的数组编号为0至N-1;这种数组在Java中称为一维数组
  • 创建并初始化数组
    • 需要三个步骤,声明数组名字和类型,创建数组,初始化数组元素
    • 声明并初始化一个数组
    • 简化写法
      double[] a = new double[N];
    • 使用数组(访问的索引小于0或者大于N-1时会抛出ArrayIndexOutOfBoundsException)
    • 典型的数组处理代码
  • 起别名
    • 下面的情况并没有将数组新复制一份,而是a,b指向了同一个数组
  • 二维数组
    • Java中二维数组就是一堆数组的数组
    • 二维数组可以是参差不齐,比如a[0]=new double[5],a[1]=new double[6]之类
    • 二维数组的创建及初始化
      double[][] a;
      a = new double[M][N];
      for (int i = 0; i < M; i++)
          for (int j = 0; j < N; j++)
              a[i][j] = 0.0;
      
    • 精简后的代码 double[][] a=new double[M][N];

linux_韩老师_01-06

基础介绍 #

  • 本套课程内容
    • 基础篇: linux入门、vm和Linux的安装、linux目录结构
    • 实操篇
      • 远程登录(xshell,xftp)、实用指令、进程管理、用户管理
      • vi和vim编辑器、定时任务调度、RPM和YUM
      • 开机、重启和用户登录注销、磁盘分区及挂载、网络配置
  • linux使用的地方
    • 在linux下开发项目(需要把javaee项目部署到linux下运行)
    • linux运维工程师(服务器规划、优化、监控等)
    • linux嵌入式工程师(linux下驱动开发[c,c++])
  • linux应用领域
    • 个人桌面
    • 服务器(免费稳定高效)
    • 嵌入式领域(对软件裁剪,内核最小可达几百kb等)

linux介绍 #

  • linux是一个开源免费操作系统
  • linux吉祥物
    tux(/tu’ks/唾可si),没找到音标,将就一下
  • linux之父,linus,也是git的创作者
    主要发行版:Ubuntu、RedHat,Centos,Debian等
    RedHat和Centos使用同样的源码,但是RedHat收费
  • Linux和Unix的关系
    unix也是一个操作系统,贝尔实验室。做一个多用户分时操作系统, multics,但是没完成。其中一个后来在这基础上,完成的操作系统为unix (原本是B语言写的),后面和另一个人用unix用c语言改写了。
    unix源码是公开的,后面商业公司拿来包装做成自己的系统, 后面有个人提倡自由时代用户应该对源码享有读写权利而非垄断
    后面RichardStallman发起GNU计划(开源计划),Linus参加该计划,并共享出linux内核,于是大家在此基础上开发出各种软件。linux又称GNU/linux
  • Linux和Unix关系

VMWare安装Centos7.6 #

在windows中安装Linux系统

  • VM和Linux系统在pc中的关系

  • 安装过程中,网络模式使用NAT模式

  • 选择最小安装,且选择CompatibilityLibraries和DevelopmentTools

  • linux分区
    一般分为三个

    一般boot1G,swap分区一般跟内存大小一致,这里是2G,所以根分区就是剩下的,也就是20-1-2=17G
    如图,boot,/,swap都是标准分区。且boot和/是ext4的文件格式,swap是swap的文件格式

  • 修改主机名

  • 修改密码及增加除root外的普通用户

  • 修改网络为固定ip(NAT模式下)

    • 先在VM里面把子网ip改了,这里改成 192.168.200.0
    • 然后改网关为192.168.200.200
    • 使用yum install -y vim 安装文本编辑工具
    • 最后在linux中改配置文件
      vim /etc/sysconfig/network-scripts/ifcfg-ens33
      
    • 其中先修改BOOTPROTO=“static”
    • 然后设置ip地址、网关和DNS, 下面是添加到上面的ifcfg-ens33后面,不是直接执行代码
      IPADDR=192.168.200.200
      GATEWAY=192.168.200.2
      DNS1=192.168.200.2
      
    • 使用命令重启网络
      service network restart 
      # 或者直接重启电脑 reboot
      
  • 这里顺便装一下zsx

    ...

redis_尚硅谷_19-A

验证码模拟 #

  • 首先需要一个MyRedis单例类
/**
 * MyRedis单例类
 */
public class MyJedis {
    private static Jedis myJedis;

    public static Jedis getInstance() {
        //如果是空则进行初始化
        if (myJedis == null) {
            //由于synchronized同步是在条件判断内,所以同步
            //并不会一直都执行,增加了效率
            synchronized (MyJedis.class) {
                if (myJedis == null) {
                    //设置密码
                    DefaultJedisClientConfig.Builder builder = DefaultJedisClientConfig.builder()
                            .password("hello.lwm");
                    DefaultJedisClientConfig config = builder.build();

                    Jedis jedis = new redis.clients.jedis.Jedis("192.168.200.200", 6379, config);

                    return jedis;
                }
            }

        }
        return myJedis;
    }
}

redis_尚硅谷_18

Jedis操作Redis6 #

  • 插曲:本地项目关联github远程库
     git init
     git add README.md
     git commit -m "first commit"
     #-m表示强制重命名
     git branch -M main
     #使用别名
     git remote add origin git@github.com:lwmfjc/jedis_demo.git
     #用了-u之后以后可以直接用git push替代整行 
     git push -u origin main 
    
  • jedis pom依赖
    <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>4.0.1</version>
    </dependency>
    
  • jedis使用
    public class Main {
        public static void main(String[] args) {
            //设置密码
            DefaultJedisClientConfig.Builder builder = 
            DefaultJedisClientConfig.builder()
                    .password("hello.lwm");
            DefaultJedisClientConfig config = builder.build();
    
            Jedis jedis = new Jedis("192.168.200.200", 6379, config);
            //ping
            String value = jedis.ping();
            System.out.println(value);
            //返回所有key
            Set<String> keys = jedis.keys("*");
            System.out.println("key count: " +
                    keys.size());
            for (String key : keys) {
                System.out.printf("key--:%s---value:%s\n", 
            key, jedis.get(key));
            }
    
            System.out.println("操作list");
            //操作list
            jedis.lpush("ly-list", "java", "c++", "css");
            List<String> lrange = jedis.lrange("ly-list", 0, -1);
            for (String v : lrange) {
                System.out.println("value:" + v);
            }
    
            //操作set
            System.out.println("操作set");
            jedis.sadd("ly-set", "1", "3", "3",
                    "5", "1");
            Set<String> smembers = jedis.smembers("ly-set");
            for (String v : smembers) {
                System.out.println("value:" + v);
            }
            //操作hash
            System.out.println("操作hash");
            jedis.hset("ly-hash", "name", "lidian");
            jedis.hset("ly-hash", "age", "30");
            jedis.hset("ly-hash", "sex", "man");
            Map<String, String> lyHash = jedis.hgetAll("ly-hash");
            for (String key : lyHash.keySet()) {
                System.out.println(key + ":" + lyHash.get(key));
            }
            //操作zset
            System.out.println("操作zset");
            jedis.zadd("person", 100, "xiaohong");
            jedis.zadd("person", 80, "xiaoli");
            jedis.zadd("person", 90, "xiaochen");
            List<String> person = jedis.zrange("person", 0, -1);
            for (String name : person) {
                System.out.println(name);
            }
            //结束操作
            jedis.flushDB();
            jedis.close();
        }
    }
    

redis_尚硅谷_12-17

Redis配置文件 #

  • redis中单位的设置,支持k,kb,m,mb,g,gb,且不区分大小写
  • include (包含其他文件,比如公共部分)
  • bind
    bind 127.0.0.1 ::1 #listens on loopback IPv4 and IPv6 
    
    • 后面这个::1,相当于ipv6版的127.0.0.1。在redis配置文件中,整句表示只允许本地网卡的某个ip连接(但是它并不能指定某个主机连接到redis中。比如本机有两个网卡,两个ip,可以限定只有其中一个ip可以连接)
    • 如果注释掉了/或者bind 0.0.0.0,表示允许所有主机连接
  • protected-mode
    protected-mode yes 
    
    • 设置保护模式为yes,protected是redis本身的一个安全层,这个安全层在同时满足下面三个条件的时候会开启,开启后只有本机可以访问redis
      • protected-mode yes
      • 没有bind指令(bind 0.0.0.0不属于这个条件)
      • 没有设置密码 (没有设置requirepass password)
    • 只要上面一个条件不满足,就不会开启保护模式。换言之,只要设置了bind 0.0.0.0或者没有设置bind,且不满足上面三个条件之一,就能够进行远程访问(当然,linux/windows的6379端口要开放)
  • tcp-backlog 表示未连接队列总和
  • timeout 秒为单位,时间内没操作则断开连接
  • tcp-keepalive 300 心跳检测,每隔300s检测连接是否存在
  • pidfile /var/run/redis_6379.pid 将进程号保存到文件中
  • loglevel 表示日志的级别/debug/verbose/notice/warning
  • logfile "" 设置日志的路径
  • database 16 默认有16个库
  • requirepass password 设置密码
  • maxclients 设置最大连接数
  • maxmemory 设置最大内存量,达到则会根据移除策略进行移除操作

Redis的发布和订阅 #

  • 发布订阅,pub/sub,是一种消息通信模式:发送者pub发送消息,订阅器sub接收消息
  • 发布者能发布消息,订阅者可以订阅/接收消息
  • 操作
    subscribe channel1 #客户端A订阅频道 
    
    publish channel1 helloly #向频道发送消息
    
    此时订阅channel1频道的客户端就会接收到消息

redis新数据类型 #

Bitmaps #

  • 进行二进制操作

    ...

redis_尚硅谷_06-11

Redis针对key的基本操作 #

  • 常用命令
    keys * #查找当前库所有库
    exists key1 #key1是否存在 1存在;0不存在
    type key2 #key2的类型
    del key3 #删除key3
    unlink key3 #删除key3(选择非阻塞删除。会先从元数据删除,而真正删除是异步删除)
    expire key1 10 #设置key1的过期时间,单位秒
    ttl key1 #获取key1的剩余存活时间,-2表示key已过期或不存在,-1表示永不过期
    select 1 #切换到1号库(redis中有15个库,默认在库1)
    dbsize #查找当前redis库中有多少个key
    flushdb #清空当前库
    flushall #清空所有库
    

Redis中常用数据类型 #

字符串(String) #

  • String是二进制安全的,可以包含jpg图片或序列化的对象
  • 一个Redis中字符串value最多可以只能是512M
  • 常用命令
    set key1 value1
    get key1 
    set key1 value11 #将覆盖上一个值
    append key1 abc #在key1的值追加"abc"
    strlen key1 #key值的长度
    setnx key1 value #当key不存在时才设置key
    incr n1 #将n1的值加一,,如果n1不存在则会创建key n1 并改为1(0+1)
    decr n1 #将n1的值减一,如果n1不存在则会创建key n1 并改为-1(0-1)
    incrby n1 20 #将n1的值加20,其他同上
    decrby n1 20 #将n1的值减20,其他同上
    
  • redis原子性
    incr具有原子性操作
    java中的i++不是原子操作
  • 其他命令
    mset k1 v1 k2 v2
    mget k1 k2 
    msetnx k1 v1 k2 v2 #仅当所有的key都不存在时才会进行设置
    getrange name 0 3 #截断字符串[0,3]
    setrange name 3 123 #从下标[3]开始替换字符串(换成123)
    setex k1 20 v1 #设置过期时间为20s
    expire k1 30 #设置过期时间为30s
    getset k1 123 #获取旧值,并设置一个新值
    
  • 数据结构,SimpleDynamicString,SDS,简单动态字符串,内部结构类似Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配

列表 (List) #

  • 单键多值
  • 底层是双向链表
  • 从左放
    lpush k1 v1 v2 v3 #从左边放(从左往右推)
    lrange k1 0 -1 #从左边取(v3 v2 v1)
    
  • lpush:
  • 从右放
    rpush k2 v1 v2 v3 
    
  • brpush:
  • lpop/rpop
    lpop k2 #从左边弹出一个值
    lpop k2 2 #从左边弹出两个值,当键没有包含值时,键被删除
    
  • rpoplpush
    lpush a a1 a2 a3
    rpush b b1 b2 b3
    rpoplpush a b #此时a:a1 a2,b:a3 b1 b2 b3
    
  • lrange
    lrange b 1 2 #获取b中下标[1,2]的所有值
    lrange b 1 -1 #获取所有值[1,最大下标]的所有值
    
  • lindex,llen
    lindex b 1 #直接取第一个下标的元素
    llen b #获取列表的长度
    
  • linsert
    linsert b before b2 myinsert
    linsert b after b2 myinsert
    #在某个列表的值(如果重复取第一个)的位置之前/之后插入值
    
  • lrem,lset
    lrem b 2 a #从b列表中,删除两个a(从左往右)
    lset b 2 AA #把下标2的值设置为AA
    
  • list数据结构是一个快速列表,quicklist
    当元素较少的时候,会使用连续的内存存储,结构时ziplist,即压缩列表;当数据多的时候会有多个压缩列表,然后会链接到一起(使用双向指针)

集合(Set) #

  • 特点:无序,不重复
  • Set:string类型的无序集合,底层是一个value为null的hash表;添加/删除时间复杂度为O(1)
  • 常用命令
    sadd k1 v1 v2 v3 v2 v2 v1 #设置集合中的值
    smembers k1 #取出集合中的值
    sismember k1 v3 #k1是否存在v3,存在返回1,不存在返回0
    scard k1 #返回集合中元素的个数
    srem k1 v2 v3 #删除集合中的v2和v3
    spop k1 #从k1中随机取出一个值
    srandmember k1 2 #从k1中随机取出2个值
    
    smove a k a1 #从a中将a1移动到k中
    sinter a k #取a,k的交集
    sunion a k #取a,k的并集
    sdiff a k #返回两个集合的差集(从集合a中,去除存在集合k中的元素,即a-k)
    
  • Set数据结构时dict字典,字典使用哈希表实现的

哈希(Hash) #

  • 是String类型的field和value的映射表,用来存储对象,类似java中的Map<String,Object>
  • 常用命令
    hset user:1001 id 1 #设置(对象)user:1001的id属性值
    hset user:1001 name zhangsan 
    hget user:1001 name #取出user:1001的name
    hmset user:1001 id 1 name zhangsan #批量设置(现在hset也可以批量设置了,hmset已弃用)
    hexists user:1001 id 1 #判断属性id是否存在
    hkeys user:1001 #查看hash结构中的所有filed
    hvals user:1001 #查看hash结构中所有value
    hincrby user:1001 age 2 #给hash结构的age属性值加2
    hsetnx user:1001 age 10 #给hash结构的age属性设置值为10(如果age属性不存在)
    
  • hash类型数据结构,当field-value长度较短时用的是ziplist,否则使用的是hashtable

有序集合(ZSet) #

  • 与set很相似,但是是有序的
  • 有序集合的所有元素(成员)都关联一个评分(score),score用来从最低到最高方式进行排序,成员唯一但评分是重复的
  • 常用命令
    zadd topn 100 xiaoming 120 xiaohong 60 xiaochen #添加key并为每个成员添加评分
    zadd topn xiaoli 200 
    zrange topn 0 -1 #查找出所有成员(按排名由小到大)
    zrange topn 0 -1 withscores #从小到大查找所有成员并显示分数
    zrangebyscore topn 130 200 #查找所有在130-200的成员
    zrevrangebyscore topn 200 130 #从大到小查找所有成员(注意,从大到小时第一个值必须大于等于第二个)
    zincrby topn 15 xiaohong #给小红添加15分
    zrem topn xiaohong #删除元素
    zcount topn 10 200 #统计该集合,分数区间内的元素个数
    zrank topn xiaohong #xiaohong的排名,从0开始
    
  • zset底层数据结构
    • hash结构
    • 跳跃表 给元素value排序,根据score的范围获取元素列表
    • 对比有序链表和跳跃表
      • 查找51元素
      • 跳跃表
        按图中的顺序查找,查找四次就能找到
  • End

redis_尚硅谷_01-05

课程简介 #

NoSQL数据库简介、Redis概述与安装、常用五大数据结构、配置文件详解、发布与订阅、Redis6新数据类型、Redis与spring boot整合、事务操作、持久化之RDB、持久化之AOF、主从复制及集群、Redis6应用问题(缓存穿透、击穿、雪崩以及分布式锁)、Redis6新增功能

NoSQL数据库简介 #

  • Redis属于NoSQL数据库
  • 技术分为三大类
    • 解决功能性问题:Java、Jsp、RDBMS、Tomcat、Linux、JDBC、SVN
    • 解决扩展性问题:Struts、Spring、SpringMVC、Hibernate、Mybatis
    • 解决性能问题:NoSQL、Java线程、Nginx、MQ、ElasticSearch
  • 缓存数据库的好处
    • 完全在内存中,速度快,结构简单
    • 作为缓存数据库:减少io的读操作
  • NoSQL=Not Only SQL,不仅仅是SQL,泛指非泛型数据库
    • 不支持ACID(但是NoSQL支持事务)
    • 选超于SQL的性能
  • NoSQL适用场景
    • 对数据高并发的读写
    • 海量数据的读写
    • 对数据高可扩展性
  • NoSQL不适用的场景
    • 需要事务支持
    • 基于sql的结构化查询存储
  • 多种NoSQL数据库介绍
    • Memcache 不支持持久化,数据类型单一,一般作为辅助持久化的数据库
    • Redis 支持持久化,除了k-v模式还有其他多种数据结构,一般作为辅助持久化的数据库
    • MongoDB,是文档型数据类型;k-v模型,但是对value提供了丰富的查询功能;支持二进制数据及大型对象;替代RDBMS,成为独立数据库
  • 大数据时代(行式数据库、列式数据库)
    • 行式数据库
      查询某一块数据的时候效率高
    • 列式数据库
      查询某一列统计信息快
    • 其他
      Hbase,Cassandra,图关系数据库(比如社会关系,公共交通网等)
  • 小计
    NoSQL数据库是为提高性能而产生的非关系型数据库

Redis概述与安装 #

  • 简单概述
    • Redis是一个开源的kv存储系统
    • 相比Mencached,支持存储的数据类型更多,包括string,list,set,zset以及hash,这些类型都支持(pop、add/remove及取交并集和差集等),操作都是原子性的
    • Redis数据都是缓存在内存中
    • Redis会周期性地把数据写入磁盘或修改操作写入追加的记录文件
    • 能在此基础上实现master-slave(主从)同步
  • Redis功能
    • 配合关系型数据库做高速缓存
    • Redis具有多样的数据结构存储持久化数据
    • 其他部分功能
  • Redis安装
    • 从官网中下载redis-6.xx.tar.gz包(该教程在linux中使用redis6教学)
    • 编译redis需要gcc环境
      • 使用gcc –version查看服务器是否有gcc环境
      • 如果没有需要进行安装
        apt install -y gcc
        或者
        yum install -y gcc
        
    • 将redis压缩文件进行解压
      tar -zxvf redis-6xx.tar.gz
      
    • 进入解压后的文件夹,并使用make命令进行编译
      make
      
    • 如果报错了,需要先用下面命令清理,之后再进行编译
      make distclean
      
    • 安装redis
      make install
      
    • 进入/usr/local/bin目录,查看目录
  • Redis启动
    • 前台启动
      redis-server 
      
    • 后台启动
      • 在刚才解压的文件夹中,拷贝出redis.conf文件(这里拷贝到/etc/目录下)
        cp redis.conf /etc/redis.conf
        
      • 到etc中修改redis.conf文件
        vim /etc/redis.conf
        # 进入编辑器后使用下面命令进行搜索并回车
        /daemonize no
        
        将no改为yes并保存
    • 进入/usr/local/bin目录启动redis
      redis-server /etc/redis.conf 
      
    • 查看进程,发现redis已经启动
      ps -ef | grep redis
      
    • 使用redis-cli 客户端连接redis
      redis-cli
      keys * 
      

相关知识 #

  • Redis6379的由来
    • 人名Merz 在九宫格对应的数字就是6379
  • Redis默认有15个库,默认数据都在数据库0中,所有库的密码都是相同的
  • Redis是单线程+多路复用技术
    • Redis是串行操作
    • 火车站的例子
      当1,2,3没有票的时候,不用一直等待买票,可以继续做自己的事情,黄牛买到票就会通知123进行取票
  • Memcached和Redis区别
    • Memcached支持单一数据类型,Redis支持多数据类型
    • Memcached不支持持久化
    • Memcached用的多线程+锁的机制,Redis用的是单线程+多路复用程序

End #