数据集匹配算法(Java)

学习记录来自:能解决一切答案 bravo1988 - 知乎博主(可购买其小册)

这个算法能解决什么问题呢?它主要处理两个数据集合的匹配问题。

比如,现在有两个数据集合:

public class Demo {

    public static void main(String[] args) {

        // 老公组
        List<Couple> husbands = new ArrayList<>();
        husbands.add(new Couple(1, "梁山伯"));
        husbands.add(new Couple(2, "牛郎"));
        husbands.add(new Couple(3, "干将"));
        husbands.add(new Couple(4, "工藤新一"));
        husbands.add(new Couple(5, "罗密欧"));

        // 老婆组
        List<Couple> wives = new ArrayList<>();
        wives.add(new Couple(1, "祝英台"));
        wives.add(new Couple(2, "织女"));
        wives.add(new Couple(3, "莫邪"));
        wives.add(new Couple(4, "毛利兰"));
        wives.add(new Couple(5, "朱丽叶"));
    }
}

@Data
@AllArgsConstructor
class Couple{
    private Integer familyId;
    private String userName;
}

要求对数据进行处理,最终输出:

梁山伯爱祝英台

牛郎爱织女

干将爱莫邪

工藤新一爱毛利兰

罗密欧爱朱丽叶

第一版算法

package com.wei.demo.Controller;

import java.util.LinkedList;
import java.util.List;

public class NumberOne {
    public static void main(String[] args) {
        //循环次数
        int count = 0;
        //第一个集合数据
        List<Couple> husbands = new LinkedList<>();
        husbands.add(new Couple(1, "梁山伯"));
        husbands.add(new Couple(2, "牛郎"));
        husbands.add(new Couple(3, "干将"));
        husbands.add(new Couple(4, "工藤新一"));
        husbands.add(new Couple(5, "罗密欧"));
        //第二个集合数据
        List<Couple> wives = new LinkedList<>();
        wives.add(new Couple(1, "祝英台"));
        wives.add(new Couple(2, "织女"));
        wives.add(new Couple(3, "莫邪"));
        wives.add(new Couple(4, "毛利兰"));
        wives.add(new Couple(5, "朱丽叶"));

        //如何把两个数据集合进行有效的匹配呢?比如梁山伯 爱 祝英台 就是1对1 2对2 ,男嘉宾需要找到属于自己的号码牌的女嘉宾
       /**
         * 首先是常规的方法for循环,好的算法是不断进行迭代的,刚开始都是从完成需求进行开始
         */
        for (Couple husband :
                husbands) {
            for (Couple wife :
                    wives) {
                //记录循环的次数
                count++;
                if (husband.getId().equals(wife.getId())) {

                    System.out.println(husband.getName()+"爱"+wife.getName());
                }
            }
        }
        System.out.println("------循环结束------");
        System.out.println("循环次数为:"+count);
    }
    
}

第二版算法

package com.wei.demo.Controller;

import java.util.LinkedList;
import java.util.List;

public class NumberTwo {
    public static void main(String[] args) {
        //循环次数
        int count = 0;
        //第一个集合数据
        List<Couple> husbands = new LinkedList<>();
        husbands.add(new Couple(1, "梁山伯"));
        husbands.add(new Couple(2, "牛郎"));
        husbands.add(new Couple(3, "干将"));
        husbands.add(new Couple(4, "工藤新一"));
        husbands.add(new Couple(5, "罗密欧"));
        //第二个集合数据
        List<Couple> wives = new LinkedList<>();
        wives.add(new Couple(1, "祝英台"));
        wives.add(new Couple(2, "织女"));
        wives.add(new Couple(3, "莫邪"));
        wives.add(new Couple(4, "毛利兰"));
        wives.add(new Couple(5, "朱丽叶"));

        //如何把两个数据集合进行有效的匹配呢?比如梁山伯 爱 祝英台
         /**
         * 第一种方法循环次数是25次,速度慢,需要进一步的改进
         * 在内层循环时,当匹配到后,我们可以加一个break,不需要再次无用的循环了
         * 循环次数是15次
         */
        for (Couple husband :
                husbands) {
            for (Couple wife :
                    wives) {
                //记录循环的次数
                count++;
                if (husband.getId().equals(wife.getId())) {

                    System.out.println(husband.getName()+"爱"+wife.getName());
                    break;
                }
            }
        }
        System.out.println("------循环结束------");
        System.out.println("循环次数为:"+count);
    }
    
}

第三版算法

package com.wei.demo.Controller;

import java.util.LinkedList;
import java.util.List;

