精华内容
下载资源
问答
  • 平均分配算法

    千次阅读 2019-10-29 01:58:46
    最近公司业务需求:要求实现批量分配操作,详情如下: 选择多个客户 ...为了实现上述需求,需要设计一个随机平均分配算法 一开始我的设计思路比较简单,遍历员工集合和客户集合,依次分配单个客户给每个...
    最近公司有业务需求:要求实现批量分配操作,详情如下:
    
    选择多个客户
    选择多个员工
    给每个员工分配客户
    要求分配的客户数量尽量平均
    选择的员工数大于选择的客户数时,一个员工分配一个客户,不够的就不分配
    选择的员工数等于客户数时,一个员工对应一个客户
    分配的客户最好是随机的。
    为了实现上述需求,需要设计一个随机平均分配算法
    一开始我的设计思路比较简单,遍历员工集合和客户集合,依次分配单个客户给每个员工,直到分完为止,但是这种实现效率很低,也达不到随机的效果。
    转变思路,先分析、设计数据存储结构,入参为两个List<String>集合,返回数据类型为:
    一、 Map<String, List<String>>,每个员工作为key,value为分配的客户列表;
    二、List<Map<String, List<String>>>,员工作为key,value为分配给他的客户,每个员工-客户列表都对应一个Map<String, List<String>>集合,这样所有的员工-客户列表组合成一个List<Map<String, List<String>>>集合
    最终我采用了第二种数据结构,下面是实现代码:
    import com.google.common.collect.Lists;
    import com.google.common.collect.Maps;
    import com.google.common.collect.Sets;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.lang3.RandomStringUtils;
    import org.apache.commons.lang3.RandomUtils;
    import org.apache.commons.lang3.StringUtils;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    /**
    * @author gxl
    * @version 1.0
    * @description 平均分配算法
    * @date 2019-09-11 08:53
    */
    public class AverageDataUtil {
    
       /**
        * 定义存储待分配数据集合
        */
       private static List<String> list = Lists.newArrayList();
    
       /**
        * 定义存储分组数据的结构,Map去除泛型,适配多种数据类型格式,使用时需注意
        */
       private static List<Map> los = Lists.newArrayList();
    
       /**
        * 供外部调用的平均分配方法
        *
        * @param visitorIds 客户列表
        * @param sellerIds  员工列表
        * @return List<Map>
        */
       public static List<Map> averageData(List<String> visitorIds, List<String> sellerIds) {
           initCollections(visitorIds, sellerIds);
           if (visitorIds.size() >= sellerIds.size()) {
               groupByData(los.size());
               return getMaps();
           } else {
               groupByData(list.size());
               return getMaps();
           }
       }
    
       /**
        * 返回数据,清空静态缓存
        *
        * @return List<Map>
        */
       @NotNull
       private static List<Map> getMaps() {
           List<Map> listMap = Lists.newArrayList();
           listMap.addAll(los);
           //清空静态数据
           los = Lists.newArrayList();
           list = Lists.newArrayList();
           return listMap;
       }
    
       /**
        * 分配数据
        *
        * @param size       分组大小
        */
       private static void groupByData(int size) {
           List<String> augmented = list;
    
           List<List<String>> lists = chunk2(augmented, size);
    
           for (int i = 0; i < size; i++) {
               Map map = los.get(i);
               Iterator iterator = map.keySet().iterator();
               if (iterator.hasNext()) {
                   String next = (String) iterator.next();
                   map.put(next, lists.get(i));
               }
           }
       }
    
       /**
        * 初始化集合数据
        *
        * @param visitorIds 待分配数据
        * @param sellerIds  分配目标
        */
       private static void initCollections(List<String> visitorIds, List<String> sellerIds) {
           //每次调用前清空数据
           if (list.size() > 0) {
               list = Lists.newArrayList();
           }
           if (los.size() > 0) {
               los = Lists.newArrayList();
           }
           list.addAll(visitorIds);
           List<Map<String, List<String>>> list1 = new ArrayList<>();
           for (String sellerId : sellerIds) {
               Map<String, List<String>> map = new HashMap<>(16);
               List<String> list = new ArrayList<>();
               map.put(sellerId, list);
               list1.add(map);
           }
           los.addAll(list1);
       }
    
       /**
        * 分组数据-核心算法,勿动
        *
        * @param list  需分配数据
        * @param group 分组大小
        * @param <T>   分组数据泛型
        * @return 分组结果
        */
       private static <T> List<List<T>> chunk2(List<T> list, int group) {
           if (CollectionUtils.isEmpty(list)) {
               return Lists.newArrayList();
           }
           List<List<T>> result = Lists.newArrayList();
           Map<Integer, Set<T>> temp = Maps.newHashMap();
           for (int i = 0; i < list.size(); i++) {
               if (temp.containsKey(i % group)) {
                   Set<T> ts = temp.get(i % group);
                   ts.add(list.get(i));
                   temp.put(i % group, ts);
               } else {
                   Set<T> ts = Sets.newHashSet();
                   ts.add(list.get(i));
                   temp.put(i % group, ts);
               }
           }
           for (Set<T> ts : temp.values()) {
               result.add(Lists.newArrayList(ts));
           }
           return result;
       }
       
       public static void main(String[] args) {
           List<String> visitorIds = new ArrayList<>();
           visitorIds.add("aa");
           visitorIds.add("bb");
           visitorIds.add("cc");
           visitorIds.add("dd");
           visitorIds.add("ee");
           visitorIds.add("ff");
           visitorIds.add("gg");
           visitorIds.add("hh");
           visitorIds.add("ii");
           visitorIds.add("jj");
           visitorIds.add("kk");
           List<String> sellerIds = new ArrayList<>();
           sellerIds.add("11");
           sellerIds.add("22");
           sellerIds.add("33");
           sellerIds.add("44");
           sellerIds.add("55");
           sellerIds.add("66");
           sellerIds.add("77");
           sellerIds.add("88");
           sellerIds.add("99");
           sellerIds.add("1010");
           sellerIds.add("1111");
           List<Map> maps = averageData(visitorIds, sellerIds);
           System.out.println(maps);
       }
    
    }
    
    
    这个代码可能还存在部分问题,可以继续优化改进,有什么建议的话,可以在评论区回复,毕竟我也只是个码农,对算法什么的不是很了解 - -
    

     

    展开全文
  • 场景:N张图片,M图片类型,每张图片可以同时属于1-M类型。现要把N张图片按照类型分配,使得每类型的图片数量差不多。 请高手们给个思路。多谢啦~
  • 基于平均思想的任务分配算法

    万次阅读 多人点赞 2017-08-28 19:37:52
    假设现在20个任务需要分配给员工去做,但是每个员工手头上还有未完成的任务,且未完成任务数不同。

            假设现在有n个任务需要分配给m个审核员去完成,但是每个审核员手头上还有未完成的任务,且未完成的任务数不同。那么如何均匀的把这些任务分配给各个审核员呢?这里我提出了一种基于平均思想的任务分配算法(我称之为标杆算法)。

            算法的主要思想是:首先找出所有审核员中手头未完成任务数最大的审核员,然后其它审核员以该审核员的未完成任务数为标杆,计算自己可容纳的任务数,最后所有审核员可容纳的任务数之和即为总的可容纳任务数(ava_task)。

            这里有两种情况,第一种情况是:总的可容纳任务数小于或等于n个待分配的任务数,此时所有审核员以最大未完成任务数(max_task)为标杆,接收待分配的任务。如果刚好分配完,那么算法结束;如果还有剩下的任务未分配,那将剩下的任务抽取m个任务分配给每一个审核员,依次类推,直到剩下的未分配任务数小于m为止,然后再将这小于m的任务随机分配给相应数量的审核员。第二种情况是:总的可容纳任务数大于n个待分配的任务数,此时降低一个单位的标杆(max_task-1),然后循环计算可容纳的任务数,直到退出循环(循环终止条件为:ava_task - task_num <= lower_List.size(),lower_List.size()表示的是低于当前标杆的审核员数)。

            接下来,我们将通过一个简单的例子来说明算法的流程,由于第一种情况比较简单,因此,该例子是基于第二种情况的,,如图1所示。


    图1

            假设有20个任务需要分配给8个审核员(对应8个条形图,实线条形图里的数字代表该审核员手头未完成的任务数)。首先找出这8个审核员中未完成任务数的最大值max_task=7,然后各审核员以max_task为标杆计算各自可容纳的任务数(对应虚线条形图里的数字),总的可容纳任务数为所有审核员可容纳的任务数之和,即ava_task=6+3+4+2+5+0+5+6=31,由图1可知,lower_List.size()=7,由于31-20>7,因此可降低一个单位的标杆,即max_task=max_task-1=6,如图2所示。


             那么,ava_task=5+2+3+1+4+0+4+5=24,lower_List.size()=7,由于24-20<7,因此循环终止。由于可容纳的任务数仍然大于待分配的任务数,因此需要再降低一个单位的标杆(一定要考虑这种情况),max_task=max_task-1=5,此时ava_task=4+1+2+0+3+0+3+4=17,lower_List.size()=6,剩余待分配任务数为20-17=3,然后将这3个任务随机分配给低于当前标杆的6个审核员中的3个,每个审核员分配一个。当然算法中还考虑了很多种情况,具体请参见如下代码。由于任务一般按审核员ID来分配,且ID一般为字符串。为了存储方便,我定义了一个二维字符串类型的数组rev_task[i][j]来存储数据,i表示第i个审核员,rev_task[i][0]存放的是第i个审核员的ID,rev_task[i][1]存放的是第i个审核员当前未完成的任务数,rev_task[i][2]存放的是第i个审核员应当被分配的任务数。

    算法工具类-AlgorithmUtils.java

    package com.yushen.allocationAlgorithm;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    import java.util.Random;
    
    public class AlgorithmUtils {
        public static void taskAllocation(int task_num, int rev_num, String[][] rev_task) {
    
            Random rd = new Random();
            List<Integer> rdList = new ArrayList<>();
            int temp;
    
            //获得审核人员中的最大未完成任务数
            int max_task = Integer.parseInt(rev_task[0][1]);
            for(int i = 1; i < rev_num; i++){
                if(max_task < Integer.parseInt(rev_task[i][1]))
                    max_task = Integer.parseInt(rev_task[i][1]);
            }
    
            //以最大待审核任务数为标杆,判断第一轮可容纳的任务数
            int ava_task = 0;
            List<Integer> lower_List = new ArrayList<>();
            for(int i=0;i<rev_num;i++){
                if((max_task-Integer.parseInt(rev_task[i][1])) > 0){
                    ava_task += (max_task-Integer.parseInt(rev_task[i][1]));
                    lower_List.add(i);
                }
            }
    
            int task_rest;
            int task_avg;
            //第一种情况:第一轮可容纳的任务数小于待分配的任务数
            if(ava_task - task_num <= 0) {
                for(int i = 0; i < rev_num; i++) {
                    rev_task[i][2] = String.valueOf(max_task-Integer.parseInt(rev_task[i][1]));
                }
                task_rest = task_num-ava_task;
                task_avg = task_rest/rev_num;
                if(task_rest != 0) {
                    while(task_avg > 0) {
                        for(int i = 0; i < rev_num; i++) {
                            rev_task[i][2] = String.valueOf(Integer.parseInt(rev_task[i][2])+task_avg);
                        }
                        task_rest -= rev_num*task_avg;
                        task_avg = task_rest/rev_num;
                    }
                    rdList.removeAll(rdList);
                    while(rdList.size() < (task_rest+1)){
                        temp = rd.nextInt(rev_num);
                        if(!rdList.contains(temp)){
                            rdList.add(temp);
                        }
                    }
                    for(int i = 0; i < task_rest; i++) {
                        rev_task[rdList.get(i)][2] = String.valueOf(Integer.parseInt(rev_task[rdList.get(i)][2])+1);
                    }
                }
            }else {//第二种情况:第一轮可容纳的任务数大于待分配的任务数,此时降低一个单位的标杆(max_task-1),然后循环计算可容纳的任务数,直到退出循环
                while(ava_task - task_num > lower_List.size()) {
                    max_task--;
                    ava_task = 0;
                    lower_List.removeAll(lower_List);
                    for(int i=0;i<rev_num;i++){
                        rev_task[i][2] = "0";
                        if((max_task-Integer.parseInt(rev_task[i][1])) > 0){
                            rev_task[i][2] = String.valueOf(max_task-Integer.parseInt(rev_task[i][1]));
                            ava_task += Integer.parseInt(rev_task[i][2]);
                            lower_List.add(i);
                        }
                    }
                }
                if(ava_task - task_num > 0) {//如果可容纳的任务数大于待分配的任务数,那么需要再再降低一个单位的标杆
                    max_task--;
                    ava_task = 0;
                    lower_List.removeAll(lower_List);
                    for(int i=0;i<rev_num;i++){
                        if((max_task-Integer.parseInt(rev_task[i][1])) >= 0){
                            rev_task[i][2] = String.valueOf(max_task-Integer.parseInt(rev_task[i][1]));
                            ava_task += Integer.parseInt(rev_task[i][2]);
                            lower_List.add(i);
                        }
                    }
                    task_rest = task_num - ava_task;
                    rdList.removeAll(rdList);
                    while(rdList.size() < (task_rest+1)){
                        temp = rd.nextInt(rev_num);
                        if((!rdList.contains(temp))&&(lower_List.contains(temp))){
                            rdList.add(temp);
                        }
                    }
                    for(int i = 0; i < task_rest; i++) {
                        rev_task[rdList.get(i)][2] = String.valueOf(Integer.parseInt(rev_task[rdList.get(i)][2])+1);
                    }
                }else {
                    task_rest = task_num-ava_task;
                    if(task_rest != 0) {
                        rdList.removeAll(rdList);
                        while(rdList.size() < (task_rest+1)){
                            temp = rd.nextInt(rev_num);
                            if((!rdList.contains(temp))&&(lower_List.contains(temp))){
                                rdList.add(temp);
                            }
                        }
                        for(int i = 0; i < task_rest; i++) {
                            rev_task[rdList.get(i)][2] = String.valueOf(Integer.parseInt(rev_task[rdList.get(i)][2])+1);
                        }
                    }
                }
            }
    
            //记录被分配的任务数
            for(int i=0;i<rev_num;i++){
                rev_task[i][1] = String.valueOf(Integer.parseInt(rev_task[i][1])+Integer.parseInt(rev_task[i][2]));
            }
        }
    }
    算法测试类-TestAlgorithm.java
    package com.yushen.allocationAlgorithm;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    import java.util.Scanner;
    
    public class TestAlgorithm {
    
    	public static void main(String[] args) {
    		
    	    Scanner sc=new Scanner(System.in);
    	    System.out.println("请输入任务数:");
    	    int task_num = sc.nextInt();
    	    System.out.println("请输入审核人员的当前未完成任务数组,整数数字输入时用英文逗号隔开:");
    	    String inputString=sc.next().toString();
    	    String stringArray[]=inputString.split(",");
    	    
    	    int rev_num = stringArray.length;//审核人员总数
    	    String[][] rev_task =new String[rev_num][3];
    	    Random rd = new Random();
    	    List<Integer> rdList = new ArrayList<>();
    	    rdList.removeAll(rdList);
    	    int temp;
    	    while(rdList.size() < (rev_num+1)){
    	    	temp = rd.nextInt(100);
                    if(!rdList.contains(temp)){
    		    rdList.add(temp);
                    }  
                }
    	    
    	    System.out.println("算法前的任务分配:");
    	    for(int i=0;i<rev_num;i++){
    	    	rev_task[i][0] = String.valueOf(rdList.get(i) + 1);
    	    	rev_task[i][1]= stringArray[i];
    	    	rev_task[i][2] = "0";
    	    	System.out.print(rev_task[i][0]+","+rev_task[i][1]+" ");
    	    }
    	    System.out.println();
    	     
                AlgorithmUtils.taskAllocation(task_num, rev_num, rev_task);//调用算法工具类
                System.out.println("算法后的任务分配:");    
                for(int i=0;i<rev_num;i++){    
                    System.out.print(rev_task[i][0]+","+rev_task[i][1]+" ");  
                } 
            }
    }
    运行结果:
    请输入任务数:
    20
    请输入审核人员的当前未完成任务数组,整数数字输入时用英文逗号隔开:
    1,4,3,5,2,7,2,1
    算法前的任务分配:
    72,1 63,4 73,3 49,5 74,2 43,7 100,2 20,1 
    算法后的任务分配:
    72,5 63,5 73,5 49,6 74,5 43,7 100,6 20,6

    由运行结果可知,20个任务均衡的分配给了每个审核人员,达到了平均分配的目的!
    本人才疏学浅,如有疏漏,请各位大虾不吝赐教!

    展开全文
  • 最近遇到需要从经理批量分配订单到主管,主管批量分配订单到人员,我们只需要设计一种算法经理到主管(主管到人类似),尽量保证经理分配到主管的订单的平均金额与数据库里面的平均金额相等。我为此设计了两种算法如下...

    1.项目背景

    最近遇到需要从经理批量分配订单到主管,主管批量分配订单到人员,我们只需要设计一种算法经理到主管(主管到人类似),尽量保证经理分配到主管的订单的平均金额与数据库里面的平均金额相等。我为此设计了两种算法如下,仅供参考。


    2.算法以及java实现

    2.1 算法1

    2.1.1 算法思路

    此算法是先传入所有组(一组对应一个主管)需要分配的订单数,按分配的订单数从大到小排序,比如A,B,C三组,订单数为5,3,1。再从数据库里获取一批数据按照订单金额从高到低排序到一个list。

    比如数据库里订单金额及订单号为(a99,99)...(a1,1)。第一轮分配先取最大的订单金额的分配给A,即A拥有a99,B分配到a98,C分配到a97。第二轮分配最小值,A分配a1,B分配a2,第三轮分配最大值,即A分配a96,B分配a95,以此类推。

    2.1.2 算法实现如下

    	int unallocated = collectionService.findAllUnabsorbedCollectionCount(collectionVo);
    
    	int assignCount = 0;
    	for(GroupInfoRecord groupInfoRecord : req.getGroupInfoRecord()){ 
    	    assignCount += groupInfoRecord.getAssignCount(); //获取总分配数
    	}
    	if(unallocated < assignCount ){
    		return BusRsp.faild(Constant.CODE_FAILD, "经理未分配总数:"+unallocated+" 需要分配数量之和:"+assignCount+";超出分配数量");
    	}
    
            collectionVo.setCollectionNum(assignCount);
    	//部门分配到组
            // 查出分配的订单id
            List<CollectionPo> collectionIdList = collectionService.findGroupAssignCollectionId(collectionVo);
            LinkedList<CollectionPo> linkedList = new LinkedList(collectionIdList); //把list转为LinkedList,方便对头尾进行操作
    
    	int listSize = linkedList.size();
    
            //先把组进行排序,按照订单量从高到低排序
            Map<String,Integer> map =  new TreeMap<>(); //key:人员id value: 分配订单数
            for(GroupInfoRecord groupInfoRecord : req.getGroupInfoRecord()){
                map.put(groupInfoRecord.getGroupId(),groupInfoRecord.getAssignCount());
            }
    
            //将我们得到的map按照金额降序排列
            // 将map.entrySet()转换成list,该list已经按照订单数从大到小排序
            List<Map.Entry<String, Integer>> list = new ArrayList<>(map.entrySet());
            //降序排序
            Collections.sort(list, (o1, o2) -> o2.getValue().compareTo(o1.getValue()));//这里可转为lambda表达式
    
            // requestNum 代表页面提交的数目 requestGet表示数组当前已经变化的数值 groupIds存放的是requestNum数目对应的人员id
            int[] requestNum = new int[map.size()];
            int[] requestGet = new int[map.size()];
            String[] groupIds = new String[map.size()];
            int j = 0;
            //给人员id以及对应的数目赋值
            for (Map.Entry<String, Integer> mapping : list) {
                System.out.println("key:"+mapping.getKey() + "  value: " + mapping.getValue());
                groupIds[j] = mapping.getKey();
                requestNum[j] = mapping.getValue();
                j++;
            }
    
    
    
            boolean[] requestGetFlag = new boolean[map.size()]; //初始化代表每个组的值都为true,如果该组数目满足要求,则置为false,下一轮不再分配
            int index = 0; //代表在某一轮分配中分配给第index+1组
            for (int i = 0; i < map.size(); i++){
                requestGetFlag[i] = true;
            }
            boolean flag;
    	int odd = 0;
            while (linkedList.size() > 0 && assignCount > 0  ){
                flag = true;
                for (int i = 0; i < map.size(); i++){
    
                    if ( 0 == index){ //代表某一轮分配完毕,开始分配下一轮
                        odd = (odd + 1) % 2; //奇数轮分配最大的,偶数轮分配最小的
                    }
    
                    if(requestGetFlag[index] && flag){
                    	assignCount--; //分配一个自减1
                        requestGet[index]++;
                        //取出订单列表的第一个,直接去数据库更新,此时更新的是map中的第一个,之后变成第二个,第三个
                        //index+1 代表是第几个groupIds[index+1]  linkedList.get(0)表示获取订单list的第一个 分配给第 index + 1个
    
                        //针对此订单更新数据库,把该订单分配给groupIds[index+1]
                        //判断订单状态是否已经完成
    		    CollectionPo po = null;
    		    int collectionNo = 0 ;
    		    if (odd == 1){ 
                            collectionNo = 0;
                        } else {
                            collectionNo = linkedList.size()-1 ;
                        }
    
                        po = collectionService.getById(linkedList.get(collectionNo).getCollectionId());
    
    
                        System.out.println("\n\n*************\n此次分配的订单id为:" + linkedList.get(collectionNo).getCollectionId() + "\n分配给:" + groupIds[index] + "\n***********\n\n");
    
    		    if(odd == 1){
    			linkedList.removeFirst();
    		    } else{
    			linkedList.removeLast();
    		    }
    
                        flag = false;
                        if (requestGet[index] == requestNum[index])
                            requestGetFlag[index] = false;
                        index ++;
                        if(index > map.size() - 1){
                            index = 0;
                        }
                        break;
                    }
                    index ++;
                    if(index > map.size() - 1){
                        index = 0;
                    }
                }
            }


    2.1.3 算法的优势与弊端

            此算法算是比较简单的一类,一个萝卜一个坑往里填,但是实现起来还是很复杂。对于数据库中存有的数据离散性有一定要求,最好是订单金额的中位数等于或接近平均数。



    展开全文
  • 由于我之前一直强调数据结构以及算法学习的重要性,所以就一些读者经常问我,数据结构与算法应该要学习到哪个程度呢?,说实话,这个问题我不知道要怎么回答你,主要取决于你想学习到哪些程度,不过针对这个问题,...

    由于我之前一直强调数据结构以及算法学习的重要性,所以就有一些读者经常问我,数据结构与算法应该要学习到哪个程度呢?,说实话,这个问题我不知道要怎么回答你,主要取决于你想学习到哪些程度,不过针对这个问题,我稍微总结一下我学过的算法知识点,以及我觉得值得学习的算法。这些算法与数据结构的学习大多数是零散的,并没有一本把他们全部覆盖的书籍。下面是我觉得值得学习的一些算法以及数据结构,当然,我也会整理一些看过不错的文章给大家。大家也可以留言区补充。

    一、算法最最基础

    1、时间复杂度

    2、空间复杂度

    一般最先接触的就是时间复杂度和空间复杂度的学习了,这两个概念以及如何计算,是必须学的,也是必须最先学的,主要有最大复杂度、平均复杂度等,直接通过博客搜索学习即可。

    文章推荐:

    算法分析神器—时间复杂度

    二、基础数据结构

    1、线性表

    • 列表(必学)
    • 链表(必学)
    • 跳跃表(知道原理,应用,最后自己实现一遍)
    • 并查集(建议结合刷题学习)

    不用说,链表、列表必须,不过重点是链表。

    三分钟基础数据结构:如何轻松手写链表?

    以后有面试官问你「跳跃表」,你就把这篇文章扔给他

    2、栈与队列

    • 栈(必学)
    • 队列(必学)
    • 优先队列、堆(必学)
    • 多级反馈队列(原理与应用)

    特别是优先队列,再刷题的时候,还是经常用到的,队列与栈,是最基本的数据结构,必学。可以通过博客来学习。相关文章:

    三分钟基础知识:什么是栈?

    二叉堆是什么鬼?

    【算法与数据结构】堆排序是什么鬼?

    3、哈希表(必学)

    • 碰撞解决方法:开放定址法、链地址法、再次哈希法、建立公共溢出区(必学)
    • 布隆过滤器(原理与应用)

    哈希表相关的,推荐通过博客来学习,推荐文章:

    Hash冲突之开放地址法

    4、树

    • 二叉树:各种遍历(递归与非递归)(必学)
    • 哈夫曼树与编码(原理与应用)
    • AVL树(必学)
    • B 树与 B+ 树(原理与应用)
    • 前缀树(原理与应用)
    • 红黑树(原理与应用)
    • 线段树(原理与应用)

    树相关是知识还是挺多的,建议看书,可以看《算法第四版》。相关文章:

    高频面试题:什么是B树?为啥文件索引要用B树而不用二叉查找树?

    【漫画】以后在有面试官问你AVL树,你就把这篇文章扔给他。

    腾讯面试题:有了二叉查找树、平衡树为啥还需要红黑树?

    【面试被虐】游戏中的敏感词过滤是如何实现的?

    5、数组

    • 树状数组
    • 矩阵(必学)

    树状数组其实我也没学过,,,,

    三、各种常见算法

    1、十大排序算法

    • 简单排序:插入排序、选择排序、冒泡排序(必学)
    • 分治排序:快速排序、归并排序(必学,快速排序还要关注中轴的选取方式)
    • 分配排序:桶排序、基数排序
    • 树状排序:堆排序(必学)
    • 其他:计数排序(必学)、希尔排序

    对于十大算法的学习,假如你不大懂的话,那么我还是挺推荐你去看书的,因为看了书,你可能不仅仅知道这个算法怎么写,还能知道他是怎么来的。推荐书籍是《算法第四版》,这本书讲的很详细,而且配了很多图演示,还是挺好懂的。

    推荐文章:

    必学十大经典排序算法,看这篇就够了(附完整代码/动图/优质文章)(修订版)

    2、图论算法

    • 图的表示:邻接矩阵和邻接表
    • 遍历算法:深度搜索和广度搜索(必学)
    • 最短路径算法:Floyd,Dijkstra(必学)
    • 最小生成树算法:Prim,Kruskal(必学)
    • 实际常用算法:关键路径、拓扑排序(原理与应用)
    • 二分图匹配:配对、匈牙利算法(原理与应用)
    • 拓展:中心性算法、社区发现算法(原理与应用)

    图还是比较难的,不过我觉得图涉及到的挺多算法都是挺实用的,例如最短路径的计算等,图相关的,我这里还是建议看书的,可以看《算法第四版》。

    漫画:什么是 “图”?(修订版)

    漫画:深度优先遍历 和 广度优先遍历

    漫画:图的 “最短路径” 问题

    漫画:Dijkstra 算法的优化

    漫画:图的 “多源” 最短路径

    更多算法的学习,欢迎关注我的公众号『帅地玩编程

    3、搜索与回溯算法

    • 贪心算法(必学)
    • 启发式搜索算法:A*寻路算法(了解)
    • 地图着色算法、N 皇后问题、最优加工顺序
    • 旅行商问题

    这方便的只是都是一些算法相关的,我觉得如果可以,都学一下。像贪心算法的思想,就必须学的了。建议通过刷题来学习,leetcode 直接专题刷。

    4、动态规划

    • 树形DP:01背包问题
    • 线性DP:最长公共子序列、最长公共子串
    • 区间DP:矩阵最大值(和以及积)
    • 数位DP:数字游戏
    • 状态压缩DP:旅行商

    我觉得动态规划是最难的一个算法思想了,记得当初第一次接触动态规划的时候,是看01背包问题的,看了好久都不大懂,懵懵懂懂,后面懂了基本思想,可是做题下不了手,但是看的懂答案。一气之下,再leetcdoe专题连续刷了几十道,才掌握了动态规划的套路,也有了自己的一套模板。不过说实话,动态规划,是考的真他妈多,学习算法、刷题,一定要掌握。这里建议先了解动态规划是什么,之后 leetcode 专题刷,反正就一般上面这几种题型。后面有时间,我也写一下我学到的套路,有点类似于我之前写的递归那样,算是一种经验。也就是我做题时的模板,不过感觉得写七八个小时,,,,,有时间就写。之前写的递归文章:为什么你学不会递归?告别递归,谈谈我的一些经验

    5、字符匹配算法

    • 正则表达式
    • 模式匹配:KMP、Boyer-Moore

    我写过两篇字符串匹配的文章,感觉还不错,看了这两篇文章,我觉得你就差不多懂 kmp 和 Boyer-Moore 了。

    字符串匹配Boyer-Moore算法:文本编辑器中的查找功能是如何实现的?

    更多算法的学习,欢迎关注我的公众号『苦逼的码农

    6、流相关算法

    • 最大流:最短增广路、Dinic 算法
    • 最大流最小割:最大收益问题、方格取数问题
    • 最小费用最大流:最小费用路、消遣

    这方面的一些算法,我也只了解过一些,感兴趣的可以学习下。

    总结

    对于上面设计到的算法,我都提供了感觉还不错的文章,建议大家收藏,然后可以利用零碎的时间进行阅读,有些人可能会觉得上面的算法太多,说实话,我觉得不多,特别是对于在校生的,上面涉及到的算法可以不用很懂,但至少得了解。至于书籍的话,如果你连基本数据结构都还不懂的,建议看《数据结构与算法》相关书籍,例如《大话数据结构》、《数据结构与算法分析》。如果你有一定的基础,例如知道链表,栈,队列,那么可以看《算法第四版》,不过这本书是用 Java 实现的,不过我觉得你只要学过 C,那么可以看的懂。

    这些算法的学习,虽然你觉得学了没有什么用,但还是那些话,它对你的影响是潜意识的,它可以给你打下很深厚的基础内功,如果你想走的更远,那么我推荐学习,标注必学的,那么我觉得,你是真的需要抽时间来学习下,标注原理与应用的,代表你可以不知道怎么用代码实现,但是必得知道它的实现原理以及应用,更多算法的学习,可以持续关注我的微信公众号勒。

    作为一个非常注重计算机基础以及算法学习的程序员,一路自学走来,看过挺多不错的优质书籍,在这里推荐给大家,全都是自己看过滴。

    最后,很多人问我都是怎么学习的,那我干脆就把我看过的优质书籍贡献出来

    计算机基础入门推荐:《程序是怎样跑起来的》、《网络是怎样连接的》、《计算机是怎样工作的》

    进一步认识计算机网络:《计算机网络:自顶向下》、《图解http》

    数据结构+算法入门:《数据结构与算法分析:C语言描述版》,《大话数据结构》、《阿哈算法》

    算法进阶:《算法第四版》、《编程之美》、《编程珠玑》

    由于我是Java技术栈的,顺便推荐基本Java的书籍,从左到由的顺序看到

    Java:《Java核心技术卷1》、《编程思想》、《深入理解Java虚拟机》、《Java编程艺术》

    数据库:《mysql必知必会》、《MySQL技术内幕:InnoDB存储引擎》

    就先介绍这么多,这些都是最基础最核心滴,希望对那些不知道看什书的同学有所帮助

    对了,我介绍的这些书籍,我顺便帮你整理好了,你可以在我的原创微信公众号『帅地玩编程』回复『书籍』获取哦

    另外,帅地把公众号的精华文章整理成了一本电子书,共 630页!目录如下
    在这里插入图片描述
    现在免费送给大家,在我的公众号帅地玩编程回复程序员内功修炼即可获取。

    有收获?希望老铁们来个三连击,给更多的人看到这篇文章

    1、老铁们,关注我的原创微信公众号「帅地玩编程」,专注于写算法 + 计算机基础知识(计算机网络+ 操作系统+数据库+Linux),保存让你看完有所收获,不信你打我。

    2、给俺点个赞呗,可以让更多的人看到这篇文章,顺便激励下我,嘻嘻。

    作者info

    作者:帅地,一位热爱写作的小伙
    原创公众号:『帅地玩编程』,已写了150多篇文章,专注于写 算法、计算机基础知识等提升你内功的文章,期待你的关注。
    转载说明:务必注明来源(注明:来源于公众号:苦逼的码农, 作者:帅地)

    展开全文
  • 几种负载均衡算法

    千次阅读 2011-11-07 15:47:24
    本地流量管理技术主要一下几种负载均衡算法: 静态负载均衡算法包括:轮询,比率,优先权 动态负载均衡算法包括: 最少连接数,最快响应速度,观察方法,预测法,动态性能分配,动态服务器补充,服务质量,服务...
  • 连续分配方式(交换技术),是指为一个用户程序分配一个连续的内存空间。它主要包括单一连续分配、固定分区分配和动态分区分配。 注意:此处的连续内存分配是将整个进程的数据整块加载到内存之中。 1.单一连续分配...
  • 几种常见排序算法的分析

    千次阅读 2016-08-31 15:34:57
    几种常见排序算法的分析摘要 插入排序、希尔排序、冒泡排序、快速排序、选择排序、归并排序和基数排序是计算机科学中常用的几种排序算法。本文简要的介绍了这几种算法的思路,并给出了公认的这些算法的时间复杂度表...
  • Java中常见的几种排序算法

    千次阅读 2020-06-26 11:40:10
    本文主要记录了几种常见的排序算法的Java实现,如冒泡排序、快速排序、直接插入排序、希尔排序、选择排序等等。 在学数据结构与算法时的部分记录,感觉好难啊╮(╯▽╰)╭,还需继续努力。 更多文章欢迎访问我的...
  • 动态分区分配的四种算法

    千次阅读 2020-05-13 09:48:30
    文章目录知识总览首次适应算法最佳适应算法最坏适应算法邻近适应算法知识回顾 知识总览 首次适应算法 最佳适应算法 最坏适应算法 邻近适应算法 知识回顾
  • 内存分配策略和分配算法

    千次阅读 2016-06-22 12:13:29
    3)物理块的分配算法。 1、最小物理块数的确定 -- 这里所说的最小物理块数,是指能保证进程正常运行所需的最小物理块数。 -- 当系统为进程分配的物理块数小于此值时,进程将无法运行。 -- 进程应获得的最少物理块数...
  • 几种操作系统的作业调度算法

    千次阅读 2019-08-21 14:16:37
    网上度娘到了几种操作系统的作业调度算法,贴出来给自己做一下参考备份,我觉得说的很好,这里讲的几种调度算法结合我要做的项目,我觉得多级反馈队列调度算法比较合适,这里暂且做一下标记,后续改动再说。...
  • 算法学习总结(2)——温故十大经典排序算法

    万次阅读 多人点赞 2019-08-29 14:57:51
    一、什么是排序算法 1.1、排序定义 对一序列对象根据某个关键字进行排序。 1.2、排序术语 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b...
  • 几种常见的软件负载均衡的算法

    千次阅读 2015-07-01 16:58:21
    文中提到了几种常见的软件负载均衡的算法平均分配(轮询),加权轮询;ip hash;fair(最小值负载均衡)这里需要提到一点,笔者曾见到过一位同事分析采用这个最小值负载均衡算法可能产生抖动,由
  • 几种磁盘调度算法的讲解

    万次阅读 2016-12-07 20:31:29
    设备的动态分配算法与进程调度相似,也是基于一定的分配策略的。常用的分配策略先请求先分配、优先级高者先分配等策略。在多道程序系统中,低效率通常是由于磁盘类旋转设备使用不当造成的。操作系统中,对磁盘的...
  • 几种搜索引擎算法

    千次阅读 2016-02-29 16:00:01
    1.引言  万维网WWW(World Wide Web)是一个巨大的,分布全球的...WEB上的文档和传统的文档比较,很多新的特点,它们是分布的,异构的,无结构或者半结构的,这就对传统信息检索技术提出了新的挑战。  传统的WE
  • LVS负载均衡的几种模式和算法

    万次阅读 2019-11-27 10:09:53
    轮询算法假设所有的服务器处理请求的能力都一样的,调度器会将所有的请求平均分配给每个真实服务器。 2.加权轮询调度 加权轮询(Weight Round Robin 简称’WRR’)算法主要是对轮询算法的一优化与补充,LVS会...
  • 几种简单的负载均衡算法

    千次阅读 2018-04-05 00:00:00
    什么是负载均衡负载均衡,英文名称为Load Balance,指由多台服务器以对称的方式组成一个服务器集合,每台...负载均衡能够平均分配客户请求到服务器阵列,借此提供快速获取重要数据,解决大量并发访问服务问题,这种集
  • linux--几种常见的进程调度算法

    千次阅读 2016-06-14 17:46:52
    先来先服务(FCFS)调度算法是一最简单的调度算法,该算法既可用于作业调度,也可用于进程调度。当在作业调度中采用该算法时,每次调度都是从后备作业队列中选择一个或多个最先进入该队列的作业,将它们调入内存,为...
  • 1. 先进先出进程调度算法(FIFO) (先来先服务FCFS) 按照进程就绪的先后次序来调度进程。... 优点: 平均周转时间,带权平均周转时间都改善 缺点: 对长作业非常不利,不能保证紧迫性进程得到及时处理,估计运行时间不准确
  • 几种搜索引擎算法 SEO

    万次阅读 2018-02-08 00:00:21
    (一)1.引言 万维网WWW(World Wide Web)是一个巨大的...WEB上的文档和传统的文档比较,很多新的特点,它们是分布的,异构的,无结构或者半结构的,这就对传统信息检索技术提出了新的挑战。 传统的WEB搜索引擎...
  • Java 实现微信红包分配算法

    万次阅读 2017-03-19 10:54:24
    抢红包的额度是从0.01到剩余平均值*N(N是一个系数,决定最大的红包值)之间,比如一共发了10块钱,发了10个红包:第一个人可以拿到(0.01~1*N)之间的一个红包值,当然为了确保所有人至少1分钱拿,不能前个人就把钱...
  • 【Linux】常见的几种进程调度算法

    千次阅读 2019-05-28 11:21:32
    操作系统管理了系统的有限资源,当多个进程(或多个进程发出的请求)要使用这些资源时,因为资源的有限性,必须按照一定的原则来选择进程(请求)来占用资源。这就是调度。目的是控制资源使用者的数量,选取资源...
  • 几种图像滤波算法的简单介绍

    千次阅读 2017-07-19 16:26:19
    图像平滑处理中,几种常见的滤波器如下: 归一化滤波器(Normalized Box Filter) 高斯滤波器(Gaussian Filter) 中值滤波器(Median Filter) 双边滤波(Bilateral Filter) 其对应的opencv函数及使用...
  • 排序算法

    万次阅读 多人点赞 2017-12-06 17:10:51
    十种常见排序算法一般分为以下几种:  (1)非线性时间比较类排序:交换类排序(快速排序和冒泡排序)、插入类排序(简单插入排序和希尔排序)、选择类排序(简单选择排序和堆排序)、归并排序(二路归并排序和多路...
  • 1、MTT算法  Multi-Task Tracking (MTT)跟踪算法,在粒子滤波框架下,将目标跟踪作为多任务稀疏学习问题,粒子模型...MTT计算上的吸引力,与L1跟踪器相比,提高了跟踪的效率。  1.1跟踪目标的多任务表示  在
  • 常用的排序算法的时间复杂度和空间复杂度 排序法  最差时间分析 平均时间复杂度  稳定度  空间复杂度  冒泡排序 O(n2) O(n2)  稳定  O(1)  ...
  • 算法】十排序算法实现

    千次阅读 2021-03-09 21:11:16
    } 2.3 算法分析 最佳情况:T(n) = O(n2) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(n2) 3、插入排序(Insertion Sort) 插入排序(Insertion-Sort)的算法描述是一简单直观的排序算法。它的工作原理是通过构建有序...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 78,388
精华内容 31,355
关键字:

平均分配算法有几种