string
- redis-cli help
redis默认共有16个库,可以在配置文件中修改
set k380 hello
get k380
help @generic
keys *
#清库,慎用,my friend
flushdb
flushall
help@string
#不存在的时候才去设置,一旦有设置,则新的设置无效(只能新建)
set k1 ooxx nx
#存在的时候才去设置,一旦没有设置,则新的设置无效(只能更新)
set k2 hello xx
#批量
mset k3 a k4 b
mget k3 k4
append k1 world
#正反向索引
getrange k1 5 -1
setrange k1 5 " xiaowu"
strlen k1
#查看k1的value类型
type k1
set k2 99
type k2
object help
#面向字符串可以有计算类型,这里的int指的是k2的value的编码类型而不是type
object encoding k2
#加减
incrby k2 12
decr k2
decrby k2 22
incrbyfloat k2 0.5
#2中类型,embstr,row
set k3 jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
object encoding k3
append k3 jjjjjjj
object encoding k3
flushall
#二进制安全演示
set k1 hello
strlen k1
set k2 9
object encoding k2
strlen k2
append k2 999
get k2
object encoding k2
incr k2
object encoding k2
strlen k2
#utf-8和gbk编码
set k3 a
get k3
strlen k3
append k3 中
get k3
strlen k3
#触发格式化操作,"中"字可以正常显示
redis-cli --raw
#原子性操作
msetnx k1 a k2 b
mget k1 k2
msetnx k2 c k3 d
mget k1 k2 k3
flushall
#一个字节8位
help setbit
setbit k1 1 1
strlen k1
setbit k1 7 1
#01000001
setbit k1 9 1
strlen k1
get k1
#就算是只找第二个字节,依然会返回全量字节的索引下标
help bitpos
bitpos k1 1 0 0
bitpos k1 1 1 1
bitpos k1 1 0 1
#统计次数
bitcount k1 1 0 1
flushall
#位操作,与或非
setbit k1 1 1
setbit k1 7 1
get k1
setbit k2 1 1
setbit k2 6 1
#与操作 有0则0,全1为1
#01000000
bittop and andkey k1 k2
#或操作 有1则1,全0为0
#01000011
bittop or orkey k1 k2
list
help @list
#向k1中添加
lpush k1 a b c d e f
#l代表左边,插入的结构实际为f e d c b a
rpush k2 a b c d e f
#r代表右边,插入的结构实际为a b c d e f
#弹出元素
lpop k1
#这个东西与栈类似
#弹出元素
rpop k1
#栈:同向命令
#队列:反向命令
#查看
lrange k1 0 -1
#根据下标取
lindex k1 2
lindex k1 -1
#根据下标设置
lset k1 3 xxxx
#删除
lrem k3 2 a
#2为正数代表正向删除,为负数代表反向删除
linsert k3 after 6 a
#在元素6之后插入,而不是下标了
#如果有两个相同元素,会在第一个元素6之后插入,而不是两个6全插入
linsert k3 before 3 a
#反向删除
lrem k3 -2 a
#统计数量
llen k3
#开三个客户端测试阻塞
blpop ooxx 0
#两个客户端阻塞,一个客户端新增数据,有机会测一下
#两端删除
ltrim k4 0 -1
ltrim k4 2 -2
#从下标2开始到下标-2留下,也就是说下标0,1,-1删除
help @list
#向k1中添加
lpush k1 a b c d e f
#l代表左边,插入的结构实际为f e d c b a
rpush k2 a b c d e f
#r代表右边,插入的结构实际为a b c d e f
#弹出元素
lpop k1
#这个东西与栈类似
#弹出元素
rpop k1
#栈:同向命令
#队列:反向命令
#查看
lrange k1 0 -1
#根据下标取
lindex k1 2
lindex k1 -1
#根据下标设置
lset k1 3 xxxx
#删除
lrem k3 2 a
#2为正数代表正向删除,为负数代表反向删除
linsert k3 after 6 a
#在元素6之后插入,而不是下标了
#如果有两个相同元素,会在第一个元素6之后插入,而不是两个6全插入
linsert k3 before 3 a
#反向删除
lrem k3 -2 a
#统计数量
llen k3
#开三个客户端测试阻塞
blpop ooxx 0
#两个客户端阻塞,一个客户端新增数据,有机会测一下
#两端删除
ltrim k4 0 -1
ltrim k4 2 -2
#从下标2开始到下标-2留下,也就是说下标0,1,-1删除
map
set sean::name 'minato aqua'
get sean::name
set sean::age 18
get sean::age
keys sean*
hset sean name 'minato aqua'
hmset sean age 18 address hovelive
hget sean name
hget sean address
hmget sean name age
hkeys sean
hvals sean
hgetall sean
hincrbyfloat sean age 0.5
hincrbyfloat sean age -1
#hashmap应用场景:收藏,详情页,点赞,修改数据等等
Set
#set特点:无序+去重
help @set
sadd k1 tom sean peter ooxx tom xxoo
smembers k1
srem k1 xxoo ooxx
smembers k1
sadd k2 1 2 3 4 5
sadd k3 4 5 6 7 8
sinter k2 k3
#插入到dest里头
sinterstore dest k2 k3
sunion k2 k3
#同上,存在rstore,并集
sdiff k2 k3
sdiff k3 k2
#外差集,两个结果并不一样,右侧为参考基准
srandmember k1 5 -5 10 -10
#为正数的时候,取出一个去重的结果集(不能超过已有结果集)
#为负数的时候,取出一个带重复的结果集(一定会满足你要的数量)
#为0,不返回结果
spop k1
Sort Set
#想让它们怎么排序?名称?大小?价格?
help @sorted_set
zadd k1 8 apple 2 banana 3 orange
#物理内存左小右大,不随命令发生变化
#查看
zrange k1 0 -1
#查看分值
zrange k1 0 -1 withscores
#取分值范围
zrangebyscore k1 3 8
#正向取
zrange k1 0 1
#反向取
zrevrange k1 0 1
#通过值取分值
zscore k1 apple
#取出排名
zrank k1 apple
#查看所有
zrange k1 0 -1 withscores
#增加
zinsrby k1 2.5 banana
#实时根据修改更新排序
zrange k1 0 -1 withscores
#集合取并集
zadd k1 80 tom 60 sean 70 baby
zadd k2 60 tom 100 sean 40 yiming
zunionstore unkey 2 k1 k2
zrange unkey 0 -1 withscores
#设置权重
zunionstore unkey1 2 k1 k2 weights 1 0.5
#k1里面的不变,k2里面的乘0.5
zrange unkey1 0 -1 withscores
#取最大的
zunionstore unkey2 2 k1 k2 aggregate max
zrange unkey2 0 -1 withscores
排序是怎么实现的怎删改查的速度?
跳跃表(skip list),平衡树
- 随机造层,最大层数是16层
package com.example.demo;
import java.util.Random;
/**
* 跳表的实现
*/
public class SkipList {
public static final int MAX_LEVEL = 16; //跳表所允许的最大层级
private SkipListNode head = new SkipListNode(null, MAX_LEVEL);
private Random random = new Random();
private int usedLevel = 1; //当前跳表使用中的最大层级
public void insert(int value) {
int level = randomLevel(); //找出当前插入值随机最大层数
//遍历节点并插入
insert(value, level);
}
public void delete(int value) {
//从最高层开始,寻找节点
int level = usedLevel;
while(level >= 1) {
level--;
SkipListNode searchResult = search(value, level);
if(searchResult != null) {
deleteNode(searchResult);
break;
}
}
}
//逐层打印
public void print() {
int level = usedLevel;
while(level >= 1) {
level--;
printLevel(level);
}
}
private void printLevel(int level) {
SkipListNode current = head;
String result = new String();
while (current.next[level] != null) {
result = result + current.next[level].data + " -> ";
current = current.next[level];
}
System.out.println("第 " + level + " 层的数据为 : " + result);
}
private void deleteNode(SkipListNode searchResult) {
//将当前节点的前置节点和后置节点关联起来即可
int currentLevel = searchResult.getMaxlevel();
while(currentLevel >= 1) {
currentLevel--;
//当前节点的前置节点的后置节点 = 当前节点的后置节点
searchResult.pre[currentLevel].next[currentLevel] = searchResult.next[currentLevel];
if(searchResult.next[currentLevel] != null) {
//如果当前节点的后置节点不为null
//当前节点的额后置节点的前置节点 = 当前节点的前置节点
searchResult.next[currentLevel].pre[currentLevel] = searchResult.pre[currentLevel];
}
}
}
private SkipListNode search(int value, int level) {
//从头开始遍历
SkipListNode current = head;
while(current.next[level] != null && current.next[level].data < value) {
current = current.next[level];
}
if(current.next[level] == null || current.next[level].data != value) {
//如果搜索到最后,或者已经搜索到比寻找值大的节点了
return null;
}
return current.next[level];
}
private void insert(int value, int level) {
SkipListNode node = new SkipListNode(value, level); //构造当前节点
int currentLevel = level;
while(currentLevel-- > 0) {
//从最高层开始,遍历每一层
if(head.next[currentLevel] == null) {
//如果当前没有插入任何元素,直接插入即可
head.next[currentLevel] = node;
node.pre[currentLevel] = head;
} else {
SkipListNode current = head.next[currentLevel], pre = head;
//从第一个元素开始遍历
while(current != null && current.data < value) {
pre = current;
current = current.next[currentLevel];
}
//设置前置节点的后置节点为当前节点
pre.next[currentLevel] = node;
node.pre[currentLevel] = pre;
if(current != null) {
//如果没有遍历到结尾,则需要设置当前节点的前置节点
current.pre[currentLevel] = node;
node.next[currentLevel] = current;
}
}
}
usedLevel = usedLevel > level ? usedLevel : level;
}
//随机生成函数,即对于任意一个要插入跳表的节点,它的层级为多少
private int randomLevel() {
int level = 1;
for(int i = 1; i < MAX_LEVEL; i++) {
if(random.nextInt() % 2 == 1) {
level++;
}
}
return level;
}
private class SkipListNode{
private Integer data;
private SkipListNode[] next; //后置节点
private SkipListNode[] pre; //前置节点,方便删除使用
public SkipListNode(Integer data, int maxLevel) {
this.data = data;
next = new SkipListNode[maxLevel];
pre = new SkipListNode[maxLevel];
}
int getMaxlevel() {
return next.length;
}
}
public static void main(String[] args) {
SkipList skipList = new SkipList();
skipList.insert(10);
skipList.insert(25);
skipList.insert(83);
skipList.insert(20);
skipList.print();
System.out.println("------------------");
skipList.delete(83);
skipList.delete(20);
skipList.print();
}
}