public class NumberThree {
    public static void main(String[] args) {
        //循环次数
        int count = 0;
        //第一个集合数据
        List<Couple> husbands = new LinkedList<>();
        husbands.add(new Couple(1, "梁山伯"));
        husbands.add(new Couple(2, "牛郎"));
        husbands.add(new Couple(3, "干将"));
        husbands.add(new Couple(4, "工藤新一"));
        husbands.add(new Couple(5, "罗密欧"));
        //第二个集合数据
        List<Couple> wives = new LinkedList<>();
        wives.add(new Couple(1, "祝英台"));
        wives.add(new Couple(2, "织女"));
        wives.add(new Couple(3, "莫邪"));
        wives.add(new Couple(4, "毛利兰"));
        wives.add(new Couple(5, "朱丽叶"));

        //如何把两个数据集合进行有效的匹配呢?比如梁山伯 爱 祝英台
         /**
         * 第二种方法,我们可以看到已经从25次缩减到15次,有了一定的进步
         * 但是,我们想,如果前面两个人已经匹配成功后,那这个妻子就不能再匹配了,相当于要删除了,不然后面还要进行不断地重复循环。
         * 所以我们可以加remove方法
         */
        for (Couple husband :
                husbands) {
            for (Couple wife :
                    wives) {
                //记录循环的次数
                count++;
                if (husband.getId().equals(wife.getId())) {

                    System.out.println(husband.getName()+"爱"+wife.getName());
                    wives.remove(wife);
                    break;
                }
            }
        }
        System.out.println("------循环结束------");
        System.out.println("循环次数为:"+count);
    }
    
}

第四版算法

package com.wei.demo.Controller;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class NumberFour {
    public static void main(String[] args) {
        //循环次数
        int count = 0;
        //第一个集合数据
        List<Couple> husbands = new LinkedList<>();
        husbands.add(new Couple(1, "梁山伯"));
        husbands.add(new Couple(2, "牛郎"));
        husbands.add(new Couple(3, "干将"));
        husbands.add(new Couple(4, "工藤新一"));
        husbands.add(new Couple(5, "罗密欧"));
        //第二个集合数据
        List<Couple> wives = new LinkedList<>();
        wives.add(new Couple(1, "祝英台"));
        wives.add(new Couple(2, "织女"));
        wives.add(new Couple(3, "莫邪"));
        wives.add(new Couple(4, "毛利兰"));
        wives.add(new Couple(5, "朱丽叶"));

        //如何把两个数据集合进行有效的匹配呢?比如梁山伯 爱 祝英台
        /**
         * 第三种的算法已经把次数减到5次了,已经是比较大改善,比第一个算法次数少了5倍
         * 但是如果把第三种算法的次数颠倒过来,比如把男嘉宾的12345次序改为54321,你可以观察一下效果,次数又变成15次,这说明这个算法的平均性能不高
         * 但是我们想一下,如果把list转map进行直接的定位匹配,而不需要直接进行遍历,那是不是更快吗?
         * 绝大多数情况下,for循环意味着抽取共同特性,忽略个体差异。好处是代码通用,坏处是无法发挥个体优势,最终影响效率
         * 如果我们给场上的女嘉宾每人发一个牌子,让他们在上面写上自己喜欢的男嘉宾号码,那么男嘉宾上场后就不用挨个问了,直接找到写有自己号码的女嘉宾即可牵手成功。
         * 这个算法的思想其实就是让数据产生差异化,外部通过差异快速定位目标数据
         * 这个算法无论次数怎么颠倒依然是10次,所以综合性能更好,它的精髓就是利用HashMap给其中一列数据加了“索引”,每个数据的“索引”(Map的key)是不同的,让数据差异化。
         */
        //给女嘉宾发牌子,然后男嘉宾直接看牌子直接进行匹配
        Map<Integer, Couple> wivesMap = new HashMap<>();
        for (Couple wife :
                wives) {
            //女嘉宾现在不在LIst集合中了,而是map中,在前面放了一块令牌,男嘉宾根据牌子直接定位进行匹配
            wivesMap.put(wife.getId(), wife);
            count++;
        }

        //然后男嘉宾进行匹配
        for (Couple husband :
                husbands) {
            //根据令牌号码直接定位到自己的女嘉宾,因为要号码牌一致啊1对1
            Couple wife = wivesMap.get(husband.getId());
             System.out.println(husband.getName()+"爱"+wife.getName());
            count++;
        }
        System.out.println("------循环结束-----");
        System.out.println("循环次数:"+count);
    }
    
}

猜你喜欢

转载自blog.csdn.net/qq_35207086/article/details/123233002
今日推荐