8.3:加强堆的应用

news2024/11/24 16:08:51

8.3:加强堆的应用

题目要求:

做一个加强堆的题目,给定一个整型数组,int[] arr;和一个布尔类型数组,boolean[] op
两个数组一定等长,假设长度为N,arr[i]表示客户编号,op[i]表示客户操作
arr= [3,3,1,2,1,2,5…
op = [T,T,T,T,F,T,F…
依次表示:
3用户购买了一件商品
3用户购买了一件商品
1用户购买了一件商品
2用户购买了一件商品
1用户退货了一件商品
2用户购买了一件商品
5用户退货了一件商品…
一对arr[i]和op[i]就代表一个事件:
用户号为arr[i],op[i] == T就代表这个用户购买了一件商品
op[i] == F就代表这个用户退货了一件商品
现在你作为电商平台负责人,你想在每一个事件到来的时候,
都给购买次数最多的前K名用户颁奖。
所以每个事件发生后,你都需要一个得奖名单(得奖区)。
得奖系统的规则:
1,如果某个用户购买商品数为0,但是又发生了退货事件,
则认为该事件无效,得奖名单和上一个事件发生后一致,例子中的5用户
2,某用户发生购买商品事件,购买商品数+1,发生退货事件,购买商品数-1
3,每次都是最多K个用户得奖,K也为传入的参数
如果根据全部规则,得奖人数确实不够K个,那就以不够的情况输出结果
4,得奖系统分为得奖区和候选区,任何用户只要购买数>0,
一定在这两个区域中的一个
5,购买数最大的前K名用户进入得奖区,
在最初时如果得奖区没有到达K个用户,那么新来的用户直接进入得奖区
6,如果购买数不足以进入得奖区的用户,进入候选区
7,如果候选区购买数最多的用户,已经足以进入得奖区,
该用户就会替换得奖区中购买数最少的用户(大于才能替换),
如果得奖区中购买数最少的用户有多个,就替换最早进入得奖区的用户
如果候选区中购买数最多的用户有多个,机会会给最早进入候选区的用户
8,候选区和得奖区是两套时间,
因用户只会在其中一个区域,所以只会有一个区域的时间,另一个没有
从得奖区出来进入候选区的用户,得奖区时间删除,
进入候选区的时间就是当前事件的时间(可以理解为arr[i]和op[i]中的i)
从候选区出来进入得奖区的用户,候选区时间删除,
进入得奖区的时间就是当前事件的时间(可以理解为arr[i]和op[i]中的i)
9,如果某用户购买数==0,不管在哪个区域都离开,区域时间删除,
离开是指彻底离开,哪个区域也不会找到该用户
如果下次该用户又发生购买行为,产生>0的购买数,
会再次根据之前规则回到某个区域中,进入区域的时间重记
请遍历arr数组和op数组,遍历每一步输出一个得奖名单
public List<List> topK (int[] arr, boolean[] op, int k)
在这里插入图片描述

在这里插入图片描述

// 暴力解法思路:
// 1:根据题目要求我们可以得出,用户对象Customer有属性buy(购买数量),enterTime(进入时间),id(独自的ID)这三个属       性,与此同时我们还分析出有得奖区和等候区两个区域,即两个容器。返回的结果是List<List<Integer>>类型,即一个链表,       链表中存储的一个存储类型是Integer类型的一个链表,记录每一次的TOPK的顾客的ID。
// 2:根据题意我们知到:当没有这个人时,这个人还退货,那么直接跳过,进行下一次的操作。这里出现了一个问题,我们如何知到       有没有这个人,因为传进来的参数只有(ID, buyOrReund, k),难道我们要遍历那两个容器吗,时间复杂度太高,所以我们需要	   根据ID查找有没有这个人。所以我们可以写一个hashmap<Integer , Customer>,这样可以快速的查找又没有这个人,并且可       以快速的拿到这个人,需要注意是,hashmap中村的顾客是两个容器中所有buy!= 0的人。
// 3:2已经分析了一种情况:当没有这个人时,这个人还退货,还剩三种情况,(1):当没有这个人时,这个人还买货。(2):有这个       人时,这个人还买货。(3):有这个人时,这个人还退货。
// 4:(1): 创建这个顾客,Customer c = new Customer(id, i, 1);其进入的时间是现在的时间。因为一次只能买一个,所以buy       == 1,Hashmap中存一下,之后这个顾客放到那个容器中呢?如果终中奖区没满,就将其进中奖区。如果中奖区满了就将其放进       等待区,放完之后我们再调整两个区域,调正的准则是:中奖区最差的放在头,等候区最好的放在头。之后必将两个头,如果等	  候区的头的buy大于中奖区头的buy就交换。
//    (2):如果有这个人这个人还买货,或者是有这个人时,这个人还退货。我们可以通过hashmap根据这个人的ID迅速的得到这个       Customer,对其buy进行调整,c.buy++ or c.buy--,如果调整完以后他的buy == 0,那么就将这个对象删除。hashmap中删除       与此同时容器中的这个对象也要删除。由于不知到这个对象在那个容器中,所以两个容器都要删除一遍cleanZeroBuy(cands);       cleanZeroBuy(daddy);删完之后,或者是说buy调整完之后,两个容器需要调整。中奖区最差的放在头,等候区最好的放在         头。之后必将两个头,如果等候区的头的buy大于中奖区头的buy就交换。
//    最后生成TOPOK。

// 大根堆解法思路:
// 1:暴力解法中,使用的容器是Arraylist类型,其进行排序调整的时间复杂度是:NlogN,删除的时间复杂度是N,由于一共有N个数       据所以总的时间复杂度是: N^2logN.
// 2: 容器我们可以使用加强堆,这样调整的时间复杂度是logN,删除的时间复杂度也是logN,而且堆的调整我们可以自己写比较器,按       照自己的要求调整堆。总的时间复杂度降到NlogN
// 3:注意java中一般的堆,你只能存与取,非常的单一。不可以对堆中的元素进行修改,一修改就废了。因为他没法自己调整成正确       的堆。但是加强堆不同,她可以对堆中的元素进行修改,它可以自己调整成正确的堆。
// 大根堆的好处:可以对堆中的元素进行修改,它可以自己调整成正确的堆,并且调整的时间复杂度是logN级别的非常的高效,与此同    时能传入比较器,按照自己想要的规则进行tiao'zheng。

暴力解法

package algorithmbasic.class8;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

public class EveryStepShowBoss2 {
    // 顾客内部类
    public static class Customer {
        public int id;
        public int enterTime;
        public int buy;

        public Customer(int id, int enterTime, int buy) {
            this.id = id;
            this.enterTime = enterTime;
            this.buy = buy;
        }
    }

    // 属性
    // 存储返回值
    List<List<Integer>> ans = new ArrayList<>();
    // 得奖区
    ArrayList<Customer> daddy = new ArrayList<>();
    // 等候区
    ArrayList<Customer> cands = new ArrayList<>();
    // 查找是否有这个顾客 --> (根据id找customer)
    HashMap<Integer, Customer> map = new HashMap<>();

    // 方法
    public List<List<Integer>> topK2(int[] arr, boolean[] op, int k) {
        for (int i = 0; i < arr.length; i++) {
            int id = arr[i];
            boolean buyOrRefund = op[i];
            // 没有这个顾客并且退货
            if (!map.containsKey(id) && !buyOrRefund) {
                ans.add(this.getCurAns());
                continue;
            }
            // 没有这个顾客 -> 买
            // 有这个顾客 -> 退
            // 有这个顾客 -> 买
            // 这个是:没有这个顾客 -> 买
            if (!map.containsKey(id)) {
                Customer c = new Customer(id, i, 1);
                map.put(id, c);
                // cands / daddy 中加
                if (daddy.size() < k) {
                    daddy.add(c);
                } else {
                    cands.add(c);
                }
                // 后面会涉及一个调整
            } else { // 有这个顾客 -> 退  有这个顾客 -> 买
                Customer c = map.get(id);
                if (buyOrRefund) {
                    c.buy++;
                } else {
                    c.buy--;
                }
                if (c.buy == 0) {
                    map.remove(id);
                    // 只会执行其中一个
                    // N
                    cleanZeroBuy(cands);
                    cleanZeroBuy(daddy);
                }
            }
            // 调整
            // NlogN
            cands.sort(new CandsComparator());
            daddy.sort(new DaddyComparator());
            // 是否要交换位置
            move(k, i);
            // 生成topK
            // K
            ans.add(getCurAns());
        }
        return ans;
    }

    // 将中奖区的topK放到 List<Integer> 中
    public List<Integer> getCurAns() {
        List<Integer> list = new ArrayList<>();
        for (Customer c : this.daddy) {
            list.add(c.id);
        }
        return list;
    }

    // 删除daddy/cands中购买数为0的顾客
    public void cleanZeroBuy(ArrayList<Customer> arr) {
        List<Customer> noZero = new ArrayList<Customer>();
        for (Customer c : arr) {
            if (c.buy != 0) {
                noZero.add(c);
            }
        }
        arr.clear();
        for (Customer c : noZero) {
            arr.add(c);
        }
    }

    // 等候区与中奖区是否要交换位置
    public void move(int k, int time) {
        if (cands.isEmpty()) {
            return;
        }
        if (daddy.size() < k) {
            Customer c = cands.get(0);
            c.enterTime = time;
            cands.remove(0);
            daddy.add(c);
        } else if (cands.get(0).buy > daddy.get(0).buy) {
            Customer c1 = cands.get(0);
            c1.enterTime = time;
            Customer c2 = daddy.get(0);
            c2.enterTime = time;
            cands.remove(0);
            daddy.remove(0);
            daddy.add(c1);
            cands.add(c2);
        }
    }

    // 比较器
    // 中奖区的比较器  ->  最烂的在前面
    public class DaddyComparator implements Comparator<Customer> {
        @Override
        public int compare(Customer o1, Customer o2) {
            return o1.buy != o2.buy ? (o1.buy - o2.buy) : (o1.enterTime - o2.enterTime);
        }
    }

    // 等待区的比较器  ->  最好的在前面
    public class CandsComparator implements Comparator<Customer> {
        @Override
        public int compare(Customer o1, Customer o2) {
            return o1.buy != o2.buy ? (o2.buy - o1.buy) : (o1.enterTime - o2.enterTime);
        }
    }
}

大根堆解法:

package algorithmbasic.class8;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

// 用加强堆实现
public class EveryStepShowBoss3 {
    // 顾客内部类
    public static class Customer {
        public int id;
        public int enterTime;
        public int buy;

        public Customer(int id, int enterTime, int buy) {
            this.id = id;
            this.enterTime = enterTime;
            this.buy = buy;
        }
    }

    // 比较器
    // 中奖区的比较器  ->  最烂的在前面
    public class DaddyComparator implements Comparator<Customer> {
        @Override
        public int compare(Customer o1, Customer o2) {
            return o1.buy != o2.buy ? (o1.buy - o2.buy) : (o1.enterTime - o2.enterTime);
        }
    }

    // 等待区的比较器  ->  最好的在前面
    public class CandsComparator implements Comparator<Customer> {
        @Override
        public int compare(Customer o1, Customer o2) {
            return o1.buy != o2.buy ? (o2.buy - o1.buy) : (o1.enterTime - o2.enterTime);
        }
    }

    // 属性
    // 查找是否有这个顾客 --> (根据id找customer)
    HashMap<Integer, Customer> map;
    // 得奖区
    HeapGreater<Customer> daddy;
    // 等候区
    HeapGreater<Customer> cands;
    // 中奖区最多容纳人数
    final int daddyLimit;



    // 构造器
    public EveryStepShowBoss3(int daddyLimit) {
        this.daddyLimit = daddyLimit;
        map = new HashMap<>();
        daddy = new HeapGreater<>(new DaddyComparator());
        cands = new HeapGreater<>(new CandsComparator());
    }

    // 方法
    public List<List<Integer>> topK(int[] arr, boolean[] op, int k) {
        // 返回的结果存放区
        List<List<Integer>> ans = new ArrayList<>();
        EveryStepShowBoss3 everyStepShowBoss3 = new EveryStepShowBoss3(k);
        for (int i = 0; i < arr.length; i++) {
            operate(i, arr[i] , op[i] , ans);
        }
        return ans;
    }

    public void operate(int time, int id, boolean buyOrRefund , List<List<Integer>> ans) {
        // 没有这个顾客并且退货
        if(!map.containsKey(id) && !buyOrRefund) {
            ans.add(this.getCurAns());
            return;
        }
        // 没有这个顾客 -> 买
        // 有这个顾客 -> 退
        // 有这个顾客 -> 买
        if(!map.containsKey(id)) {
            Customer c = new Customer(id, time, 1);
            map.put(id, c);
            if(daddy.size() < daddyLimit) {
                // 会自动调整
                daddy.push(c);
            }else {
                cands.push(c);
            }
        }else {
            Customer c = map.get(id);
            if(buyOrRefund) {
                c.buy++;
            }else {
                c.buy--;
            }
            if(cands.contains(c)) {
                if(c.buy == 0) {
                    cands.remove(c);
                    map.remove(id);
                }else {
                    // 调整一下
                    cands.resign(c);
                }
            }else {
                if(c.buy == 0) {
                    daddy.remove(c);
                    map.remove(id);
                }else {
                    // 调整一下
                    daddy.resign(c);
                }
            }
        }
        // 是否要交换位置
        move(time);
        // 生成topK
        ans.add(this.getCurAns());
    }

    public void move(int time) {
        if(cands.isEmpty()) {
            return;
        }
        if(daddy.size() < daddyLimit) {
            Customer c = cands.pop();
            c.enterTime = time;
            daddy.push(c);
        }else {
            if(cands.peek().buy > daddy.peek().buy) {
                Customer c1 = cands.pop();
                c1.enterTime = time;
                Customer c2 = daddy.pop();
                c2.enterTime = time;
                cands.push(c2);
                daddy.push(c1);
            }
        }
    }

    // 将中奖区的topK放到 List<Integer> 中
    public List<Integer> getCurAns() {
        List<Customer> c =  daddy.getAllElements();
        List<Integer> list = new ArrayList<>();
        for (Customer cus : c) {
            list.add(cus.id);
        }
        return list;
    }
}

Heapgreater

package algorithmbasic.class8;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

// 加强堆
public class HeapGreater<T> {
    private ArrayList<T> heap;
    private int heapSize;
    private HashMap<T, Integer> indexMap;
    private Comparator<? super T> comp;

    public HeapGreater(Comparator<? super T> comp) {
        this.heap = new ArrayList<>();
        indexMap = new HashMap<>();
        this.heapSize = 0;
        this.comp = comp;
    }

    public boolean isEmpty() {
        return this.heapSize == 0;
    }

    public int size() {
        return this.heapSize;
    }

    public boolean contains(T obj) {
        return this.indexMap.containsKey(obj);
    }

    public T peek() {
        return this.heap.get(0);
    }

    // logN
    public void push(T obj) {
        heap.add(obj);
        indexMap.put(obj, heapSize);
        heapInsert(heapSize++);
    }

    // logN
    public void heapInsert(int index) {
        int father = (index - 1) / 2;
        while (this.comp.compare(heap.get(index), heap.get(father)) < 0) {
            // 注意交换的时候,ArrayList中的K V需要交换,HashMap中的K V也需要交换。
            swap(father, index);
            index = father;
            father = (index - 1) / 2;
        }
    }

    // logN
    public T pop() {
        T ans = heap.get(0);
        swap(0, --heapSize);
        indexMap.remove(ans);
        // 注意:其实Arraylist里面已经有一个heapsize这样的尾指针,这里我们自己定义的heapsize只是为了方便我们找到尾节点下标。
        // 真正意义上删除一个节点还是需要Arraylist里面的尾指针进行操作的。
        heap.remove(heapSize); // 真正的将尾节点删除。
        heapFiy(0);
        return ans;
    }

    // logN
    public void heapFiy(int index) {
        int l = index * 2 + 1;
        while (l < heapSize) {
            int minSonIndex = l + 1 < heapSize ? (this.comp.compare(heap.get(l), heap.get(l + 1)) < 0 ? l : l + 1) : (l);
            if(this.comp.compare(heap.get(minSonIndex), heap.get(index)) < 0) {
                swap(minSonIndex, index);
                index = minSonIndex;
                l = index * 2 + 1;
            }else {
                break;
            }
        }
    }

    // logN
    public void remove(T obj) {
        // 得到节点的位置index
        int index = indexMap.get(obj);
        // 得到末尾的数 value
        T replace = heap.get(--heapSize);
        // 将hashmap中obj值以及heap中末尾的数直接删掉
        indexMap.remove(obj);
        // 真正的删除尾节点。
        heap.remove(heapSize);
        // 如果末尾节点值与obj是同一个,不需要一下操作
        if (obj != replace) {
            // 将结果塞回去
            heap.set(index, replace);
            indexMap.put(replace, index);
            resign(replace);
        }
    }

    // 重构造
    // 只会执行其中的一个,logN
    public void resign(T obj) {
        heapInsert(indexMap.get(obj));
        heapFiy(indexMap.get(obj));
    }

    // 请返回堆上的所有元素
    public List<T> getAllElements() {
        List<T> ans = new ArrayList<>();
        for (T c : heap) {
            ans.add(c);
        }
        return ans;
    }

    public void swap(int i, int j) {
        T value1 = heap.get(i);
        T value2 = heap.get(j);
        heap.set(i, value2);
        heap.set(j, value1);
        // HashMap新的值覆盖旧的值
        indexMap.put(value1, j);
        indexMap.put(value2, i);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/579331.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【程序人生】上海城市开发者社区小聚有感

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…

shell脚本入门-编写格式以及执行方式

Shell介绍 通过编写shell命令发送给linux内核去执行&#xff0c;操作就是计算机硬件&#xff0c;所以Shell命令是用户操作计算机硬件的桥梁 Shell是命令&#xff0c;类似与windows系统的Dos命令 Shell是一门程序设计语言&#xff0c;shell里面含有变量&#xff0c;函数&#xf…

低代码助力企业数字化转型:构建高效业务系统的新选择

在当今数字化时代&#xff0c;企业数字化转型已经成为业界的热门话题。随着全球各大企业逐渐意识到数字化转型的重要性&#xff0c;越来越多的公司开始采用低代码开发平台作为数字化转型的工具&#xff0c;以低成本高效率构建业务系统&#xff0c;实现数字化转型。 但现实情况是…

Less基础速学 —— 混入、运算、继承

Less 混合 在上一篇内容中就已经简单的了解了关于CSS预处理器 —— Less&#xff0c;本篇就往下讲Less中的混合&#xff0c;什么是混合&#xff1f;就是将一系列属性从一个规则集引入到另外一个规则集的方式。下面来看一下它的混合方式有哪些&#xff1f; 普通混合 <div …

使用OpenCvSharp来计算图像的清晰度(可实现相机自动对焦)

相机自动对焦&#xff0c;其实是对相机成像的清晰值得计算&#xff0c;若对焦不清晰&#xff0c;成像的清晰度低&#xff0c;视觉效果模糊。若是在工业检测行业&#xff0c;对焦不准确&#xff0c;可能导致信息不正确&#xff1b;对焦准确的图像&#xff0c;其清晰度高&#xf…

长连接心跳原理与机制工程上踩坑与优化

QA: 业务上对于心跳间隔一般怎么确定? 心跳间隔的确定一般需要根据具体业务场景和需求来进行。以下是一些常见的确定心跳间隔的方法&#xff1a; 根据应用场景和需求来确定心跳间隔。例如&#xff0c;在智能手环等健康监测设备中&#xff0c;心跳间隔通常设置为几秒钟到几分钟…

华为OD机试之过滤组合字符串(Java源码)

过滤组合字符串 题目描述 每个数字关联多个字母&#xff0c;关联关系如下&#xff1a; 0 关联 “a”,”b”,”c”1 关联 “d”,”e”,”f”2 关联 “g”,”h”,”i”3 关联 “j”,”k”,”l”4 关联 “m”,”n”,”o”5 关联 “p”,”q”,”r”6 关联 “s”,”t”7 关联 “u”…

六级备考24天|CET-6|翻译技巧4|翻译红楼梦|22:40~23:40

目录 作题步骤 红楼梦 12 PRACTICE ANSWER​ 时态问题 3 ANSWER 4 PRACTICE ANSWER ​ 5​ PRACTICE ANSWER 合并 ​ 全文翻译​ 作题步骤 不要拿到题目就动笔、一定要先读题、重建逻辑、找句子主干、有能力可以润色简化&#xff01; 红楼梦 12 PRACTICE Dream of th…

【java】leetcode 二叉树展开为链表

二叉树展开为链表 leetcode114 .二叉树展开为链表解题思路二叉树专题&#xff1a; leetcode114 .二叉树展开为链表 114 leetcode 链接。可以打开测试 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#x…

【Redis】共同关注列表与基于Feed流的关注消息滚动分页推送的实现

目录 一、共同关注 1、思路 2、实现步骤 二、Feed流 1、概念 2、需求 3、TimeLine的三种模式 1.拉 2.推 3.推拉结合 4、TimeLine三种模式的区别 三、关注推送 1、需求 2、实现思路 3、Redis数据结构的选择 4、滚动分页 5、代码实现 1.博主 2.粉丝 一、共同关…

Packet Tracer - 在 VTY 线路上配置 ACL

Packet Tracer - 在 VTY 线路上配置 ACL 地址分配表 设备 接口 IP 地址 子网掩码 默认网关 路由器 F0/0 10.0.0.254 255.0.0.0 不适用 PC NIC 10.0.0.1 255.0.0.0 10.0.0.254 笔记本电脑 NIC 10.0.0.2 255.0.0.0 10.0.0.254 拓扑图 目标 第 1 部分&#…

企业性能测试全面解析,一步步教你进行性能测试!

目录 前言&#xff1a; 性能需求调研 性能测试计划制定 性能测试执行 性能测试结果分析与优化 结尾&#xff1a; 前言&#xff1a; 在软件开发过程中&#xff0c;性能测试是一个非常重要的环节。性能测试的主要目的是评估系统在负载情况下的响应时间、吞吐量、稳定性等指…

【C语言】二分查找(含图解)

文章目录 1. 二分查找思想2. 代码实现2.1 未封装函数2.2 封装函数&#xff08;使用while循环&#xff09;2.3 封装函数&#xff08;使用递归&#xff09; 1. 二分查找思想 二分法&#xff1a;二分查找算法是一种在有序数组中查找某一特定元素的搜索算法&#xff0c;其思想就是…

【Linux】多线程操作

文章目录 一. 线程库二. 多线程操作1. 线程创建2. 线程等待3. 线程退出4. 线程取消5. 线程分离6. 返回值 三. 多线程理解结束语 一. 线程库 在Linux下&#xff0c;并没有真正的线程&#xff0c;只有用进程模拟的轻量级进程&#xff0c;所以Linux并没有提供可以直接创建线程的接…

JavaScript教程(三)之 jQuery

JavaScript库 即library&#xff0c;是一个封装好的特定的集合&#xff08;方法和函数&#xff09;。从封装一大堆函数的角度理解库&#xff0c;就是在这个库中&#xff0c;封装了很多预先定义好的函数在里面&#xff0c;比如动画animate、hide、show&#xff0c;比如获取元素…

每日学术速递5.25

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Chupa: Carving 3D Clothed Humans from Skinned Shape Priors using 2D Diffusion Probabilistic Models 标题&#xff1a;Chupa&#xff1a;使用 2D 扩散概率模型从蒙皮形状先验雕…

理解Window和WindowManager(一)

理解Window和WindowManager(一) Window是一个抽象类,它的具体实现是PhoneWindow,创建一个WindowManager就可以创建一个Window&#xff0c; Window的具体实现位于WindowManagerService中,WindowManager和WindowManagerService是一个IPC过程 为什么使用Window 首先就是Window…

redis持久化【RDB+AOF】持久化双雄

这是redis系列文章之《redis持久化【RDBAOF】持久化双雄》&#xff0c;上一篇文章【redis基础】redis的十大数据类型_努力努力再努力mlx的博客-CSDN博客 感谢大家的支持~ 目录 RDB 什么是RDB RDB的作用 配置文件关于RDB部分 6vs7 操作步骤 修改配置文件&#xff08;本案…

通过python采集整站lazada商品列表数据,支持多站点

要采集整站lazada商品列表数据&#xff0c;需要先了解lazada网站的结构和数据源。Lazada是东南亚最大的电商平台之一&#xff0c;提供各种商品和服务。Lazada的数据源主要分为两种&#xff1a;HTML和API。 方法1&#xff1a;采集HTML数据 步骤1&#xff1a;确定采集目标 首先…

Redis - Redis为什么快

根据官方数据&#xff0c;Redis 的 QPS 可以达到约 100000&#xff08;每秒请求数&#xff09;&#xff0c;有兴趣的可以参考官方的基准程序测试《How fast is Redis&#xff1f;》&#xff0c;官方地址&#xff1a; https://redis.io/topics/benchmarks 横轴是连接数&#xf…